Re: [Bluez PATCH 2/2] shared/gatt: Add descriptor insert function

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

 



Hi Yun-hao,

On Mon, Apr 8, 2024 at 10:03 AM Luiz Augusto von Dentz
<luiz.dentz@xxxxxxxxx> wrote:
>
> Hi,
>
> On Mon, Apr 8, 2024 at 8:23 AM Yun-hao Chung <howardchung@xxxxxxxxxx> wrote:
> >
> > Hi Luiz,
> >
> > Thanks for the response.
> >
> > This issue was found in ChromeOS edition BlueZ. I'm not sure if any
> > official BlueZ would do the same discovery procedure or not.
> >
> > I extracted relevant part of the trace as below
> > ==========================
> > < ACL Data TX: Handle 2048 flags 0x00 dlen 11
> >
> >                                                 #43961 [hci0]
> > 2024-03-05 07:33:55.936283
> >       ATT: Read By Group Type Request (0x10) len 6
> >         Handle range: 0x001f-0xffff
> >         Attribute group type: Primary Service (0x2800)
> > ...
> > > ACL Data RX: Handle 2048 flags 0x02 dlen 27                                                                                                                                                 #43963 [hci0] 2024-03-05 07:33:55.967020
> > > ACL Data RX: Handle 2048 flags 0x01 dlen 3                                                                                                                                                  #43964 [hci0] 2024-03-05 07:33:55.967022
> >       ATT: Read By Group Type Response (0x11) len 25
> >         Attribute data length: 6
> >         Attribute group list: 4 entries
> >         Handle range: 0x001f-0x0035
> >         UUID: Human Interface Device (0x1812)
> >         Handle range: 0x0036-0x0044
> >         UUID: Human Interface Device (0x1812)
> >         Handle range: 0x0045-0x0055
> >         UUID: Human Interface Device (0x1812)
> >         Handle range: 0x0056-0x0062
> >         UUID: Logitech International SA (0xfd72)
> > …
> > < ACL Data TX: Handle 2048 flags 0x00 dlen 11
> >
> >                                                 #44018 [hci0]
> > 2024-03-05 07:33:56.281436
> >       ATT: Read By Type Request (0x08) len 6
> >         Handle range: 0x0021-0xffff
> >         Attribute type: Characteristic (0x2803)
> > ...
> > > ACL Data RX: Handle 2048 flags 0x02 dlen 27                                                                                                                                                 #44023 [hci0] 2024-03-05 07:33:56.311026
> >       ATT: Read By Type Response (0x09) len 22
> >         Attribute data length: 7
> >         Attribute data list: 3 entries
> >         Handle: 0x0022
> >         Value: 122300332a
> >             Properties: 0x12
> >               Read (0x02)
> >               Notify (0x10)
> >             Value Handle: 0x0023
> >             Value UUID: Boot Mouse Input Report (0x2a33)
> >         Handle: 0x0025
> >         Value: 0226004b2a
> >             Properties: 0x02
> >               Read (0x02)
> >             Value Handle: 0x0026
> >             Value UUID: Report Map (0x2a4b)
> >         Handle: 0x0027
> >         Value: 1228004d2a
> >             Properties: 0x12
> >               Read (0x02)
> >               Notify (0x10)
> >             Value Handle: 0x0028
> >             Value UUID: Report (0x2a4d)
> > ...
> > < ACL Data TX: Handle 2048 flags 0x00 dlen 11
> >
> >                                                 #44024 [hci0]
> > 2024-03-05 07:33:56.311458
> >       ATT: Read By Type Request (0x08) len 6
> >         Handle range: 0x0028-0xffff
> >         Attribute type: Characteristic (0x2803)
> > …
> > > ACL Data RX: Handle 2048 flags 0x02 dlen 27                                                                                                                                                 #44029 [hci0] 2024-03-05 07:33:56.341025
> >       ATT: Read By Type Response (0x09) len 22
> >         Attribute data length: 7
> >         Attribute data list: 3 entries
> >         Handle: 0x002b
> >         Value: 122c004d2a
> >             Properties: 0x12
> >               Read (0x02)
> >               Notify (0x10)
> >             Value Handle: 0x002c
> >             Value UUID: Report (0x2a4d)
> >         Handle: 0x002f
> >         Value: 0e30004d2a
> >             Properties: 0x0e
> >               Read (0x02)
> >               Write Without Response (0x04)
> >               Write (0x08)
> >             Value Handle: 0x0030
> >             Value UUID: Report (0x2a4d)
> >         Handle: 0x0032
> >         Value: 0433004c2a
> >             Properties: 0x04
> >               Write Without Response (0x04)
> >             Value Handle: 0x0033
> >             Value UUID: HID Control Point (0x2a4c)
> > …
> > < ACL Data TX: Handle 2048 flags 0x00 dlen 9
> >
> >                                                 #44071 [hci0]
> > 2024-03-05 07:33:56.702334
> >       ATT: Find Information Request (0x04) len 4
> >         Handle range: 0x0029-0x002a
> > …
> > > ACL Data RX: Handle 2048 flags 0x02 dlen 14                                                                                                                                                 #44073 [hci0] 2024-03-05 07:33:56.731069
> >       ATT: Find Information Response (0x05) len 9
> >         Format: UUID-16 (0x01)
> >         Handle: 0x0029
> >         UUID: Client Characteristic Configuration (0x2902)
> >         Handle: 0x002a
> >         UUID: Report Reference (0x2908)
> > =============================
> >
> > When decoding packet #44073, we can't append descriptors 0x0029 and
> > 0x002a at the tail of the |service->attributes| since the
> > characteristics 0x002b,0x002f and 0x0032 are already in the array.
>
> So bluetoothd works but the monitor doesn't? They both are using
> gatt_db_insert_descriptor which uses servvice_insert_descriptor, so
> where exactly is it failing at? The only difference I see is that in
> case of gatt-client.c we do:
>
>             attr = gatt_db_get_attribute(client->db, handle);
>             if (attr && !bt_uuid_cmp(&uuid,
>                     gatt_db_attribute_get_type(attr)))
>                 continue;
>
>
> The daemon does actually insert the CCC automatically in case there is
> only one handle left for the it:
>
>         if (desc_start == chrc_data->end_handle &&
>             (chrc_data->properties & BT_GATT_CHRC_PROP_NOTIFY ||
>              chrc_data->properties & BT_GATT_CHRC_PROP_INDICATE)) {
>             bt_uuid_t ccc_uuid;
>
>             /* If there is only one descriptor that must be the CCC
>              * in case either notify or indicate are supported.
>              */
>             bt_uuid16_create(&ccc_uuid,
>                     GATT_CLIENT_CHARAC_CFG_UUID);
>             attr = gatt_db_insert_descriptor(client->db, desc_start,
>                             &ccc_uuid, 0, NULL,
>                             NULL, NULL);
>             if (attr) {
>                 free(chrc_data);
>                 continue;
>             }
>         }
>
> That said perhaps we need to revise the implementation of
> get_attribute_index, it does attempt to take the first free index
> which is incorrect when we are inserting characteristics it shall not
> allocate the indexes one after another, instead the index shall be
> handle - service->attribute[0].handle when the handle is set.

