Re: [PATCH v2 3/3] Bluetooth: hci_sync: Attempt to dequeue connection attempt

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

 



Hi Jonas,

On Tue, Feb 13, 2024 at 6:47 PM Jonas Dreßler <verdre@xxxxxxx> wrote:
>
> Hi Luiz,
>
> > If connection is still queued/pending in the cmd_sync queue it means no
> > command has been generated and it should be safe to just dequeue the
> > callback when it is being aborted.
> >
> > Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@xxxxxxxxx>
> > ---
> >  include/net/bluetooth/hci_core.h | 19 ++++++++
> >  include/net/bluetooth/hci_sync.h | 10 +++--
> >  net/bluetooth/hci_conn.c         | 70 ++++++------------------------
> >  net/bluetooth/hci_sync.c         | 74 ++++++++++++++++++++++++++++----
> >  4 files changed, 102 insertions(+), 71 deletions(-)
> >
> > diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> > index 2bdea85b7c44..317d495cfcf5 100644
> > --- a/include/net/bluetooth/hci_core.h
> > +++ b/include/net/bluetooth/hci_core.h
> > @@ -1083,6 +1083,24 @@ static inline unsigned int hci_conn_count(struct hci_dev *hdev)
> >       return c->acl_num + c->amp_num + c->sco_num + c->le_num + c->iso_num;
> >  }
> >
> > +static inline bool hci_conn_valid(struct hci_dev *hdev, struct hci_conn *conn)
> > +{
> > +     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 == conn) {
> > +                     rcu_read_unlock();
> > +                     return true;
> > +             }
> > +     }
> > +     rcu_read_unlock();
> > +
> > +     return false;
> > +}
> > +
> >  static inline __u8 hci_conn_lookup_type(struct hci_dev *hdev, __u16 handle)
> >  {
> >       struct hci_conn_hash *h = &hdev->conn_hash;
> > @@ -1493,6 +1511,7 @@ struct hci_conn *hci_connect_le_scan(struct hci_dev *hdev, bdaddr_t *dst,
> >  struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
> >                               u8 dst_type, bool dst_resolved, u8 sec_level,
> >                               u16 conn_timeout, u8 role);
> > +void hci_connect_le_scan_cleanup(struct hci_conn *conn, u8 status);
> >  struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
> >                                u8 sec_level, u8 auth_type,
> >                                enum conn_reasons conn_reason, u16 timeout);
> > diff --git a/include/net/bluetooth/hci_sync.h b/include/net/bluetooth/hci_sync.h
> > index 4ff4aa68ee19..6a9d063e9f47 100644
> > --- a/include/net/bluetooth/hci_sync.h
> > +++ b/include/net/bluetooth/hci_sync.h
> > @@ -48,11 +48,11 @@ int hci_cmd_sync_submit(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
> >                       void *data, hci_cmd_sync_work_destroy_t destroy);
> >  int hci_cmd_sync_queue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
> >                      void *data, hci_cmd_sync_work_destroy_t destroy);
> > +int hci_cmd_sync_queue_once(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
> > +                         void *data, hci_cmd_sync_work_destroy_t destroy);
> >  struct hci_cmd_sync_work_entry *
> >  hci_cmd_sync_lookup_entry(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
> >                         void *data, hci_cmd_sync_work_destroy_t destroy);
> > -int hci_cmd_sync_queue_once(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
> > -                         void *data, hci_cmd_sync_work_destroy_t destroy);
> >  void hci_cmd_sync_cancel_entry(struct hci_dev *hdev,
> >                              struct hci_cmd_sync_work_entry *entry);
> >  bool hci_cmd_sync_dequeue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
> > @@ -139,8 +139,6 @@ struct hci_conn;
> >
> >  int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, u8 reason);
> >
> > -int hci_le_create_conn_sync(struct hci_dev *hdev, struct hci_conn *conn);
> > -
> >  int hci_le_create_cis_sync(struct hci_dev *hdev);
> >
> >  int hci_le_remove_cig_sync(struct hci_dev *hdev, u8 handle);
> > @@ -152,3 +150,7 @@ int hci_le_big_terminate_sync(struct hci_dev *hdev, u8 handle);
> >  int hci_le_pa_terminate_sync(struct hci_dev *hdev, u16 handle);
> >
> >  int hci_connect_acl_sync(struct hci_dev *hdev, struct hci_conn *conn);
> > +
> > +int hci_connect_le_sync(struct hci_dev *hdev, struct hci_conn *conn);
> > +
> > +int hci_cancel_connect_sync(struct hci_dev *hdev, struct hci_conn *conn);
> > diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
> > index 587eb27f374c..21e0b4064d05 100644
> > --- a/net/bluetooth/hci_conn.c
> > +++ b/net/bluetooth/hci_conn.c
> > @@ -68,7 +68,7 @@ static const struct sco_param esco_param_msbc[] = {
> >  };
> >
> >  /* This function requires the caller holds hdev->lock */
> > -static void hci_connect_le_scan_cleanup(struct hci_conn *conn, u8 status)
> > +void hci_connect_le_scan_cleanup(struct hci_conn *conn, u8 status)
> >  {
> >       struct hci_conn_params *params;
> >       struct hci_dev *hdev = conn->hdev;
> > @@ -1124,6 +1124,9 @@ void hci_conn_del(struct hci_conn *conn)
> >        * rest of hci_conn_del.
> >        */
> >       hci_conn_cleanup(conn);
> > +
> > +     /* Dequeue callbacks using connection pointer as data */
> > +     hci_cmd_sync_dequeue(hdev, NULL, conn, NULL);
> >  }
> >
> >  struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src, uint8_t src_type)
> > @@ -1258,53 +1261,6 @@ u8 hci_conn_set_handle(struct hci_conn *conn, u16 handle)
> >       return 0;
> >  }
> >
> > -static void create_le_conn_complete(struct hci_dev *hdev, void *data, int err)
> > -{
> > -     struct hci_conn *conn;
> > -     u16 handle = PTR_UINT(data);
> > -
> > -     conn = hci_conn_hash_lookup_handle(hdev, handle);
> > -     if (!conn)
> > -             return;
> > -
> > -     bt_dev_dbg(hdev, "err %d", err);
> > -
> > -     hci_dev_lock(hdev);
> > -
> > -     if (!err) {
> > -             hci_connect_le_scan_cleanup(conn, 0x00);
> > -             goto done;
> > -     }
> > -
> > -     /* Check if connection is still pending */
> > -     if (conn != hci_lookup_le_connect(hdev))
> > -             goto done;
> > -
> > -     /* Flush to make sure we send create conn cancel command if needed */
> > -     flush_delayed_work(&conn->le_conn_timeout);
> > -     hci_conn_failed(conn, bt_status(err));
> > -
> > -done:
> > -     hci_dev_unlock(hdev);
> > -}
> > -
> > -static int hci_connect_le_sync(struct hci_dev *hdev, void *data)
> > -{
> > -     struct hci_conn *conn;
> > -     u16 handle = PTR_UINT(data);
> > -
> > -     conn = hci_conn_hash_lookup_handle(hdev, handle);
> > -     if (!conn)
> > -             return 0;
> > -
> > -     bt_dev_dbg(hdev, "conn %p", conn);
> > -
> > -     clear_bit(HCI_CONN_SCANNING, &conn->flags);
> > -     conn->state = BT_CONNECT;
> > -
> > -     return hci_le_create_conn_sync(hdev, conn);
> > -}
> > -
> >  struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
> >                               u8 dst_type, bool dst_resolved, u8 sec_level,
> >                               u16 conn_timeout, u8 role)
> > @@ -1371,9 +1327,7 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
> >       conn->sec_level = BT_SECURITY_LOW;
> >       conn->conn_timeout = conn_timeout;
> >
>
> Might want to add a
>
> +       if (conn->state != BT_OPEN && conn->state != BT_CLOSED)
> +               return conn;
>
> before setting the conn->dst_type while at it, similar to how it's
> in hci_connect_acl().

