Re: [PATCH] shared/gatt: Allow register_notify without CCC

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

 



Hi Arman,

On Fri, Feb 6, 2015 at 4:19 PM, Arman Uguray <armansito@xxxxxxxxxxxx> wrote:
> Hi Luiz,
>
>> On Thu, Feb 5, 2015 at 1:29 AM, Luiz Augusto von Dentz <luiz.dentz@xxxxxxxxx> wrote:
>> Hi Arman,
>>
>> On Thu, Feb 5, 2015 at 12:05 AM, Arman Uguray <armansito@xxxxxxxxxxxx> wrote:
>>> Hi Luiz,
>>>
>>>> On Wed, Feb 4, 2015 at 6:26 AM, Luiz Augusto von Dentz <luiz.dentz@xxxxxxxxx> wrote:
>>>> Hi Arman,
>>>>
>>>> On Wed, Feb 4, 2015 at 5:58 AM, Arman Uguray <armansito@xxxxxxxxxxxx> wrote:
>>>>> Certain peripherals can expose a GATT characteristic with the
>>>>> notify/indicate property but with no Client Characteristic Configuration
>>>>> descriptor. Since bt_gatt_client_register_notify enforces a CCC as a
>>>>> requirement, it returns an error for such characteristics.
>>>>
>>>> Do you have some evidence of this? I don't mind not being too strict
>>>> while receiving but we need to document why we are doing these
>>>> changes,...
>>>
>>> I came across this while testing with a Nexus 6 device running Android
>>> L. The application exposes a "Service Changed" characteristic with no
>>> CCC, which is causing bt_gatt_client's initialization sequence to fail
>>> (since it assumes that there will be a CCC and treats the absence as
>>> an error). This seemed strange to me, so I did some digging, and the
>>> Bluetooth developer page actually lists "None" for "Descriptors"
>>> (https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.generic_attribute.xml)
>>> of this characteristic.
>>>
>>> However, this seemed incorrect to me, so I checked the Core Spec v4.2,
>>> Vol 3, Part G, Section 7.1 "Service Changed", which states: "This
>>> [Service Changed] Characteristic Value shall be configured to be
>>> indicated, using the Client Characteristic Configuration descriptor by
>>> a client. Indications caused by changes to the Service Changed
>>> Characteristic Value shall be considered lost if the client has not
>>> enabled indications in the Client Configuration Characteristic
>>> Descriptor." Which means that the CCC is certainly mandatory, so this
>>> must be an error in the developer page.
>>
>> It is probably a bug, and in this case the device might not even be
>> able to qualify since service changed has 2 tests: TP/GAS/CL/BV-01-C
>> and TP/GAS/SR/BV-01-C. We should probably communicate that the
>> documentation needs fixing and the TS should probably be updated as
>> well to reflect CCC is mandatory in this case.
>>
>>> Regardless, though, even if this is an error in the BlueDroid stack,
>>> it means that some devices may have incorrectly implemented the spec
>>> here, so we should probably tolerate this. BlueZ's server
>>> implementation SHOULD regardless expose this descriptor, but the
>>> client IMO shouldn't fail if the CCC generally doesn't exist.
>>
>> Provided the SIG don't come with invalid tests for service changed
>> that is probably okay for the client, for the server I don't how it
>> would pass TP/GAS/SR/BV-01-C without CCC except if PTS is ignoring the
>> lack of CCC which IMO defeats the purpose of the test. So the argument
>> for service changed is probably not valid here, but for custom
>> attributes where there is no tests to validate the implemenation
>> perhaps you have a point, but note that it still will need to set
>> BT_GATT_CHRC_PROP_NOTIFY and BT_GATT_CHRC_PROP_INDICATE, btw such
>> policies perhaps should be done directly in shared/gatt-client.c so we
>> don't need have duplicated logic for Android.
>>
>>>
>>>> ...and btw this perhaps makes my argument of enabling
>>>> notification by default even stronger since if such devices really
>>>> exists they might be notifying us since the beginning.
>>>>
>>>
>>> Hmm, I don't know how this makes that argument any stronger.
>>> bt_gatt_client already automatically registers for Service Changed,
>>> and for external applications we still want to only notify if an app
>>> is interested (which they can do now across connections).
>>>
>>> Generally, I want to treat this as a corner-case, since it's not
>>> really spec compliant behavior. Either way, it's probably not that bad
>>> to have this fix so that we don't bork out immediately with devices
>>> that behave incorrectly. Actually, it might be even more spec
>>> compliant for us to simply ignore the Service Changed characteristic
>>> if it's discovered but doesn't have a CCC, since the spec says
>>> "changes to the Service Changed Characteristic Value shall be
>>> considered lost if the client has not enabled indications in the
>>> Client Configuration Characteristic Descriptor", which would end up
>>> being a simpler fix on our end.
>>>
>>> Either way, I'll wait for your response to determine what the right
>>> behavior is here.
>>
>> For service changed perhaps, but since we are using
>> bt_gatt_client_register_notify for any notification we would need to
>> have a special case for service changed alone so I would not bother
>> since broken stacks in this respect will probably not pass the
>> qualification if the test spec where implemented properly, for any
>> other char I would not be so strict since some OS may allow adding a
>> characteristic with notifiy/indicate bits sets but without a CCC to
>> enable them, actually Android probably allows that to happen already,
>> sadly I think even our BlueZ for Android currently allows that.
>>
>>>> The other problem I now see is that there is probably no way to rate
>>>> limit the notification, because they are profile specific, so if you
>>>> had a problem with too much traffic on D-Bus this may already happen
>>>> even if we register the notification on demand.
>>>>
>>>
>>> Right, though I guess this is a separate issue that can be dealt with
>>> at the D-Bus API level. shared/gatt-client has to still send all
>>> notifications up, otherwise things like HoG wouldn't work well with a
>>> rate limit. Anyway, we can do this at a D-Bus API level separately.
>>> I'll add this to the general TODO list.
>>>
>>>>> This patch fixes this behavior so that bt_gatt_client_register_notify
>>>>> immediately registers the callback and returns success for
>>>>> characteristics with no CCC.
>>>>> ---
>>>>>  src/shared/gatt-client.c | 43 +++++++++++++++++++++++++------------------
>>>>>  1 file changed, 25 insertions(+), 18 deletions(-)
>>>>>
>>>>> diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
>>>>> index 5edb991..d0fc054 100644
>>>>> --- a/src/shared/gatt-client.c
>>>>> +++ b/src/shared/gatt-client.c
>>>>> @@ -88,6 +88,7 @@ struct bt_gatt_client {
>>>>>          * the remote peripheral.
>>>>>          */
>>>>>         unsigned int svc_chngd_ind_id;
>>>>> +       bool svc_chngd_registered;
>>>>>         struct queue *svc_chngd_queue;  /* Queued service changed events */
>>>>>         bool in_svc_chngd;
>>>>>
>>>>> @@ -234,12 +235,6 @@ static struct notify_chrc *notify_chrc_create(struct bt_gatt_client *client,
>>>>>                                                         &properties, NULL))
>>>>>                         return NULL;
>>>>>
>>>>> -       /* Find the CCC characteristic */
>>>>> -       ccc = NULL;
>>>>> -       gatt_db_service_foreach_desc(attr, find_ccc, &ccc);
>>>>> -       if (!ccc)
>>>>> -               return NULL;
>>>>> -
>>>>>         chrc = new0(struct notify_chrc, 1);
>>>>>         if (!chrc)
>>>>>                 return NULL;
>>>>> @@ -250,8 +245,17 @@ static struct notify_chrc *notify_chrc_create(struct bt_gatt_client *client,
>>>>>                 return NULL;
>>>>>         }
>>>>>
>>>>> +       /*
>>>>> +        * Find the CCC characteristic. Some characteristics that allow
>>>>> +        * notifications may not have a CCC descriptor. We treat these as
>>>>> +        * automatically successful.
>>>>> +        */
>>>>> +       ccc = NULL;
>>>>> +       gatt_db_service_foreach_desc(attr, find_ccc, &ccc);
>>>>> +       if (ccc)
>>>>> +               chrc->ccc_handle = gatt_db_attribute_get_handle(ccc);
>>>>> +
>>>>>         chrc->value_handle = value_handle;
>>>>> -       chrc->ccc_handle = gatt_db_attribute_get_handle(ccc);
>>>>>         chrc->properties = properties;
>>>>>
>>>>>         queue_push_tail(client->notify_chrcs, chrc);
>>>>> @@ -1020,6 +1024,7 @@ static void service_changed_reregister_cb(uint16_t att_ecode, void *user_data)
>>>>>                 util_debug(client->debug_callback, client->debug_data,
>>>>>                         "Re-registered handler for \"Service Changed\" after "
>>>>>                         "change in GATT service");
>>>>> +               client->svc_chngd_registered = true;
>>>>>                 return;
>>>>>         }
>>>>>
>>>>> @@ -1089,6 +1094,7 @@ static void service_changed_complete(struct discovery_op *op, bool success,
>>>>>         /* The GATT service was modified. Re-register the handler for
>>>>>          * indications from the "Service Changed" characteristic.
>>>>>          */
>>>>> +       client->svc_chngd_registered = false;
>>>>>         client->svc_chngd_ind_id = bt_gatt_client_register_notify(client,
>>>>>                                         gatt_db_attribute_get_handle(attr),
>>>>>                                         service_changed_reregister_cb,
>>>>> @@ -1197,6 +1203,7 @@ static void service_changed_register_cb(uint16_t att_ecode, void *user_data)
>>>>>                 goto done;
>>>>>         }
>>>>>
>>>>> +       client->svc_chngd_registered = true;
>>>>>         client->ready = true;
>>>>>         success = true;
>>>>>         util_debug(client->debug_callback, client->debug_data,
>>>>> @@ -1239,13 +1246,16 @@ static void init_complete(struct discovery_op *op, bool success,
>>>>>                                         service_changed_register_cb,
>>>>>                                         service_changed_cb,
>>>>>                                         client, NULL);
>>>>> -       client->ready = false;
>>>>> +
>>>>> +       if (!client->svc_chngd_registered)
>>>>> +               client->ready = false;
>>>>>
>>>>>         if (client->svc_chngd_ind_id)
>>>>>                 return;
>>>>>
>>>>>         util_debug(client->debug_callback, client->debug_data,
>>>>>                         "Failed to register handler for \"Service Changed\"");
>>>>> +       success = false;
>>>>>
>>>>>  fail:
>>>>>         util_debug(client->debug_callback, client->debug_data,
>>>>> @@ -1423,18 +1433,17 @@ static void complete_unregister_notify(void *data)
>>>>>          */
>>>>>         if (notify_data->att_id) {
>>>>>                 bt_att_cancel(notify_data->client->att, notify_data->att_id);
>>>>> -               notify_data_unref(notify_data);
>>>>> -               return;
>>>>> +               goto done;
>>>>>         }
>>>>>
>>>>> -       if (__sync_sub_and_fetch(&notify_data->chrc->notify_count, 1)) {
>>>>> -               notify_data_unref(notify_data);
>>>>> -               return;
>>>>> -       }
>>>>> +       if (__sync_sub_and_fetch(&notify_data->chrc->notify_count, 1) ||
>>>>> +                                               !notify_data->chrc->ccc_handle)
>>>>> +               goto done;
>>>>>
>>>>>         if (notify_data_write_ccc(notify_data, false, disable_ccc_callback))
>>>>>                 return;
>>>>>
>>>>> +done:
>>>>>         notify_data_unref(notify_data);
>>>>>  }
>>>>>
>>>>> @@ -2571,9 +2580,7 @@ unsigned int bt_gatt_client_register_notify(struct bt_gatt_client *client,
>>>>>         /* Add the handler to the bt_gatt_client's general list */
>>>>>         queue_push_tail(client->notify_list, notify_data);
>>>>>
>>>>> -       /* Assign an ID to the handler and notify the caller that it was
>>>>> -        * successfully registered.
>>>>> -        */
>>>>> +       /* Assign an ID to the handler. */
>>>>>         if (client->next_reg_id < 1)
>>>>>                 client->next_reg_id = 1;
>>>>>
>>>>> @@ -2591,7 +2598,7 @@ unsigned int bt_gatt_client_register_notify(struct bt_gatt_client *client,
>>>>>         /*
>>>>>          * If the ref count is not zero, then notifications are already enabled.
>>>>>          */
>>>>> -       if (chrc->notify_count > 0) {
>>>>> +       if (chrc->notify_count > 0 || !chrc->ccc_handle) {
>>>>>                 complete_notify_request(notify_data);
>>>>>                 return notify_data->id;
>>>>>         }
>>>>> --
>>>>> 2.2.0.rc0.207.ga3a616c
>>>>>
>>>>> --
>>>>> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
>>>>> the body of a message to majordomo@xxxxxxxxxxxxxxx
>>>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>>>
>>>>
>>>>
>>>> --
>>>> Luiz Augusto von Dentz
>>>
>>> Thanks,
>>> Arman
>>
>>
>>
>> --
>> Luiz Augusto von Dentz
>
> ping

This has been applied, I just forgot to comment.



-- 
Luiz Augusto von Dentz
--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[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