Here is a tentative of fixing the index logic:

https://patchwork.kernel.org/project/bluetooth/patch/20240408155949.3622429-1-luiz.dentz@xxxxxxxxx/

> >
> >
> > On Wed, Apr 3, 2024 at 10:37 PM Luiz Augusto von Dentz
> > <luiz.dentz@xxxxxxxxx> wrote:
> > >
> > > Hi Howard,
> > >
> > > On Wed, Apr 3, 2024 at 7:06 AM Howard Chung <howardchung@xxxxxxxxxx> wrote:
> > > >
> > > > service->attributes has an assumption that it should look like:
> > > > |char_uuid|char_1|desc_1_1|desc_1_2|char_uuid|char_2|desc_2_1|char_uuid|...
> > > > where desc_x_y means a descriptor of char_x.
> > >
> > > Will need to check the trace but I believe BlueZ always discover all
> > > characteristics before moving to descriptors, if that is not happening
> > > they there is probably a bug somewhere, that said perhaps you are
> > > doing the discovery procedure with another stack which doesn't employ
> > > the same logic, although inefficient it is possible to discover out of
> > > order but that would require reassigning the descriptors to
> > > characteristics once they are found, which is also inefficient but I
> > > would understand if you after supporting other stacks.
> > >
> > > > In monitor, an attribute is inserted as soon as it is found. It is not
> > > > guranteed that all the descriptors of a characteristic would be found
> > > > before another characteristic is found.
> > >
> > > You might want to include such a trace, don't recall seeing any stack
> > > that does out-order discover.
> > >
> > > > This adds a function to insert the descriptor with the given handle to
> > > > an appropriate place in its service attribute list and make monitor to
> > > > use this function when a descripter is found.
> > > >
> > > > Reviewed-by: Archie Pusaka <apusaka@xxxxxxxxxxxx>
> > > > ---
> > > >
> > > >  monitor/att.c        |  2 +-
> > > >  src/shared/gatt-db.c | 66 ++++++++++++++++++++++++++++++++++++++++++++
> > > >  src/shared/gatt-db.h |  9 ++++++
> > > >  3 files changed, 76 insertions(+), 1 deletion(-)
> > > >
> > > > diff --git a/monitor/att.c b/monitor/att.c
> > > > index ddeb54d9e..503099745 100644
> > > > --- a/monitor/att.c
> > > > +++ b/monitor/att.c
> > > > @@ -4153,7 +4153,7 @@ static struct gatt_db_attribute *insert_desc(const struct l2cap_frame *frame,
> > > >         if (!db)
> > > >                 return NULL;
> > > >
> > > > -       return gatt_db_append_descriptor(db, handle, uuid, 0, NULL, NULL, NULL);
> > > > +       return gatt_db_insert_descriptor(db, handle, uuid, 0, NULL, NULL, NULL);
> > > >  }
> > > >
> > > >  static void att_find_info_rsp_16(const struct l2cap_frame *frame)
> > > > diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
> > > > index 39bba9b54..f08c5afaa 100644
> > > > --- a/src/shared/gatt-db.c
> > > > +++ b/src/shared/gatt-db.c
> > > > @@ -1002,6 +1002,72 @@ service_append_descriptor(struct gatt_db_service *service,
> > > >         return service->attributes[i];
> > > >  }
> > > >
> > > > +struct gatt_db_attribute *
> > > > +gatt_db_insert_descriptor(struct gatt_db *db,
> > > > +                                       uint16_t handle,
> > > > +                                       const bt_uuid_t *uuid,
> > > > +                                       uint32_t permissions,
> > > > +                                       gatt_db_read_t read_func,
> > > > +                                       gatt_db_write_t write_func,
> > > > +                                       void *user_data)
> > > > +{
> > > > +       struct gatt_db_attribute *attrib, *iter_attr, *char_attr = NULL;
> > > > +       struct gatt_db_service *service;
> > > > +       int i, j, num_index, char_index;
> > > > +
> > > > +       attrib = gatt_db_get_service(db, handle);
> > > > +       if (!attrib)
> > > > +               return NULL;
> > > > +
> > > > +       service = attrib->service;
> > > > +       num_index = get_attribute_index(service, 0);
> > > > +       if (!num_index)
> > > > +               return NULL;
> > > > +
> > > > +       // Find the characteristic the descriptor belongs to.
> > > > +       for (i = 0; i < num_index; i++) {
> > > > +               iter_attr = service->attributes[i];
> > > > +               if (bt_uuid_cmp(&characteristic_uuid, &iter_attr->uuid))
> > > > +                       continue;
> > > > +
> > > > +               if (iter_attr->handle > handle)
> > > > +                       continue;
> > > > +
> > > > +               // Find the characteristic with the largest handle among those
> > > > +               // with handles less than the descriptor's handle.
> > > > +               if (!char_attr || iter_attr->handle > char_attr->handle) {
> > > > +                       char_attr = iter_attr;
> > > > +                       char_index = i;
> > > > +               }
> > > > +       }
> > > > +
> > > > +       // There is no characteristic contain this descriptor. Something went
> > > > +       // wrong
> > > > +       if (!char_attr)
> > > > +               return NULL;
> > > > +
> > > > +       // Find the end of this characteristic
> > > > +       for (i = char_index + 1; i < num_index; i++) {
> > > > +               iter_attr = service->attributes[i];
> > > > +
> > > > +               if (!bt_uuid_cmp(&characteristic_uuid, &iter_attr->uuid) ||
> > > > +                       !bt_uuid_cmp(&included_service_uuid, &iter_attr->uuid))
> > > > +                       break;
> > > > +       }
> > > > +
> > > > +       // Move all of the attributes after the end of this characteristic to
> > > > +       // its next index.
> > > > +       for (j = num_index; j > i; j--)
> > > > +               service->attributes[j] = service->attributes[j - 1];
> > > > +
> > > > +       service->attributes[i] = new_attribute(service, handle, uuid, NULL, 0);
> > > > +
> > > > +       set_attribute_data(service->attributes[i], read_func, write_func,
> > > > +                                                       permissions, user_data);
> > > > +
> > > > +       return service->attributes[i];
> > > > +}
> > > > +
> > > >  struct gatt_db_attribute *
> > > >  gatt_db_append_descriptor(struct gatt_db *db,
> > > >                                         uint16_t handle,
> > > > diff --git a/src/shared/gatt-db.h b/src/shared/gatt-db.h
> > > > index ec0eccdfc..4c4e88d87 100644
> > > > --- a/src/shared/gatt-db.h
> > > > +++ b/src/shared/gatt-db.h
> > > > @@ -80,6 +80,15 @@ gatt_db_append_characteristic(struct gatt_db *db,
> > > >                                         gatt_db_write_t write_func,
> > > >                                         void *user_data);
> > > >
> > > > +struct gatt_db_attribute *
> > > > +gatt_db_insert_descriptor(struct gatt_db *db,
> > > > +                                       uint16_t handle,
> > > > +                                       const bt_uuid_t *uuid,
> > > > +                                       uint32_t permissions,
> > > > +                                       gatt_db_read_t read_func,
> > > > +                                       gatt_db_write_t write_func,
> > > > +                                       void *user_data);
> > > > +
> > > >  struct gatt_db_attribute *
> > > >  gatt_db_append_descriptor(struct gatt_db *db,
> > > >                                         uint16_t handle,
> > > > --
> > > > 2.44.0.478.gd926399ef9-goog
> > > >
> > >
> > >
> > > --
> > > Luiz Augusto von Dentz
>
>
>
> --
> Luiz Augusto von Dentz



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