Hmm but shall never be the case since we have the following check before it:

    /* Since the controller supports only one LE connection attempt at a
     * time, we return -EBUSY if there is any connection attempt running.
     */
    if (hci_lookup_le_connect(hdev))
        return ERR_PTR(-EBUSY);

>
> > -     err = hci_cmd_sync_queue(hdev, hci_connect_le_sync,
> > -                              UINT_PTR(conn->handle),
> > -                              create_le_conn_complete);
> > +     err = hci_connect_le_sync(hdev, conn);
> >       if (err) {
> >               hci_conn_del(conn);
> >               return ERR_PTR(err);
> > @@ -2909,12 +2863,10 @@ u32 hci_conn_get_phy(struct hci_conn *conn)
> >
> >  static int abort_conn_sync(struct hci_dev *hdev, void *data)
> >  {
> > -     struct hci_conn *conn;
> > -     u16 handle = PTR_UINT(data);
> > +     struct hci_conn *conn = data;
> >
> > -     conn = hci_conn_hash_lookup_handle(hdev, handle);
> > -     if (!conn)
> > -             return 0;
> > +     if (!hci_conn_valid(hdev, conn))
> > +             return -ECANCELED;
> >
> >       return hci_abort_conn_sync(hdev, conn, conn->abort_reason);
> >  }
> > @@ -2949,8 +2901,10 @@ int hci_abort_conn(struct hci_conn *conn, u8 reason)
> >                       hci_cmd_sync_cancel(hdev, -ECANCELED);
> >                       break;
> >               }
> > +     /* Cancel connect attempt if still queued/pending */
> > +     } else if (!hci_cancel_connect_sync(hdev, conn)) {
> > +             return 0;
> >       }
> >
> > -     return hci_cmd_sync_queue(hdev, abort_conn_sync, UINT_PTR(conn->handle),
> > -                               NULL);
> > +     return hci_cmd_sync_queue_once(hdev, abort_conn_sync, conn, NULL);
> >  }
> > diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
> > index 5b314bf844f8..b7d8e99e2a30 100644
> > --- a/net/bluetooth/hci_sync.c
> > +++ b/net/bluetooth/hci_sync.c
> > @@ -6285,12 +6285,21 @@ static int hci_le_ext_create_conn_sync(struct hci_dev *hdev,
> >                                       conn->conn_timeout, NULL);
> >  }
> >
> > -int hci_le_create_conn_sync(struct hci_dev *hdev, struct hci_conn *conn)
> > +static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data)
> >  {
> >       struct hci_cp_le_create_conn cp;
> >       struct hci_conn_params *params;
> >       u8 own_addr_type;
> >       int err;
> > +     struct hci_conn *conn = data;
> > +
> > +     if (!hci_conn_valid(hdev, conn))
> > +             return -ECANCELED;
> > +
> > +     bt_dev_dbg(hdev, "conn %p", conn);
> > +
> > +     clear_bit(HCI_CONN_SCANNING, &conn->flags);
> > +     conn->state = BT_CONNECT;
> >
> >       /* If requested to connect as peripheral use directed advertising */
> >       if (conn->role == HCI_ROLE_SLAVE) {
> > @@ -6611,16 +6620,11 @@ int hci_update_adv_data(struct hci_dev *hdev, u8 instance)
> >
> >  static int hci_acl_create_conn_sync(struct hci_dev *hdev, void *data)
> >  {
> > -     struct hci_conn *conn;
> > -     u16 handle = PTR_UINT(data);
> > +     struct hci_conn *conn = data;
> >       struct inquiry_entry *ie;
> >       struct hci_cp_create_conn cp;
> >       int err;
> >
> > -     conn = hci_conn_hash_lookup_handle(hdev, handle);
> > -     if (!conn)
> > -             return 0;
> > -
> >       /* Many controllers disallow HCI Create Connection while it is doing
> >        * HCI Inquiry. So we cancel the Inquiry first before issuing HCI Create
> >        * Connection. This may cause the MGMT discovering state to become false
> > @@ -6679,6 +6683,58 @@ static int hci_acl_create_conn_sync(struct hci_dev *hdev, void *data)
> >
> >  int hci_connect_acl_sync(struct hci_dev *hdev, struct hci_conn *conn)
> >  {
> > -     return hci_cmd_sync_queue(hdev, hci_acl_create_conn_sync,
> > -                               UINT_PTR(conn->handle), NULL);
> > +     return hci_cmd_sync_queue_once(hdev, hci_acl_create_conn_sync, conn,
> > +                                    NULL);
> > +}
> > +
> > +static void create_le_conn_complete(struct hci_dev *hdev, void *data, int err)
> > +{
> > +     struct hci_conn *conn = data;
> > +
> > +     bt_dev_dbg(hdev, "err %d", err);
> > +
> > +     if (err == -ECANCELED)
> > +             return;
> > +
> > +     hci_dev_lock(hdev);
> > +
> > +     if (!err) {
> > +             hci_connect_le_scan_cleanup(conn, 0x00);
> > +             goto done;
> > +     }
> > +
> > +     /* Check if connection is still pending */
> > +     if (conn != hci_lookup_le_connect(hdev))
> > +             goto done;
> > +
> > +     /* Flush to make sure we send create conn cancel command if needed */
> > +     flush_delayed_work(&conn->le_conn_timeout);
> > +     hci_conn_failed(conn, bt_status(err));
> > +
> > +done:
> > +     hci_dev_unlock(hdev);
> > +}
> > +
> > +int hci_connect_le_sync(struct hci_dev *hdev, struct hci_conn *conn)
> > +{
> > +     return hci_cmd_sync_queue_once(hdev, hci_le_create_conn_sync, conn,
> > +                                    create_le_conn_complete);
> > +}
> > +
> > +int hci_cancel_connect_sync(struct hci_dev *hdev, struct hci_conn *conn)
> > +{
> > +     if (conn->state != BT_OPEN)
> > +             return -EINVAL;
> > +
> > +     switch (conn->type) {
> > +     case ACL_LINK:
> > +             return !hci_cmd_sync_dequeue_once(hdev,
> > +                                               hci_acl_create_conn_sync,
> > +                                               conn, NULL);
> > +     case LE_LINK:
> > +             return !hci_cmd_sync_dequeue_once(hdev, hci_le_create_conn_sync,
> > +                                               conn, create_le_conn_complete);
> > +     }
> > +
> > +     return -ENOENT;
> >  }
> > --
> > 2.43.0
>
> Thanks for sending those patches, this is pretty much exactly what I had in mind!
>
> I came up with a slightly different cancel function for the queued work, one that
> also cancels the ongoing work. I'm not sure if it makes too much sense, because it
> means adding careful -ECANCELED handling to those sync_work callbacks.
>
> The nice thing about it is that it should also allow getting rid of the
> hci_cmd_sync_cancel(hdev, -ECANCELED) in hci_abort_conn().
>
> Adding the patch below, feel free to reuse whatever you like!
>
> Cheers,
> Jonas
>
> diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
> index 067d445701..a2b14f6be1 100644
> --- a/net/bluetooth/hci_sync.c
> +++ b/net/bluetooth/hci_sync.c
> @@ -154,6 +154,13 @@ struct sk_buff *__hci_cmd_sync_sk(struct hci_dev *hdev, u16 opcode, u32 plen,
>
>         bt_dev_dbg(hdev, "Opcode 0x%4x", opcode);
>
> +       if (hdev->cur_hci_sync_work_cancelled) {
> +               hdev->cur_hci_sync_work_cancelled = false;
> +
> +               return ERR_PTR(-ECANCELED);
> +       }
> +       mutex_unlock(&hdev->cmd_sync_work_lock);
> +
>         hci_req_init(&req, hdev);
>
>         hci_cmd_sync_add(&req, opcode, plen, param, event, sk);
> @@ -303,9 +310,29 @@ static void hci_cmd_sync_work(struct work_struct *work)
>                         int err;
>
>                         hci_req_sync_lock(hdev);
> +
> +                       mutex_lock(&hdev->cmd_sync_work_lock);
> +                       hdev->cur_hci_sync_work_func = entry->func;
> +                       hdev->cur_hci_sync_work_data = entry->data;
> +                       mutex_unlock(&hdev->cmd_sync_work_lock);
> +
>                         err = entry->func(hdev, entry->data);
>                         if (entry->destroy)
>                                 entry->destroy(hdev, entry->data, err);
> +
> +                       mutex_lock(&hdev->cmd_sync_work_lock);
> +                       hdev->cur_hci_sync_work_func = NULL;
> +                       hdev->cur_hci_sync_work_data = NULL;
> +
> +                       if (hdev->cur_hci_sync_work_cancelled) {
> +                               /* If cur_hci_sync_work_cancelled is still set at this point,
> +                                * no more request was sent and the work func has never been
> +                                * notified of our cancellation.
> +                                */
> +                               hdev->cur_hci_sync_work_cancelled = false;
> +                       }
> +                       mutex_unlock(&hdev->cmd_sync_work_lock);

Not really following this code, do you want to be able to cancel
callbacks that are actually executing, rather than queued?

>                         hci_req_sync_unlock(hdev);
>                 }
>
> @@ -735,6 +762,87 @@ int hci_cmd_sync_queue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
>   }
>   EXPORT_SYMBOL(hci_cmd_sync_queue);
>
> +bool hci_cmd_sync_has_cmd(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
> +                         void *data)
> +{
> +       struct hci_cmd_sync_work_entry *entry;
> +
> +       mutex_lock(&hdev->cmd_sync_work_lock);
> +       if (hdev->cur_hci_sync_work_func == func &&
> +           hdev->cur_hci_sync_work_data == data) {
> +               mutex_unlock(&hdev->cmd_sync_work_lock);
> +               return true;
> +       }
> +
> +       list_for_each_entry(entry, &hdev->cmd_sync_work_list, list) {
> +               if (entry->func == func && entry->data == data) {
> +                       mutex_unlock(&hdev->cmd_sync_work_lock);
> +                       return true;
> +               }
> +       }
> +       mutex_unlock(&hdev->cmd_sync_work_lock);
> +
> +       return false;
> +}
> +
> +void hci_cmd_sync_cancel_cmd(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
> +                            void *data)
> +{
> +       struct hci_cmd_sync_work_entry *entry;
> +       bool work_already_ongoing;
> +
> +       mutex_lock(&hdev->cmd_sync_work_lock);
> +       if (hdev->cur_hci_sync_work_func == func &&
> +           hdev->cur_hci_sync_work_data == data) {
> +               /* If the command is already ongoing, we check if we're currently
> +                * sending a async HCI request. If we are, we can cancel that
> +                * and hope that the hci_cmd_sync_work_func is handling -ECANCELED.
> +                */
> +
> +               if (hdev->req_status == HCI_REQ_PEND) {
> +                       /* If we're already executing a request, cancel that request.
> +                        * This will signal cancellation to the work func which sent
> +                        * the request in the first place.
> +                        */
> +                       __hci_cmd_sync_cancel(hdev, -ECANCELED);
> +               } else {
> +                       /* Otherwise, just set a flag which will cancel the next
> +                        * request. Just as above, this will then signal cancellation
> +                        * to the work func.
> +                        */
> +                       hdev->cur_hci_sync_work_cancelled = true;
> +               }

It might be better to save the executing entry at hdev and then make
the lookup_entry return it if the parameters match so it can be
cancelled with cancel_entry, that said perhaps it would be better to
just cancel the work if -ECANCELED is received so we don't have to
keep checking if it is returned on every command the callback
generates.

> +               mutex_unlock(&hdev->cmd_sync_work_lock);
> +
> +               return;
> +       } else {
> +               /* Or is it still queued? Then we remove it from the queue and
> +                * execute the destroy callback.
> +                */
> +               list_for_each_entry(entry, &hdev->cmd_sync_work_list, list) {
> +                       if (entry->func == func && entry->data == data) {
> +                               if (entry->destroy)
> +                                       entry->destroy(hdev, entry->data, -ECANCELED);
> +                               list_del(&entry->list);
> +                               kfree(entry);
> +
> +                               mutex_unlock(&hdev->cmd_sync_work_lock);
> +
> +                               if (list_empty(&hdev->cmd_sync_work_list)) {
> +                                       cancel_work_sync(&hdev->cmd_sync_work);
> +                                       cancel_work_sync(&hdev->reenable_adv_work);
> +                               }
> +
> +                               return;
> +                       }
> +               }
> +
> +       }
> +
> +       mutex_unlock(&hdev->cmd_sync_work_lock);
> +}
> +
>   int hci_update_eir_sync(struct hci_dev *hdev)
>   {
>         struct hci_cp_write_eir cp;
> @@ -6262,15 +6370,20 @@ int hci_le_create_conn_sync(struct hci_dev *hdev, struct hci_conn *conn)
>                 }
>
>                 /* Pause advertising while doing directed advertising. */
> -               hci_pause_advertising_sync(hdev);
> +               err = hci_pause_advertising_sync(hdev);
> +               if (err == -ECANCELED)
> +                       goto done;
>
>                 err = hci_le_directed_advertising_sync(hdev, conn);
>                 goto done;
>         }
>
>         /* Disable advertising if simultaneous roles is not in use. */
> -       if (!hci_dev_test_flag(hdev, HCI_LE_SIMULTANEOUS_ROLES))
> -               hci_pause_advertising_sync(hdev);
> +       if (!hci_dev_test_flag(hdev, HCI_LE_SIMULTANEOUS_ROLES)) {
> +               err = hci_pause_advertising_sync(hdev);
> +               if (err == -ECANCELED)
> +                       goto done;
> +       }
>
>         params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
>         if (params) {
> @@ -6292,7 +6405,10 @@ int hci_le_create_conn_sync(struct hci_dev *hdev, struct hci_conn *conn)
>          * state.
>          */
>         if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
> -               hci_scan_disable_sync(hdev);
> +               err = hci_scan_disable_sync(hdev);
> +               if (err == -ECANCELED)
> +                       goto done;
> +
>                 hci_dev_set_flag(hdev, HCI_LE_SCAN_INTERRUPTED);
>         }
>
> @@ -6336,11 +6452,10 @@ int hci_le_create_conn_sync(struct hci_dev *hdev, struct hci_conn *conn)
>                                        HCI_EV_LE_ENHANCED_CONN_COMPLETE :
>                                        HCI_EV_LE_CONN_COMPLETE,
>                                        conn->conn_timeout, NULL);
> +       if (err == -ECANCELED || err == -ETIMEDOUT)
> +               hci_le_connect_cancel_sync(hdev, conn, conn->abort_reason || 0x00);
>
>   done:
> -       if (err == -ETIMEDOUT)
> -               hci_le_connect_cancel_sync(hdev, conn, 0x00);
> -
>         /* Re-enable advertising after the connection attempt is finished. */
>         hci_resume_advertising_sync(hdev);
>         return err;
> @@ -6586,7 +6701,9 @@ static int __hci_acl_create_connection_sync(struct hci_dev *hdev, void *data)
>         if (test_bit(HCI_INQUIRY, &hdev->flags)) {
>                 err = __hci_cmd_sync_status(hdev, HCI_OP_INQUIRY_CANCEL, 0,
>                                             NULL, HCI_CMD_TIMEOUT);
> -               if (err)
> +               if (err == -ECANCELED)
> +                       return -ECANCELED;
> +               else if (err)
>                         bt_dev_warn(hdev, "Failed to cancel inquiry %d", err);
>         }
>
> @@ -6625,15 +6742,10 @@ static int __hci_acl_create_connection_sync(struct hci_dev *hdev, void *data)
>                                        HCI_EV_CONN_COMPLETE,
>                                        HCI_ACL_CONN_TIMEOUT, NULL);
>
> -       if (err == -ETIMEDOUT)
> -               hci_abort_conn_sync(hdev, conn, HCI_ERROR_LOCAL_HOST_TERM);
> +       if (err == -ECANCELED || err == -ETIMEDOUT) {
> +               hci_connect_cancel_sync(hdev, conn, conn->abort_reason || HCI_ERROR_LOCAL_HOST_TERM);
> +               return err;
> +       }
>
>         return err;
>   }
>


-- 
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