2011-12-16 16:09:48

by Santiago Carot

[permalink] [raw]
Subject: RFC: GATT server multi-adapter support

This is an initial work to provide support for multiple adapters
in GATT server. Current implementation manages handlers and device
connections using global list without taking into account that we
can have many adapters plugged. These patches propose a separation
among handlers, clients management and other stuff in each adapter.

In this way, GATT servers plugins should register their attributes
on each adapter. Current interfaces doesn't provide support for that,
future work include exposing adapters in the APIS and using adapter
drivers to register attributes instead of doing that when the plugin
is initialized.

These patches don't modify current API yet, they use the default
adapter to manage GATT stuff when the adapter is not provided in
order to keep backward compatibility. In this way they can be
applied without causing compilation problems in GATT dependant
plugins which are using current GATT server interface.

Comments are welcome.

[PATCH 01/11] attrib-server: Initial steps to provide multi-adapter
[PATCH 02/11] attrib-server: Register GATT SDP record per each
[PATCH 03/11] attrib-server: Add attributes in adapter database
[PATCH 04/11] attrib-server: Attach attrib_channel in adapter
[PATCH 05/11] attrib-server: Remove global client list
[PATCH 06/11] attrib-server: Remove global le_io variable
[PATCH 07/11] attrib-server: Attah gatt channels to a adapters
[PATCH 08/11] attrib-server: Remove global database list
[PATCH 09/11] attrib-server: Mark attrib_channel_detach as
[PATCH 10/11] attrib-server: Remove
[PATCH 11/11] gatt-example: Use adapter driver to register GATT


2011-12-19 18:13:21

by Santiago Carot

[permalink] [raw]
Subject: Re: [PATCH 01/11] attrib-server: Initial steps to provide multi-adapter GATT server support

Hi,

2011/12/19 Anderson Lizardo <[email protected]>:
> Hi Santiago,
>
> On Mon, Dec 19, 2011 at 10:54 AM, Santiago Carot <[email protected]> wrote:
>> Hi,
>>
>> 2011/12/19 Santiago Carot <[email protected]>:
>>> Hi Anderson,
>>>
>>> 2011/12/19 Anderson Lizardo <[email protected]>:
>>>> Hi Santiago,
>>>>
>>>> On Mon, Dec 19, 2011 at 10:35 AM, Santiago Carot <[email protected]> wrote:
>>>>>> Is there race condition here? Remember that plugins can also register
>>>>>> an adapter driver.
>>>>>> If a GATT "plugin" wants to register attributes during the probing the
>>>>>> attribute server needs to be ready.
>>>>>>
>>>>>
>>>>> I know that, remember these are transactional patches towardas
>>>>> multi-adapter support. They only prepare the environment to start
>>>>> coding. The patch 11 fixes this issue. In fact, one could think that
>>>>> it should in this place but when I started coding it I thought it was
>>>>> easier to reutilize functions which were already implemented and
>>>>> change it after multi-adapter started working.
>>>>
>>
>> Sorry: patch 10 is supposed to deal with that :P
>
> Ok. Now it makes sense :) I still had not time to review the full
> series (only took a look on Claudio comments).
>
> Still, I'm not sure adding a whole adapter driver just to remove it
> later on the same series is worth the trouble. Looks like you are
> fixing an issue introduced on the same series.
>
> Is it possible for you to rearrange the series so it is not necessary
> to introduce the adapter driver?

I'll try to redo the patches again, don't worry about that, I have
sent them in this way to be sure I was following the right toward the
multi-adapter suport, I didn't want to spent the time fixing the
patches until being sure that this is the architecture we were looking
for.

Regards.

2011-12-19 16:17:15

by Anderson Lizardo

[permalink] [raw]
Subject: Re: [PATCH 01/11] attrib-server: Initial steps to provide multi-adapter GATT server support

Hi Santiago,

On Mon, Dec 19, 2011 at 10:54 AM, Santiago Carot <[email protected]> wrote:
> Hi,
>
> 2011/12/19 Santiago Carot <[email protected]>:
>> Hi Anderson,
>>
>> 2011/12/19 Anderson Lizardo <[email protected]>:
>>> Hi Santiago,
>>>
>>> On Mon, Dec 19, 2011 at 10:35 AM, Santiago Carot <[email protected]> wrote:
>>>>> Is there race condition here? Remember that plugins can also register
>>>>> an adapter driver.
>>>>> If a GATT "plugin" wants to register attributes during the probing the
>>>>> attribute server needs to be ready.
>>>>>
>>>>
>>>> I know that, remember these are transactional patches towardas
>>>> multi-adapter support. They only prepare the environment to start
>>>> coding. The patch 11 fixes this issue. In fact, one could think that
>>>> it should in this place but when I started coding it I thought it was
>>>> easier to reutilize functions which were already implemented and
>>>> change it after multi-adapter started working.
>>>
>
> Sorry: patch 10 is supposed to deal with that :P

Ok. Now it makes sense :) I still had not time to review the full
series (only took a look on Claudio comments).

Still, I'm not sure adding a whole adapter driver just to remove it
later on the same series is worth the trouble. Looks like you are
fixing an issue introduced on the same series.

Is it possible for you to rearrange the series so it is not necessary
to introduce the adapter driver?

If not, please improve the patches commit messages to explain why it
is introduced (and the known problems), and that it is removed on a
later patch. This helps a lot tracing regressions later.

Best Regards,
--
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil

2011-12-19 14:54:42

by Santiago Carot

[permalink] [raw]
Subject: Re: [PATCH 01/11] attrib-server: Initial steps to provide multi-adapter GATT server support

Hi,

2011/12/19 Santiago Carot <[email protected]>:
> Hi Anderson,
>
> 2011/12/19 Anderson Lizardo <[email protected]>:
>> Hi Santiago,
>>
>> On Mon, Dec 19, 2011 at 10:35 AM, Santiago Carot <[email protected]> wrote:
>>>> Is there race condition here? Remember that plugins can also register
>>>> an adapter driver.
>>>> If a GATT "plugin" wants to register attributes during the probing the
>>>> attribute server needs to be ready.
>>>>
>>>
>>> I know that, remember these are transactional patches towardas
>>> multi-adapter support. They only prepare the environment to start
>>> coding. The patch 11 fixes this issue. In fact, one could think that
>>> it should in this place but when I started coding it I thought it was
>>> easier to reutilize functions which were already implemented and
>>> change it after multi-adapter started working.
>>

Sorry: patch 10 is supposed to deal with that :P

>> I don't think patch 11 fixes the architectural issue of initializing
>> the attribute databases on a adapter driver. You can't guarantee it
>> will be initialized prior to other adapter drivers (registered by GATT
>> plugins).
>>
>
> Patch 11 removes the adapter driver usage and initializes the GATT
> server (and related stuff) in the adapter during the adapter setup,
> this is operation is done before any other adapter plugin is called:
>
> diff --git a/src/adapter.c b/src/adapter.c
> index 1a701a4..200e9d9 100644
> --- a/src/adapter.c
> +++ b/src/adapter.c
> @@ -2483,6 +2483,10 @@ gboolean adapter_init(struct btd_adapter *adapter)
> ? ? ? }
>
> ? ? ? sdp_init_services_list(&adapter->bdaddr);
> +
> + ? ? ? if (main_opts.attrib_server)
> + ? ? ? ? ? ? ? btd_adapter_gatt_server_start(adapter);
> +
> ? ? ? load_drivers(adapter);
> ? ? ? clear_blocked(adapter);
> ? ? ? load_devices(adapter);
>
> Please, corect me if I'm wrong.
>
>> Please take our comments as responses to the RFC :)
>
> ?Of course, and they are very welcome ;)
> Regards.

2011-12-19 14:51:57

by Santiago Carot

[permalink] [raw]
Subject: Re: [PATCH 01/11] attrib-server: Initial steps to provide multi-adapter GATT server support

Hi Anderson,

2011/12/19 Anderson Lizardo <[email protected]>:
> Hi Santiago,
>
> On Mon, Dec 19, 2011 at 10:35 AM, Santiago Carot <[email protected]> wrote:
>>> Is there race condition here? Remember that plugins can also register
>>> an adapter driver.
>>> If a GATT "plugin" wants to register attributes during the probing the
>>> attribute server needs to be ready.
>>>
>>
>> I know that, remember these are transactional patches towardas
>> multi-adapter support. They only prepare the environment to start
>> coding. The patch 11 fixes this issue. In fact, one could think that
>> it should in this place but when I started coding it I thought it was
>> easier to reutilize functions which were already implemented and
>> change it after multi-adapter started working.
>
> I don't think patch 11 fixes the architectural issue of initializing
> the attribute databases on a adapter driver. You can't guarantee it
> will be initialized prior to other adapter drivers (registered by GATT
> plugins).
>

Patch 11 removes the adapter driver usage and initializes the GATT
server (and related stuff) in the adapter during the adapter setup,
this is operation is done before any other adapter plugin is called:

diff --git a/src/adapter.c b/src/adapter.c
index 1a701a4..200e9d9 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -2483,6 +2483,10 @@ gboolean adapter_init(struct btd_adapter *adapter)
}

sdp_init_services_list(&adapter->bdaddr);
+
+ if (main_opts.attrib_server)
+ btd_adapter_gatt_server_start(adapter);
+
load_drivers(adapter);
clear_blocked(adapter);
load_devices(adapter);

Please, corect me if I'm wrong.

> Please take our comments as responses to the RFC :)

Of course, and they are very welcome ;)
Regards.

2011-12-19 14:41:56

by Anderson Lizardo

[permalink] [raw]
Subject: Re: [PATCH 01/11] attrib-server: Initial steps to provide multi-adapter GATT server support

Hi Santiago,

On Mon, Dec 19, 2011 at 10:35 AM, Santiago Carot <[email protected]> wrote:
>> Is there race condition here? Remember that plugins can also register
>> an adapter driver.
>> If a GATT "plugin" wants to register attributes during the probing the
>> attribute server needs to be ready.
>>
>
> I know that, remember these are transactional patches towardas
> multi-adapter support. They only prepare the environment to start
> coding. The patch 11 fixes this issue. In fact, one could think that
> it should in this place but when I started coding it I thought it was
> easier to reutilize functions which were already implemented and
> change it after multi-adapter started working.

I don't think patch 11 fixes the architectural issue of initializing
the attribute databases on a adapter driver. You can't guarantee it
will be initialized prior to other adapter drivers (registered by GATT
plugins).

> Changing the order of patches or redo them is easy once I get an ack
> to do that if the idea showed here is good. I'm just looking for
> comments about the main idea behind them.

Please take our comments as responses to the RFC :)

Regards,
--
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil

2011-12-19 14:35:42

by Santiago Carot

[permalink] [raw]
Subject: Re: [PATCH 01/11] attrib-server: Initial steps to provide multi-adapter GATT server support

Hi Claudio,

2011/12/19 Claudio Takahasi <[email protected]>:
> Hi Santiago,
>
> On Fri, Dec 16, 2011 at 1:09 PM, Santiago Carot-Nemesio
> <[email protected]> wrote:
>> This patch prepares the structures in att-server to start and stop
>> GATT server whenever an adapter is plugged or unplugged.
>> ---
>> ?src/attrib-server.c | ?168 +++++++++++++++++++++++++++++++++++----------------
>> ?1 files changed, 116 insertions(+), 52 deletions(-)
>>
>> diff --git a/src/attrib-server.c b/src/attrib-server.c
>> index b767b72..e8dade8 100644
>> --- a/src/attrib-server.c
>> +++ b/src/attrib-server.c
>> @@ -71,12 +71,23 @@ struct group_elem {
>> ? ? ? ?uint16_t len;
>> ?};
>>
>> -static GIOChannel *l2cap_io = NULL;
>> ?static GIOChannel *le_io = NULL;
> le_io is not being used anymore.
>
>> ?static GSList *clients = NULL;
>> ?static uint32_t gatt_sdp_handle = 0;
>> ?static uint32_t gap_sdp_handle = 0;
>>
>> +struct gatt_adapter {
>> + ? ? ? struct btd_adapter ? ? ?*adapter;
>> + ? ? ? GIOChannel ? ? ? ? ? ? ?*l2cap_io;
>> + ? ? ? GIOChannel ? ? ? ? ? ? ?*le_io;
>> + ? ? ? GSList ? ? ? ? ? ? ? ? ?*clients;
>> + ? ? ? uint32_t ? ? ? ? ? ? ? ?gatt_sdp_handle;
>> + ? ? ? uint32_t ? ? ? ? ? ? ? ?gap_sdp_handle;
>> + ? ? ? GSList ? ? ? ? ? ? ? ? ?*database;
>
> I recommend to introduce new variable when the it is really being
> used. "database" and "clients" are used by free functions only, but
> new elements are not being added in the list by this patch.
>

These are a RFC patches, I put them in here so that everybody can see
at the first sight what I'm pretending to do. Anycase I agree with
you.

>> +};
>> +
>> +static GSList *adapters = NULL;
>> +
>> ?/* GAP attribute handles */
>> ?static uint16_t name_handle = 0x0000;
>> ?static uint16_t appearance_handle = 0x0000;
>> @@ -94,6 +105,60 @@ static bt_uuid_t ccc_uuid = {
>> ? ? ? ? ? ? ? ? ? ? ? ?.value.u16 = GATT_CLIENT_CHARAC_CFG_UUID
>> ?};
>>
>> +static void attrib_free(void *data)
>> +{
>> + ? ? ? struct attribute *a = data;
>> +
>> + ? ? ? g_free(a->data);
>> + ? ? ? g_free(a);
>> +}
>> +
>> +static void channel_free(struct gatt_channel *channel)
>> +{
>> + ? ? ? g_attrib_unref(channel->attrib);
>> +
>> + ? ? ? g_free(channel);
>> +}
>> +
>> +static void free_gatt_adapter(struct gatt_adapter *gatt_adapter)
> the coding style is "free" at the end of the function name
>
>> +{
>> + ? ? ? g_slist_free_full(gatt_adapter->database, attrib_free);
>> +
>> + ? ? ? if (gatt_adapter->l2cap_io != NULL) {
>> + ? ? ? ? ? ? ? g_io_channel_unref(gatt_adapter->l2cap_io);
>> + ? ? ? ? ? ? ? g_io_channel_shutdown(gatt_adapter->l2cap_io, FALSE, NULL);
>> + ? ? ? }
>> +
>> + ? ? ? if (gatt_adapter->le_io != NULL) {
>> + ? ? ? ? ? ? ? g_io_channel_unref(gatt_adapter->le_io);
>> + ? ? ? ? ? ? ? g_io_channel_shutdown(gatt_adapter->le_io, FALSE, NULL);
>> + ? ? ? }
>> +
>> + ? ? ? g_slist_free_full(gatt_adapter->clients, (GDestroyNotify) channel_free);
>> +
>> + ? ? ? if (gatt_adapter->gatt_sdp_handle > 0)
>> + ? ? ? ? ? ? ? remove_record_from_server(gatt_adapter->gatt_sdp_handle);
>> +
>> + ? ? ? if (gatt_adapter->gap_sdp_handle > 0)
>> + ? ? ? ? ? ? ? remove_record_from_server(gatt_adapter->gap_sdp_handle);
>
> Removing gap_sdp_handle again
>
>> +
>> + ? ? ? if (gatt_adapter->adapter != NULL)
>> + ? ? ? ? ? ? ? btd_adapter_unref(gatt_adapter->adapter);
>> +
>> + ? ? ? g_free(gatt_adapter);
>> +}
>> +
>> +static gint adapter_cmp(gconstpointer a, gconstpointer b)
>> +{
>> + ? ? ? const struct gatt_adapter *gatt_adapter = a;
>> + ? ? ? const struct btd_adapter *adapter = b;
>> +
>> + ? ? ? if (gatt_adapter->adapter == adapter)
>> + ? ? ? ? ? ? ? return 0;
>> +
>> + ? ? ? return -1;
>> +}
>> +
>> ?static sdp_record_t *server_record_new(uuid_t *uuid, uint16_t start, uint16_t end)
>> ?{
>> ? ? ? ?sdp_list_t *svclass_id, *apseq, *proto[2], *root, *aproto;
>> @@ -689,21 +754,6 @@ static uint16_t mtu_exchange(struct gatt_channel *channel, uint16_t mtu,
>> ? ? ? ?return enc_mtu_resp(old_mtu, pdu, len);
>> ?}
>>
>> -static void attrib_free(void *data)
>> -{
>> - ? ? ? struct attribute *a = data;
>> -
>> - ? ? ? g_free(a->data);
>> - ? ? ? g_free(a);
>> -}
>> -
>> -static void channel_free(struct gatt_channel *channel)
>> -{
>> - ? ? ? g_attrib_unref(channel->attrib);
>> -
>> - ? ? ? g_free(channel);
>> -}
>> -
>> ?static void channel_disconnect(void *user_data)
>> ?{
>> ? ? ? ?struct gatt_channel *channel = user_data;
>> @@ -1012,74 +1062,88 @@ failed:
>> ? ? ? ?return FALSE;
>> ?}
>>
>> -int attrib_server_init(void)
>> +static int attrib_adapter_probe(struct btd_adapter *adapter)
>> ?{
>> + ? ? ? struct gatt_adapter *gatt_adapter;
>> ? ? ? ?GError *gerr = NULL;
>> + ? ? ? bdaddr_t addr;
>> +
>> + ? ? ? DBG("Start GATT server in %s", adapter_get_path(adapter));
>> +
>> + ? ? ? gatt_adapter = g_new0(struct gatt_adapter, 1);
>> + ? ? ? gatt_adapter->adapter = btd_adapter_ref(adapter);
>> +
>> + ? ? ? adapter_get_address(gatt_adapter->adapter, &addr);
>>
>> ? ? ? ?/* BR/EDR socket */
>> - ? ? ? l2cap_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event,
>> + ? ? ? gatt_adapter->l2cap_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event,
>> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?NULL, NULL, &gerr,
>> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? BT_IO_OPT_SOURCE_BDADDR, BDADDR_ANY,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? BT_IO_OPT_SOURCE_BDADDR, &addr,
>> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?BT_IO_OPT_PSM, ATT_PSM,
>> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
>> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?BT_IO_OPT_INVALID);
>> - ? ? ? if (l2cap_io == NULL) {
>> +
>> + ? ? ? if (gatt_adapter->l2cap_io == NULL) {
>> ? ? ? ? ? ? ? ?error("%s", gerr->message);
>> ? ? ? ? ? ? ? ?g_error_free(gerr);
>> + ? ? ? ? ? ? ? free_gatt_adapter(gatt_adapter);
>> ? ? ? ? ? ? ? ?return -1;
>> ? ? ? ?}
>>
>> - ? ? ? if (!register_core_services())
>> - ? ? ? ? ? ? ? goto failed;
>> + ? ? ? if (!register_core_services()) {
>> + ? ? ? ? ? ? ? g_io_channel_unref(gatt_adapter->l2cap_io);
>> + ? ? ? ? ? ? ? free_gatt_adapter(gatt_adapter);
>
> Two unref calls for l2cap_io here. free function also calls unref for l2cap_io
>
>> + ? ? ? ? ? ? ? return -1;
>> + ? ? ? }
>>
>> ? ? ? ?/* LE socket */
>> - ? ? ? le_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event,
>> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &le_io, NULL, &gerr,
>> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? BT_IO_OPT_SOURCE_BDADDR, BDADDR_ANY,
>> + ? ? ? gatt_adapter->le_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &gatt_adapter->le_io, NULL, &gerr,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? BT_IO_OPT_SOURCE_BDADDR, &addr,
>> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?BT_IO_OPT_CID, ATT_CID,
>> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
>> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?BT_IO_OPT_INVALID);
>> - ? ? ? if (le_io == NULL) {
>> +
>> + ? ? ? if (gatt_adapter->le_io == NULL) {
>> ? ? ? ? ? ? ? ?error("%s", gerr->message);
>> ? ? ? ? ? ? ? ?g_error_free(gerr);
>> ? ? ? ? ? ? ? ?/* Doesn't have LE support, continue */
>> ? ? ? ?}
>>
>> + ? ? ? adapters = g_slist_prepend(adapters, gatt_adapter);
>> ? ? ? ?return 0;
>> -
>> -failed:
>> - ? ? ? g_io_channel_unref(l2cap_io);
>> - ? ? ? l2cap_io = NULL;
>> -
>> - ? ? ? if (le_io) {
>> - ? ? ? ? ? ? ? g_io_channel_unref(le_io);
>> - ? ? ? ? ? ? ? le_io = NULL;
>> - ? ? ? }
>> -
>> - ? ? ? return -1;
>> ?}
>>
>> -void attrib_server_exit(void)
>> +static void attrib_adapter_remove(struct btd_adapter *adapter)
>> ?{
>> - ? ? ? g_slist_free_full(database, attrib_free);
>> + ? ? ? struct gatt_adapter *gatt_adapter;
>> + ? ? ? GSList *l;
>>
>> - ? ? ? if (l2cap_io) {
>> - ? ? ? ? ? ? ? g_io_channel_unref(l2cap_io);
>> - ? ? ? ? ? ? ? g_io_channel_shutdown(l2cap_io, FALSE, NULL);
>> - ? ? ? }
>> + ? ? ? l = g_slist_find_custom(adapters, adapter, adapter_cmp);
>> + ? ? ? if (l == NULL)
>> + ? ? ? ? ? ? ? return;
>>
>> - ? ? ? if (le_io) {
>> - ? ? ? ? ? ? ? g_io_channel_unref(le_io);
>> - ? ? ? ? ? ? ? g_io_channel_shutdown(le_io, FALSE, NULL);
>> - ? ? ? }
>> + ? ? ? DBG("Stop GATT server in %s", adapter_get_path(adapter));
>>
>> - ? ? ? g_slist_free_full(clients, (GDestroyNotify) channel_free);
>> + ? ? ? gatt_adapter = l->data;
>> + ? ? ? adapters = g_slist_remove(adapters, gatt_adapter);
>> + ? ? ? free_gatt_adapter(gatt_adapter);
>> +}
>>
>> - ? ? ? if (gatt_sdp_handle)
>> - ? ? ? ? ? ? ? remove_record_from_server(gatt_sdp_handle);
>> +static struct btd_adapter_driver attrib_adapter_driver = {
>> + ? ? ? .name ? = "attrib-adapter-driver",
>> + ? ? ? .probe ?= attrib_adapter_probe,
>> + ? ? ? .remove = attrib_adapter_remove,
>> +};
>
> Is there race condition here? Remember that plugins can also register
> an adapter driver.
> If a GATT "plugin" wants to register attributes during the probing the
> attribute server needs to be ready.
>

I know that, remember these are transactional patches towardas
multi-adapter support. They only prepare the environment to start
coding. The patch 11 fixes this issue. In fact, one could think that
it should in this place but when I started coding it I thought it was
easier to reutilize functions which were already implemented and
change it after multi-adapter started working.

Changing the order of patches or redo them is easy once I get an ack
to do that if the idea showed here is good. I'm just looking for
comments about the main idea behind them.

Thanks

2011-12-19 14:35:26

by Anderson Lizardo

[permalink] [raw]
Subject: Re: [PATCH 01/11] attrib-server: Initial steps to provide multi-adapter GATT server support

Hi Santiago,

On Mon, Dec 19, 2011 at 10:08 AM, Claudio Takahasi
<[email protected]> wrote:
>> +static struct btd_adapter_driver attrib_adapter_driver = {
>> + ? ? ? .name ? = "attrib-adapter-driver",
>> + ? ? ? .probe ?= attrib_adapter_probe,
>> + ? ? ? .remove = attrib_adapter_remove,
>> +};
>
> Is there race condition here? Remember that plugins can also register
> an adapter driver.
> If a GATT "plugin" wants to register attributes during the probing the
> attribute server needs to be ready.

I agree with Claudio here. We should not rely on adapter drivers for
initializing the attribute server (although I previously thought it
could be that simple as well). Otherwise, plugins can't also use
adapter driver's probe() to register attributes , which defeats the
idea of per-adapter ATT attributes.

I think the attribute server should be initialized at an early stage,
after the adapter is created, but prior to having the adapter drivers
called.

Regards,
--
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil

2011-12-19 14:08:45

by Claudio Takahasi

[permalink] [raw]
Subject: Re: [PATCH 01/11] attrib-server: Initial steps to provide multi-adapter GATT server support

Hi Santiago,

On Fri, Dec 16, 2011 at 1:09 PM, Santiago Carot-Nemesio
<[email protected]> wrote:
> This patch prepares the structures in att-server to start and stop
> GATT server whenever an adapter is plugged or unplugged.
> ---
>  src/attrib-server.c |  168 +++++++++++++++++++++++++++++++++++----------------
>  1 files changed, 116 insertions(+), 52 deletions(-)
>
> diff --git a/src/attrib-server.c b/src/attrib-server.c
> index b767b72..e8dade8 100644
> --- a/src/attrib-server.c
> +++ b/src/attrib-server.c
> @@ -71,12 +71,23 @@ struct group_elem {
>        uint16_t len;
>  };
>
> -static GIOChannel *l2cap_io = NULL;
>  static GIOChannel *le_io = NULL;
le_io is not being used anymore.

>  static GSList *clients = NULL;
>  static uint32_t gatt_sdp_handle = 0;
>  static uint32_t gap_sdp_handle = 0;
>
> +struct gatt_adapter {
> +       struct btd_adapter      *adapter;
> +       GIOChannel              *l2cap_io;
> +       GIOChannel              *le_io;
> +       GSList                  *clients;
> +       uint32_t                gatt_sdp_handle;
> +       uint32_t                gap_sdp_handle;
> +       GSList                  *database;

I recommend to introduce new variable when the it is really being
used. "database" and "clients" are used by free functions only, but
new elements are not being added in the list by this patch.

> +};
> +
> +static GSList *adapters = NULL;
> +
>  /* GAP attribute handles */
>  static uint16_t name_handle = 0x0000;
>  static uint16_t appearance_handle = 0x0000;
> @@ -94,6 +105,60 @@ static bt_uuid_t ccc_uuid = {
>                        .value.u16 = GATT_CLIENT_CHARAC_CFG_UUID
>  };
>
> +static void attrib_free(void *data)
> +{
> +       struct attribute *a = data;
> +
> +       g_free(a->data);
> +       g_free(a);
> +}
> +
> +static void channel_free(struct gatt_channel *channel)
> +{
> +       g_attrib_unref(channel->attrib);
> +
> +       g_free(channel);
> +}
> +
> +static void free_gatt_adapter(struct gatt_adapter *gatt_adapter)
the coding style is "free" at the end of the function name

> +{
> +       g_slist_free_full(gatt_adapter->database, attrib_free);
> +
> +       if (gatt_adapter->l2cap_io != NULL) {
> +               g_io_channel_unref(gatt_adapter->l2cap_io);
> +               g_io_channel_shutdown(gatt_adapter->l2cap_io, FALSE, NULL);
> +       }
> +
> +       if (gatt_adapter->le_io != NULL) {
> +               g_io_channel_unref(gatt_adapter->le_io);
> +               g_io_channel_shutdown(gatt_adapter->le_io, FALSE, NULL);
> +       }
> +
> +       g_slist_free_full(gatt_adapter->clients, (GDestroyNotify) channel_free);
> +
> +       if (gatt_adapter->gatt_sdp_handle > 0)
> +               remove_record_from_server(gatt_adapter->gatt_sdp_handle);
> +
> +       if (gatt_adapter->gap_sdp_handle > 0)
> +               remove_record_from_server(gatt_adapter->gap_sdp_handle);

Removing gap_sdp_handle again

> +
> +       if (gatt_adapter->adapter != NULL)
> +               btd_adapter_unref(gatt_adapter->adapter);
> +
> +       g_free(gatt_adapter);
> +}
> +
> +static gint adapter_cmp(gconstpointer a, gconstpointer b)
> +{
> +       const struct gatt_adapter *gatt_adapter = a;
> +       const struct btd_adapter *adapter = b;
> +
> +       if (gatt_adapter->adapter == adapter)
> +               return 0;
> +
> +       return -1;
> +}
> +
>  static sdp_record_t *server_record_new(uuid_t *uuid, uint16_t start, uint16_t end)
>  {
>        sdp_list_t *svclass_id, *apseq, *proto[2], *root, *aproto;
> @@ -689,21 +754,6 @@ static uint16_t mtu_exchange(struct gatt_channel *channel, uint16_t mtu,
>        return enc_mtu_resp(old_mtu, pdu, len);
>  }
>
> -static void attrib_free(void *data)
> -{
> -       struct attribute *a = data;
> -
> -       g_free(a->data);
> -       g_free(a);
> -}
> -
> -static void channel_free(struct gatt_channel *channel)
> -{
> -       g_attrib_unref(channel->attrib);
> -
> -       g_free(channel);
> -}
> -
>  static void channel_disconnect(void *user_data)
>  {
>        struct gatt_channel *channel = user_data;
> @@ -1012,74 +1062,88 @@ failed:
>        return FALSE;
>  }
>
> -int attrib_server_init(void)
> +static int attrib_adapter_probe(struct btd_adapter *adapter)
>  {
> +       struct gatt_adapter *gatt_adapter;
>        GError *gerr = NULL;
> +       bdaddr_t addr;
> +
> +       DBG("Start GATT server in %s", adapter_get_path(adapter));
> +
> +       gatt_adapter = g_new0(struct gatt_adapter, 1);
> +       gatt_adapter->adapter = btd_adapter_ref(adapter);
> +
> +       adapter_get_address(gatt_adapter->adapter, &addr);
>
>        /* BR/EDR socket */
> -       l2cap_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event,
> +       gatt_adapter->l2cap_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event,
>                                        NULL, NULL, &gerr,
> -                                       BT_IO_OPT_SOURCE_BDADDR, BDADDR_ANY,
> +                                       BT_IO_OPT_SOURCE_BDADDR, &addr,
>                                        BT_IO_OPT_PSM, ATT_PSM,
>                                        BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
>                                        BT_IO_OPT_INVALID);
> -       if (l2cap_io == NULL) {
> +
> +       if (gatt_adapter->l2cap_io == NULL) {
>                error("%s", gerr->message);
>                g_error_free(gerr);
> +               free_gatt_adapter(gatt_adapter);
>                return -1;
>        }
>
> -       if (!register_core_services())
> -               goto failed;
> +       if (!register_core_services()) {
> +               g_io_channel_unref(gatt_adapter->l2cap_io);
> +               free_gatt_adapter(gatt_adapter);

Two unref calls for l2cap_io here. free function also calls unref for l2cap_io

> +               return -1;
> +       }
>
>        /* LE socket */
> -       le_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event,
> -                                       &le_io, NULL, &gerr,
> -                                       BT_IO_OPT_SOURCE_BDADDR, BDADDR_ANY,
> +       gatt_adapter->le_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event,
> +                                       &gatt_adapter->le_io, NULL, &gerr,
> +                                       BT_IO_OPT_SOURCE_BDADDR, &addr,
>                                        BT_IO_OPT_CID, ATT_CID,
>                                        BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
>                                        BT_IO_OPT_INVALID);
> -       if (le_io == NULL) {
> +
> +       if (gatt_adapter->le_io == NULL) {
>                error("%s", gerr->message);
>                g_error_free(gerr);
>                /* Doesn't have LE support, continue */
>        }
>
> +       adapters = g_slist_prepend(adapters, gatt_adapter);
>        return 0;
> -
> -failed:
> -       g_io_channel_unref(l2cap_io);
> -       l2cap_io = NULL;
> -
> -       if (le_io) {
> -               g_io_channel_unref(le_io);
> -               le_io = NULL;
> -       }
> -
> -       return -1;
>  }
>
> -void attrib_server_exit(void)
> +static void attrib_adapter_remove(struct btd_adapter *adapter)
>  {
> -       g_slist_free_full(database, attrib_free);
> +       struct gatt_adapter *gatt_adapter;
> +       GSList *l;
>
> -       if (l2cap_io) {
> -               g_io_channel_unref(l2cap_io);
> -               g_io_channel_shutdown(l2cap_io, FALSE, NULL);
> -       }
> +       l = g_slist_find_custom(adapters, adapter, adapter_cmp);
> +       if (l == NULL)
> +               return;
>
> -       if (le_io) {
> -               g_io_channel_unref(le_io);
> -               g_io_channel_shutdown(le_io, FALSE, NULL);
> -       }
> +       DBG("Stop GATT server in %s", adapter_get_path(adapter));
>
> -       g_slist_free_full(clients, (GDestroyNotify) channel_free);
> +       gatt_adapter = l->data;
> +       adapters = g_slist_remove(adapters, gatt_adapter);
> +       free_gatt_adapter(gatt_adapter);
> +}
>
> -       if (gatt_sdp_handle)
> -               remove_record_from_server(gatt_sdp_handle);
> +static struct btd_adapter_driver attrib_adapter_driver = {
> +       .name   = "attrib-adapter-driver",
> +       .probe  = attrib_adapter_probe,
> +       .remove = attrib_adapter_remove,
> +};

Is there race condition here? Remember that plugins can also register
an adapter driver.
If a GATT "plugin" wants to register attributes during the probing the
attribute server needs to be ready.

BR,
Claudio

2011-12-17 09:28:48

by Santiago Carot

[permalink] [raw]
Subject: Re: [PATCH 11/11] gatt-example: Use adapter driver to register GATT attributes

Hi everybody,

2011/12/16 Santiago Carot-Nemesio <[email protected]>:
> GATT servers should register their attributes on each adapter when
> it is plugged instead of doing that when the plugins is loaded. This
> patch registers a new adapter driver to manage plug and unplug
> events in order to register attributes in each GATT served managed
> in each adapter.
> ---
> ?plugins/gatt-example.c | ? 46 +++++++++++++++++++++++++++++++++++++++-------
> ?1 files changed, 39 insertions(+), 7 deletions(-)
>
> diff --git a/plugins/gatt-example.c b/plugins/gatt-example.c
> index 6d9b6b8..c719697 100644
> --- a/plugins/gatt-example.c
> +++ b/plugins/gatt-example.c
> @@ -29,6 +29,7 @@
> ?#include <glib.h>
> ?#include <bluetooth/uuid.h>
> ?#include <errno.h>
> +#include <adapter.h>
>
> ?#include "plugin.h"
> ?#include "hcid.h"
> @@ -59,6 +60,8 @@
>
> ?static GSList *sdp_handles = NULL;
>
> +static gboolean started = FALSE;
> +
> ?static uint8_t battery_state_read(struct attribute *a, gpointer user_data)
> ?{
> ? ? ? ?uint8_t value;
> @@ -436,19 +439,19 @@ static void register_weight_service(const uint16_t vendor[2])
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?GUINT_TO_POINTER(sdp_handle));
> ?}
>
> -static int gatt_example_init(void)
> +static int gatt_example_adapter_probe(struct btd_adapter *adapter)
> ?{
> ? ? ? ?uint16_t manuf1_range[2] = {0, 0}, manuf2_range[2] = {0, 0};
> ? ? ? ?uint16_t vendor_range[2] = {0, 0};
>
> - ? ? ? if (!main_opts.attrib_server) {
> - ? ? ? ? ? ? ? DBG("Attribute server is disabled");
> + ? ? ? /* FIXME: Add support for more than one adapter */
> +
> + ? ? ? if (started)
> ? ? ? ? ? ? ? ?return -1;
> - ? ? ? }
>
> ? ? ? ?if (!register_battery_service()) {
> ? ? ? ? ? ? ? ?DBG("Battery service could not be registered");
> - ? ? ? ? ? ? ? return -EIO;
> + ? ? ? ? ? ? ? return -1;
> ? ? ? ?}
>
> ? ? ? ?register_manuf1_service(manuf1_range);
> @@ -457,12 +460,15 @@ static int gatt_example_init(void)
> ? ? ? ?register_vendor_service(vendor_range);
> ? ? ? ?register_weight_service(vendor_range);
>
> + ? ? ? started = TRUE;
> ? ? ? ?return 0;
> ?}
>
> -static void gatt_example_exit(void)
> +static void gatt_example_adapter_remove(struct btd_adapter *adapter)
> ?{
> - ? ? ? if (!main_opts.attrib_server)
> + ? ? ? /* FIXME: Add support for more than one adapter */
> +
> + ? ? ? if (!started)
> ? ? ? ? ? ? ? ?return;
>
> ? ? ? ?while (sdp_handles) {
> @@ -471,6 +477,32 @@ static void gatt_example_exit(void)
> ? ? ? ? ? ? ? ?attrib_free_sdp(handle);
> ? ? ? ? ? ? ? ?sdp_handles = g_slist_remove(sdp_handles, sdp_handles->data);
> ? ? ? ?}
> +
> + ? ? ? started = FALSE;
> +}
> +
> +static struct btd_adapter_driver gatt_example_adapter_driver = {
> + ? ? ? .name ? = "hdp-adapter-driver",
> + ? ? ? .probe ?= gatt_example_adapter_probe,
> + ? ? ? .remove = gatt_example_adapter_remove,
> +};
> +
> +static int gatt_example_init(void)
> +{
> + ? ? ? if (!main_opts.attrib_server) {
> + ? ? ? ? ? ? ? DBG("Attribute server is disabled");
> + ? ? ? ? ? ? ? return -1;
> + ? ? ? }
> +
> + ? ? ? return btd_register_adapter_driver(&gatt_example_adapter_driver);
> +}
> +
> +static void gatt_example_exit(void)
> +{
> + ? ? ? if (!main_opts.attrib_server)
> + ? ? ? ? ? ? ? return;
> +
> + ? ? ? btd_register_adapter_driver(&gatt_example_adapter_driver);
> ?}
>
> ?BLUETOOTH_PLUGIN_DEFINE(gatt_example, VERSION, BLUETOOTH_PLUGIN_PRIORITY_LOW,
> --
> 1.7.8
>

This last patch is only a proof of concept, don't waste your time
rewieging it, just discard it
Regards

2011-12-16 16:09:59

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 11/11] gatt-example: Use adapter driver to register GATT attributes

GATT servers should register their attributes on each adapter when
it is plugged instead of doing that when the plugins is loaded. This
patch registers a new adapter driver to manage plug and unplug
events in order to register attributes in each GATT served managed
in each adapter.
---
plugins/gatt-example.c | 46 +++++++++++++++++++++++++++++++++++++++-------
1 files changed, 39 insertions(+), 7 deletions(-)

diff --git a/plugins/gatt-example.c b/plugins/gatt-example.c
index 6d9b6b8..c719697 100644
--- a/plugins/gatt-example.c
+++ b/plugins/gatt-example.c
@@ -29,6 +29,7 @@
#include <glib.h>
#include <bluetooth/uuid.h>
#include <errno.h>
+#include <adapter.h>

#include "plugin.h"
#include "hcid.h"
@@ -59,6 +60,8 @@

static GSList *sdp_handles = NULL;

+static gboolean started = FALSE;
+
static uint8_t battery_state_read(struct attribute *a, gpointer user_data)
{
uint8_t value;
@@ -436,19 +439,19 @@ static void register_weight_service(const uint16_t vendor[2])
GUINT_TO_POINTER(sdp_handle));
}

-static int gatt_example_init(void)
+static int gatt_example_adapter_probe(struct btd_adapter *adapter)
{
uint16_t manuf1_range[2] = {0, 0}, manuf2_range[2] = {0, 0};
uint16_t vendor_range[2] = {0, 0};

- if (!main_opts.attrib_server) {
- DBG("Attribute server is disabled");
+ /* FIXME: Add support for more than one adapter */
+
+ if (started)
return -1;
- }

if (!register_battery_service()) {
DBG("Battery service could not be registered");
- return -EIO;
+ return -1;
}

register_manuf1_service(manuf1_range);
@@ -457,12 +460,15 @@ static int gatt_example_init(void)
register_vendor_service(vendor_range);
register_weight_service(vendor_range);

+ started = TRUE;
return 0;
}

-static void gatt_example_exit(void)
+static void gatt_example_adapter_remove(struct btd_adapter *adapter)
{
- if (!main_opts.attrib_server)
+ /* FIXME: Add support for more than one adapter */
+
+ if (!started)
return;

while (sdp_handles) {
@@ -471,6 +477,32 @@ static void gatt_example_exit(void)
attrib_free_sdp(handle);
sdp_handles = g_slist_remove(sdp_handles, sdp_handles->data);
}
+
+ started = FALSE;
+}
+
+static struct btd_adapter_driver gatt_example_adapter_driver = {
+ .name = "hdp-adapter-driver",
+ .probe = gatt_example_adapter_probe,
+ .remove = gatt_example_adapter_remove,
+};
+
+static int gatt_example_init(void)
+{
+ if (!main_opts.attrib_server) {
+ DBG("Attribute server is disabled");
+ return -1;
+ }
+
+ return btd_register_adapter_driver(&gatt_example_adapter_driver);
+}
+
+static void gatt_example_exit(void)
+{
+ if (!main_opts.attrib_server)
+ return;
+
+ btd_register_adapter_driver(&gatt_example_adapter_driver);
}

BLUETOOTH_PLUGIN_DEFINE(gatt_example, VERSION, BLUETOOTH_PLUGIN_PRIORITY_LOW,
--
1.7.8


2011-12-16 16:09:58

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 10/11] attrib-server: Remove attrib_server_exit/attrib_server_exit functions

We need neither to init nor stop gatt server whenever the demon starts
and finishes the execution, instead of doing that, we init or stop the
GATT server when the adapter is initialized or removed. Furthermore,
we don't use btd_adapter_driver any more because the GATT server must
be already initialized before any plugin use it.
---
src/adapter.c | 7 +++++++
src/adapter.h | 3 +++
src/attrib-server.c | 24 ++++--------------------
src/hcid.h | 3 ---
src/main.c | 8 --------
5 files changed, 14 insertions(+), 31 deletions(-)

diff --git a/src/adapter.c b/src/adapter.c
index 1a701a4..200e9d9 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -2483,6 +2483,10 @@ gboolean adapter_init(struct btd_adapter *adapter)
}

sdp_init_services_list(&adapter->bdaddr);
+
+ if (main_opts.attrib_server)
+ btd_adapter_gatt_server_start(adapter);
+
load_drivers(adapter);
clear_blocked(adapter);
load_devices(adapter);
@@ -2542,6 +2546,9 @@ void adapter_remove(struct btd_adapter *adapter)
g_slist_free(adapter->devices);

unload_drivers(adapter);
+ if (main_opts.attrib_server)
+ btd_adapter_gatt_server_stop(adapter);
+
g_slist_free(adapter->pin_callbacks);

/* Return adapter to down state if it was not up on init */
diff --git a/src/adapter.h b/src/adapter.h
index ff1d659..2f8f125 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -275,3 +275,6 @@ int btd_adapter_add_remote_oob_data(struct btd_adapter *adapter,

int btd_adapter_remove_remote_oob_data(struct btd_adapter *adapter,
bdaddr_t *bdaddr);
+
+int btd_adapter_gatt_server_start(struct btd_adapter *adapter);
+void btd_adapter_gatt_server_stop(struct btd_adapter *adapter);
\ No newline at end of file
diff --git a/src/attrib-server.c b/src/attrib-server.c
index 0414ff7..12065fa 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -1210,13 +1210,13 @@ static gboolean register_core_services(struct gatt_adapter *gatt_adapter)
return TRUE;
}

-static int attrib_adapter_probe(struct btd_adapter *adapter)
+int btd_adapter_gatt_server_start(struct btd_adapter *adapter)
{
struct gatt_adapter *gatt_adapter;
GError *gerr = NULL;
bdaddr_t addr;

- DBG("Start GATT server in %s", adapter_get_path(adapter));
+ DBG("Start GATT server in hci%d", adapter_get_dev_id(adapter));

gatt_adapter = g_new0(struct gatt_adapter, 1);
gatt_adapter->adapter = btd_adapter_ref(adapter);
@@ -1262,7 +1262,7 @@ static int attrib_adapter_probe(struct btd_adapter *adapter)
return 0;
}

-static void attrib_adapter_remove(struct btd_adapter *adapter)
+void btd_adapter_gatt_server_stop(struct btd_adapter *adapter)
{
struct gatt_adapter *gatt_adapter;
GSList *l;
@@ -1271,29 +1271,13 @@ static void attrib_adapter_remove(struct btd_adapter *adapter)
if (l == NULL)
return;

- DBG("Stop GATT server in %s", adapter_get_path(adapter));
+ DBG("Stop GATT server in hci%d", adapter_get_dev_id(adapter));

gatt_adapter = l->data;
adapters = g_slist_remove(adapters, gatt_adapter);
free_gatt_adapter(gatt_adapter);
}

-static struct btd_adapter_driver attrib_adapter_driver = {
- .name = "attrib-adapter-driver",
- .probe = attrib_adapter_probe,
- .remove = attrib_adapter_remove,
-};
-
-int attrib_server_init(void)
-{
- return btd_register_adapter_driver(&attrib_adapter_driver);
-}
-
-void attrib_server_exit(void)
-{
- btd_unregister_adapter_driver(&attrib_adapter_driver);
-}
-
uint32_t attrib_create_sdp(uint16_t handle, const char *name)
{
struct gatt_adapter *gatt_adapter;
diff --git a/src/hcid.h b/src/hcid.h
index e993a16..1987b7d 100644
--- a/src/hcid.h
+++ b/src/hcid.h
@@ -63,6 +63,3 @@ void plugin_cleanup(void);

void rfkill_init(void);
void rfkill_exit(void);
-
-int attrib_server_init(void);
-void attrib_server_exit(void);
diff --git a/src/main.c b/src/main.c
index 3031f09..74ec3fa 100644
--- a/src/main.c
+++ b/src/main.c
@@ -521,11 +521,6 @@ int main(int argc, char *argv[])

start_sdp_server(mtu, main_opts.deviceid, SDP_SERVER_COMPAT);

- if (main_opts.attrib_server) {
- if (attrib_server_init() < 0)
- error("Can't initialize attribute server");
- }
-
/* Loading plugins has to be done after D-Bus has been setup since
* the plugins might wanna expose some paths on the bus. However the
* best order of how to init various subsystems of the Bluetooth
@@ -551,9 +546,6 @@ int main(int argc, char *argv[])

plugin_cleanup();

- if (main_opts.attrib_server)
- attrib_server_exit();
-
stop_sdp_server();

agent_exit();
--
1.7.8


2011-12-16 16:09:57

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 09/11] attrib-server: Mark attrib_channel_detach as deprecated

All public attrib-server functions are marked as deprecated until
they expose adapter facilities to operate with. This is a
transactional patch toward multiple adapter support is implemented.
All those functions use default adaptar in order to keep backward
compatibility.
---
src/attrib-server.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/src/attrib-server.c b/src/attrib-server.c
index 61bb05b..0414ff7 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -1433,6 +1433,8 @@ int attrib_gap_set(uint16_t uuid, const uint8_t *value, int len)
{
uint16_t handle;

+ DBG("Deprecated function!");
+
/* FIXME: Missing Privacy and Reconnection Address */

switch (uuid) {
--
1.7.8


2011-12-16 16:09:54

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 06/11] attrib-server: Remove global le_io variable

Get ride of the global low energy channel in order to use the low
energy channel managed in each adapter.
---
src/attrib-server.c | 9 ++++++---
1 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/src/attrib-server.c b/src/attrib-server.c
index 453bdd7..c7a9a67 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -71,8 +71,6 @@ struct group_elem {
uint16_t len;
};

-static GIOChannel *le_io = NULL;
-
struct gatt_adapter {
struct btd_adapter *adapter;
GIOChannel *l2cap_io;
@@ -861,6 +859,7 @@ static uint16_t write_value(struct gatt_channel *channel, uint16_t handle,
static uint16_t mtu_exchange(struct gatt_channel *channel, uint16_t mtu,
uint8_t *pdu, int len)
{
+ struct gatt_adapter *gatt_adapter;
guint old_mtu = channel->mtu;

if (mtu < ATT_DEFAULT_LE_MTU)
@@ -868,7 +867,11 @@ static uint16_t mtu_exchange(struct gatt_channel *channel, uint16_t mtu,
else
channel->mtu = MIN(mtu, channel->mtu);

- bt_io_set(le_io, BT_IO_L2CAP, NULL,
+ gatt_adapter = find_gatt_adapter(&channel->src);
+ if (gatt_adapter == NULL)
+ return 0;
+
+ bt_io_set(gatt_adapter->le_io, BT_IO_L2CAP, NULL,
BT_IO_OPT_OMTU, channel->mtu,
BT_IO_OPT_INVALID);

--
1.7.8


2011-12-16 16:09:55

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 07/11] attrib-server: Attah gatt channels to a adapters

This patch adds a new field to gatt channel structure to referentiate
the adapter which the channel belongs
---
src/attrib-server.c | 22 +++++++++++++---------
1 files changed, 13 insertions(+), 9 deletions(-)

diff --git a/src/attrib-server.c b/src/attrib-server.c
index c7a9a67..ad2dfd5 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -54,15 +54,6 @@

static GSList *database = NULL;

-struct gatt_channel {
- bdaddr_t src;
- bdaddr_t dst;
- GAttrib *attrib;
- guint mtu;
- gboolean le;
- guint id;
- gboolean encrypted;
-};

struct group_elem {
uint16_t handle;
@@ -81,6 +72,17 @@ struct gatt_adapter {
GSList *database;
};

+struct gatt_channel {
+ bdaddr_t src;
+ bdaddr_t dst;
+ GAttrib *attrib;
+ guint mtu;
+ gboolean le;
+ guint id;
+ gboolean encrypted;
+ struct gatt_adapter *gatt_adapter;
+};
+
static GSList *adapters = NULL;

/* GAP attribute handles */
@@ -1046,6 +1048,8 @@ guint attrib_channel_attach(GAttrib *attrib, gboolean out)
if (gatt_adapter == NULL)
return 0;

+ channel->gatt_adapter = gatt_adapter;
+
ba2str(&channel->dst, addr);
device = adapter_find_device(gatt_adapter->adapter, addr);

--
1.7.8


2011-12-16 16:09:56

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 08/11] attrib-server: Remove global database list

Each adapter use its own databa list to manage handlers so all
operations should managed in adapters instead of using a global
handler list.
---
src/attrib-server.c | 68 ++++++++++++++++++++++++++++++++++++---------------
1 files changed, 48 insertions(+), 20 deletions(-)

diff --git a/src/attrib-server.c b/src/attrib-server.c
index ad2dfd5..61bb05b 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -52,9 +52,6 @@

#include "attrib-server.h"

-static GSList *database = NULL;
-
-
struct group_elem {
uint16_t handle;
uint16_t end;
@@ -425,7 +422,7 @@ static uint16_t read_by_group(struct gatt_channel *channel, uint16_t start,
struct att_data_list *adl;
struct attribute *a;
struct group_elem *cur, *old = NULL;
- GSList *l, *groups;
+ GSList *l, *groups, *database;
uint16_t length, last_handle, last_size = 0;
uint8_t status;
int i;
@@ -444,6 +441,7 @@ static uint16_t read_by_group(struct gatt_channel *channel, uint16_t start,
return enc_error_resp(ATT_OP_READ_BY_GROUP_REQ, 0x0000,
ATT_ECODE_UNSUPP_GRP_TYPE, pdu, len);

+ database = channel->gatt_adapter->database;
last_handle = end;
for (l = database, groups = NULL, cur = NULL; l; l = l->next) {

@@ -536,7 +534,7 @@ static uint16_t read_by_type(struct gatt_channel *channel, uint16_t start,
uint8_t *pdu, int len)
{
struct att_data_list *adl;
- GSList *l, *types;
+ GSList *l, *types, *database;
struct attribute *a;
uint16_t num, length;
uint8_t status;
@@ -546,6 +544,7 @@ static uint16_t read_by_type(struct gatt_channel *channel, uint16_t start,
return enc_error_resp(ATT_OP_READ_BY_TYPE_REQ, start,
ATT_ECODE_INVALID_HANDLE, pdu, len);

+ database = channel->gatt_adapter->database;
for (l = database, length = 0, types = NULL; l; l = l->next) {

a = l->data;
@@ -612,11 +611,12 @@ static uint16_t read_by_type(struct gatt_channel *channel, uint16_t start,
return length;
}

-static int find_info(uint16_t start, uint16_t end, uint8_t *pdu, int len)
+static int find_info(struct gatt_channel *channel, uint16_t start, uint16_t end,
+ uint8_t *pdu, int len)
{
struct attribute *a;
struct att_data_list *adl;
- GSList *l, *info;
+ GSList *l, *info, *database;
uint8_t format, last_type = BT_UUID_UNSPEC;
uint16_t length, num;
int i;
@@ -625,6 +625,7 @@ static int find_info(uint16_t start, uint16_t end, uint8_t *pdu, int len)
return enc_error_resp(ATT_OP_FIND_INFO_REQ, start,
ATT_ECODE_INVALID_HANDLE, pdu, len);

+ database = channel->gatt_adapter->database;
for (l = database, info = NULL, num = 0; l; l = l->next) {
a = l->data;

@@ -684,12 +685,13 @@ static int find_info(uint16_t start, uint16_t end, uint8_t *pdu, int len)
return length;
}

-static int find_by_type(uint16_t start, uint16_t end, bt_uuid_t *uuid,
- const uint8_t *value, int vlen, uint8_t *opdu, int mtu)
+static int find_by_type(struct gatt_channel *channel, uint16_t start,
+ uint16_t end, bt_uuid_t *uuid, const uint8_t *value,
+ int vlen, uint8_t *opdu, int mtu)
{
struct attribute *a;
struct att_range *range;
- GSList *l, *matches;
+ GSList *l, *matches, *database;
int len;

if (start > end || start == 0x0000)
@@ -697,6 +699,7 @@ static int find_by_type(uint16_t start, uint16_t end, bt_uuid_t *uuid,
ATT_ECODE_INVALID_HANDLE, opdu, mtu);

/* Searching first requested handle number */
+ database = channel->gatt_adapter->database;
for (l = database, matches = NULL, range = NULL; l; l = l->next) {
a = l->data;

@@ -749,7 +752,8 @@ static uint16_t read_value(struct gatt_channel *channel, uint16_t handle,
uint16_t cccval;
guint h = handle;

- l = g_slist_find_custom(database, GUINT_TO_POINTER(h), handle_cmp);
+ l = g_slist_find_custom(channel->gatt_adapter->database,
+ GUINT_TO_POINTER(h), handle_cmp);
if (!l)
return enc_error_resp(ATT_OP_READ_REQ, handle,
ATT_ECODE_INVALID_HANDLE, pdu, len);
@@ -786,7 +790,8 @@ static uint16_t read_blob(struct gatt_channel *channel, uint16_t handle,
uint16_t cccval;
guint h = handle;

- l = g_slist_find_custom(database, GUINT_TO_POINTER(h), handle_cmp);
+ l = g_slist_find_custom(channel->gatt_adapter->database,
+ GUINT_TO_POINTER(h), handle_cmp);
if (!l)
return enc_error_resp(ATT_OP_READ_BLOB_REQ, handle,
ATT_ECODE_INVALID_HANDLE, pdu, len);
@@ -828,7 +833,8 @@ static uint16_t write_value(struct gatt_channel *channel, uint16_t handle,
GSList *l;
guint h = handle;

- l = g_slist_find_custom(database, GUINT_TO_POINTER(h), handle_cmp);
+ l = g_slist_find_custom(channel->gatt_adapter->database,
+ GUINT_TO_POINTER(h), handle_cmp);
if (!l)
return enc_error_resp(ATT_OP_WRITE_REQ, handle,
ATT_ECODE_INVALID_HANDLE, pdu, len);
@@ -965,7 +971,7 @@ static void channel_handler(const uint8_t *ipdu, uint16_t len,
goto done;
}

- length = find_info(start, end, opdu, channel->mtu);
+ length = find_info(channel, start, end, opdu, channel->mtu);
break;
case ATT_OP_WRITE_REQ:
length = dec_write_req(ipdu, len, &start, value, &vlen);
@@ -991,7 +997,7 @@ static void channel_handler(const uint8_t *ipdu, uint16_t len,
goto done;
}

- length = find_by_type(start, end, &uuid, value, vlen,
+ length = find_by_type(channel, start, end, &uuid, value, vlen,
opdu, channel->mtu);
break;
case ATT_OP_HANDLE_CNF:
@@ -1286,7 +1292,6 @@ int attrib_server_init(void)
void attrib_server_exit(void)
{
btd_unregister_adapter_driver(&attrib_adapter_driver);
- g_slist_free_full(database, attrib_free);
}

uint32_t attrib_create_sdp(uint16_t handle, const char *name)
@@ -1309,12 +1314,19 @@ void attrib_free_sdp(uint32_t sdp_handle)

uint16_t attrib_db_find_avail(uint16_t nitems)
{
+ struct gatt_adapter *gatt_adapter;
uint16_t handle;
GSList *l;

+ DBG("Deprecated function");
+
g_assert(nitems > 0);

- for (l = database, handle = 0; l; l = l->next) {
+ gatt_adapter = get_default_gatt_adapter();
+ if (gatt_adapter == NULL)
+ return 0;
+
+ for (l = gatt_adapter->database, handle = 0; l; l = l->next) {
struct attribute *a = l->data;

if (handle && (bt_uuid_cmp(&a->uuid, &prim_uuid) == 0 ||
@@ -1353,13 +1365,21 @@ struct attribute *attrib_db_add(uint16_t handle, bt_uuid_t *uuid, int read_reqs,
int attrib_db_update(uint16_t handle, bt_uuid_t *uuid, const uint8_t *value,
int len, struct attribute **attr)
{
+ struct gatt_adapter *gatt_adapter;
struct attribute *a;
GSList *l;
guint h = handle;

+ DBG("Deprecated function!");
+
DBG("handle=0x%04x", handle);

- l = g_slist_find_custom(database, GUINT_TO_POINTER(h), handle_cmp);
+ gatt_adapter = get_default_gatt_adapter();
+ if (gatt_adapter == NULL)
+ return -ENOENT;
+
+ l = g_slist_find_custom(gatt_adapter->database, GUINT_TO_POINTER(h),
+ handle_cmp);
if (!l)
return -ENOENT;

@@ -1383,18 +1403,26 @@ int attrib_db_update(uint16_t handle, bt_uuid_t *uuid, const uint8_t *value,

int attrib_db_del(uint16_t handle)
{
+ struct gatt_adapter *gatt_adapter;
struct attribute *a;
GSList *l;
guint h = handle;

+ DBG("Deprecated function!");
+
DBG("handle=0x%04x", handle);

- l = g_slist_find_custom(database, GUINT_TO_POINTER(h), handle_cmp);
+ gatt_adapter = get_default_gatt_adapter();
+ if (gatt_adapter == NULL)
+ return -ENOENT;
+
+ l = g_slist_find_custom(gatt_adapter->database, GUINT_TO_POINTER(h),
+ handle_cmp);
if (!l)
return -ENOENT;

a = l->data;
- database = g_slist_remove(database, a);
+ gatt_adapter->database = g_slist_remove(gatt_adapter->database, a);
g_free(a->data);
g_free(a);

--
1.7.8


2011-12-16 16:09:53

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 05/11] attrib-server: Remove global client list

---
src/attrib-server.c | 12 +++++++++---
1 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/src/attrib-server.c b/src/attrib-server.c
index 751091e..453bdd7 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -72,7 +72,6 @@ struct group_elem {
};

static GIOChannel *le_io = NULL;
-static GSList *clients = NULL;

struct gatt_adapter {
struct btd_adapter *adapter;
@@ -1082,11 +1081,18 @@ static gint channel_id_cmp(gconstpointer data, gconstpointer user_data)

gboolean attrib_channel_detach(guint id)
{
+ struct gatt_adapter *gatt_adapter;
struct gatt_channel *channel;
GSList *l;

- l = g_slist_find_custom(clients, GUINT_TO_POINTER(id),
- channel_id_cmp);
+ DBG("Deprecated function");
+
+ gatt_adapter = get_default_gatt_adapter();
+ if (gatt_adapter == NULL)
+ return FALSE;
+
+ l = g_slist_find_custom(gatt_adapter->clients, GUINT_TO_POINTER(id),
+ channel_id_cmp);
if (!l)
return FALSE;

--
1.7.8


2011-12-16 16:09:52

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 04/11] attrib-server: Attach attrib_channel in adapter clients list

This patch attaches attribute channels to the adapter list instead
of using the global client list.
---
src/attrib-server.c | 44 +++++++++++++++++++++++++++++++++++++++-----
1 files changed, 39 insertions(+), 5 deletions(-)

diff --git a/src/attrib-server.c b/src/attrib-server.c
index b2f0edb..751091e 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -146,6 +146,17 @@ static void free_gatt_adapter(struct gatt_adapter *gatt_adapter)
g_free(gatt_adapter);
}

+static gint adapter_cmp_addr(gconstpointer a, gconstpointer b)
+{
+ const struct gatt_adapter *gatt_adapter = a;
+ const bdaddr_t *bdaddr = b;
+ bdaddr_t src;
+
+ adapter_get_address(gatt_adapter->adapter, &src);
+
+ return bacmp(&src, bdaddr);
+}
+
static gint adapter_cmp(gconstpointer a, gconstpointer b)
{
const struct gatt_adapter *gatt_adapter = a;
@@ -157,6 +168,22 @@ static gint adapter_cmp(gconstpointer a, gconstpointer b)
return -1;
}

+static struct gatt_adapter *find_gatt_adapter(const bdaddr_t *bdaddr)
+{
+ GSList *l;
+
+ l = g_slist_find_custom(adapters, bdaddr, adapter_cmp_addr);
+ if (l == NULL) {
+ char addr[18];
+
+ ba2str(bdaddr, addr);
+ error("Not GATT adapter found for address %s", addr);
+ return NULL;
+ }
+
+ return l->data;
+}
+
static struct gatt_adapter *get_default_gatt_adapter(void)
{
struct gatt_adapter *gatt_adapter;
@@ -852,8 +879,13 @@ static uint16_t mtu_exchange(struct gatt_channel *channel, uint16_t mtu,
static void channel_disconnect(void *user_data)
{
struct gatt_channel *channel = user_data;
+ struct gatt_adapter *gatt_adapter;
+
+ gatt_adapter = find_gatt_adapter(&channel->src);
+ if (gatt_adapter == NULL)
+ return;

- clients = g_slist_remove(clients, channel);
+ gatt_adapter->clients = g_slist_remove(gatt_adapter->clients, channel);
channel_free(channel);
}

@@ -983,7 +1015,7 @@ done:

guint attrib_channel_attach(GAttrib *attrib, gboolean out)
{
- struct btd_adapter *adapter;
+ struct gatt_adapter *gatt_adapter;
struct btd_device *device;
struct gatt_channel *channel;
GIOChannel *io;
@@ -1008,10 +1040,12 @@ guint attrib_channel_attach(GAttrib *attrib, gboolean out)
return 0;
}

- adapter = manager_find_adapter(&channel->src);
+ gatt_adapter = find_gatt_adapter(&channel->src);
+ if (gatt_adapter == NULL)
+ return 0;

ba2str(&channel->dst, addr);
- device = adapter_find_device(adapter, addr);
+ device = adapter_find_device(gatt_adapter->adapter, addr);

if (device_is_bonded(device) == FALSE)
delete_device_ccc(&channel->src, &channel->dst);
@@ -1033,7 +1067,7 @@ guint attrib_channel_attach(GAttrib *attrib, gboolean out)
g_attrib_set_disconnect_function(channel->attrib,
channel_disconnect, channel);

- clients = g_slist_append(clients, channel);
+ gatt_adapter->clients = g_slist_append(gatt_adapter->clients, channel);

return channel->id;
}
--
1.7.8


2011-12-16 16:09:51

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 03/11] attrib-server: Add attributes in adapter database

Each adapter has its own database so the global database list
will be removed. This patch makes a wrapper over attrib_db_add
function to get the default adapter in order to add attributes
in the default adapter, int his way we keep backward compatibility
with the gatt server interface until the api is updated.
---
src/attrib-server.c | 68 +++++++++++++++++++++++++++++++++-----------------
1 files changed, 45 insertions(+), 23 deletions(-)

diff --git a/src/attrib-server.c b/src/attrib-server.c
index 5a5024c..b2f0edb 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -331,6 +331,33 @@ static uint32_t attrib_create_sdp_new(struct gatt_adapter *gatt_adapter,
return 0;
}

+static struct attribute *attrib_db_add_new(struct gatt_adapter *gatt_adapter,
+ uint16_t handle, bt_uuid_t *uuid, int read_reqs,
+ int write_reqs, const uint8_t *value, int len)
+{
+ struct attribute *a;
+ guint h = handle;
+
+ DBG("handle=0x%04x", handle);
+
+ if (g_slist_find_custom(gatt_adapter->database, GUINT_TO_POINTER(h),
+ handle_cmp))
+ return NULL;
+
+ a = g_new0(struct attribute, 1);
+ a->len = len;
+ a->data = g_memdup(value, len);
+ a->handle = handle;
+ a->uuid = *uuid;
+ a->read_reqs = read_reqs;
+ a->write_reqs = write_reqs;
+
+ gatt_adapter->database = g_slist_insert_sorted(gatt_adapter->database,
+ a, attribute_cmp);
+
+ return a;
+}
+
static uint8_t att_check_reqs(struct gatt_channel *channel, uint8_t opcode,
int reqs)
{
@@ -1075,7 +1102,8 @@ static gboolean register_core_services(struct gatt_adapter *gatt_adapter)
/* GAP service: primary service definition */
bt_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
att_put_u16(GENERIC_ACCESS_PROFILE_ID, &atval[0]);
- attrib_db_add(0x0001, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 2);
+ attrib_db_add_new(gatt_adapter, 0x0001, &uuid, ATT_NONE,
+ ATT_NOT_PERMITTED, atval, 2);

/* GAP service: device name characteristic */
name_handle = 0x0006;
@@ -1083,12 +1111,13 @@ static gboolean register_core_services(struct gatt_adapter *gatt_adapter)
atval[0] = ATT_CHAR_PROPER_READ;
att_put_u16(name_handle, &atval[1]);
att_put_u16(GATT_CHARAC_DEVICE_NAME, &atval[3]);
- attrib_db_add(0x0004, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 5);
+ attrib_db_add_new(gatt_adapter, 0x0004, &uuid, ATT_NONE,
+ ATT_NOT_PERMITTED, atval, 5);

/* GAP service: device name attribute */
bt_uuid16_create(&uuid, GATT_CHARAC_DEVICE_NAME);
- attrib_db_add(name_handle, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
- NULL, 0);
+ attrib_db_add_new(gatt_adapter, name_handle, &uuid, ATT_NONE,
+ ATT_NOT_PERMITTED, NULL, 0);

/* GAP service: device appearance characteristic */
appearance_handle = 0x0008;
@@ -1096,13 +1125,14 @@ static gboolean register_core_services(struct gatt_adapter *gatt_adapter)
atval[0] = ATT_CHAR_PROPER_READ;
att_put_u16(appearance_handle, &atval[1]);
att_put_u16(GATT_CHARAC_APPEARANCE, &atval[3]);
- attrib_db_add(0x0007, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 5);
+ attrib_db_add_new(gatt_adapter, 0x0007, &uuid, ATT_NONE,
+ ATT_NOT_PERMITTED, atval, 5);

/* GAP service: device appearance attribute */
bt_uuid16_create(&uuid, GATT_CHARAC_APPEARANCE);
att_put_u16(appearance, &atval[0]);
- attrib_db_add(appearance_handle, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
- atval, 2);
+ attrib_db_add_new(gatt_adapter, appearance_handle, &uuid, ATT_NONE,
+ ATT_NOT_PERMITTED, atval, 2);

gatt_adapter->gap_sdp_handle = attrib_create_sdp_new(gatt_adapter,
0x0001, "Generic Access Profile");
@@ -1114,7 +1144,8 @@ static gboolean register_core_services(struct gatt_adapter *gatt_adapter)
/* GATT service: primary service definition */
bt_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
att_put_u16(GENERIC_ATTRIB_PROFILE_ID, &atval[0]);
- attrib_db_add(0x0010, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 2);
+ attrib_db_add_new(gatt_adapter, 0x0010, &uuid, ATT_NONE,
+ ATT_NOT_PERMITTED, atval, 2);

gatt_adapter->gatt_sdp_handle = attrib_create_sdp_new(gatt_adapter,
0x0010, "Generic Attribute Profile");
@@ -1260,25 +1291,16 @@ uint16_t attrib_db_find_avail(uint16_t nitems)
struct attribute *attrib_db_add(uint16_t handle, bt_uuid_t *uuid, int read_reqs,
int write_reqs, const uint8_t *value, int len)
{
- struct attribute *a;
- guint h = handle;
+ struct gatt_adapter *gatt_adapter;

- DBG("handle=0x%04x", handle);
+ DBG("Deprecated function!");

- if (g_slist_find_custom(database, GUINT_TO_POINTER(h), handle_cmp))
+ gatt_adapter = get_default_gatt_adapter();
+ if (gatt_adapter == NULL)
return NULL;

- a = g_new0(struct attribute, 1);
- a->len = len;
- a->data = g_memdup(value, len);
- a->handle = handle;
- a->uuid = *uuid;
- a->read_reqs = read_reqs;
- a->write_reqs = write_reqs;
-
- database = g_slist_insert_sorted(database, a, attribute_cmp);
-
- return a;
+ return attrib_db_add_new(gatt_adapter, handle, uuid, read_reqs, write_reqs,
+ value, len);
}

int attrib_db_update(uint16_t handle, bt_uuid_t *uuid, const uint8_t *value,
--
1.7.8


2011-12-16 16:09:50

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 02/11] attrib-server: Register GATT SDP record per each adapter

Each adapter has its own SDP registry wich will be managed
separately. This patch makes a wrapper over attrib_create_sdp
function using the default adapter in order to keep backward
compatibility with the gatt server interface until the api is
finally updated.
---
src/attrib-server.c | 203 ++++++++++++++++++++++++++++++---------------------
1 files changed, 120 insertions(+), 83 deletions(-)

diff --git a/src/attrib-server.c b/src/attrib-server.c
index e8dade8..5a5024c 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -73,8 +73,6 @@ struct group_elem {

static GIOChannel *le_io = NULL;
static GSList *clients = NULL;
-static uint32_t gatt_sdp_handle = 0;
-static uint32_t gap_sdp_handle = 0;

struct gatt_adapter {
struct btd_adapter *adapter;
@@ -159,6 +157,30 @@ static gint adapter_cmp(gconstpointer a, gconstpointer b)
return -1;
}

+static struct gatt_adapter *get_default_gatt_adapter(void)
+{
+ struct gatt_adapter *gatt_adapter;
+ struct btd_adapter *adapter;
+ GSList *l;
+
+ adapter = manager_get_default_adapter();
+ if (adapter == NULL) {
+ error("Can't get default adapter");
+ return NULL;
+ }
+
+ l = g_slist_find_custom(adapters, adapter, adapter_cmp);
+ if (l == NULL) {
+ error("Not GATT server initialized on adapter %s",
+ adapter_get_path(adapter));
+ return NULL;
+ }
+
+ gatt_adapter = l->data;
+
+ return gatt_adapter;
+}
+
static sdp_record_t *server_record_new(uuid_t *uuid, uint16_t start, uint16_t end)
{
sdp_list_t *svclass_id, *apseq, *proto[2], *root, *aproto;
@@ -230,6 +252,85 @@ static int attribute_cmp(gconstpointer a1, gconstpointer a2)
return attrib1->handle - attrib2->handle;
}

+static struct attribute *find_primary_range(struct gatt_adapter *gatt_adapter,
+ uint16_t start, uint16_t *end)
+{
+ struct attribute *attrib;
+ guint h = start;
+ GSList *l;
+
+ if (end == NULL)
+ return NULL;
+
+ l = g_slist_find_custom(gatt_adapter->database, GUINT_TO_POINTER(h),
+ handle_cmp);
+ if (!l)
+ return NULL;
+
+ attrib = l->data;
+
+ if (bt_uuid_cmp(&attrib->uuid, &prim_uuid) != 0)
+ return NULL;
+
+ *end = start;
+
+ for (l = l->next; l; l = l->next) {
+ struct attribute *a = l->data;
+
+ if (bt_uuid_cmp(&a->uuid, &prim_uuid) == 0 ||
+ bt_uuid_cmp(&a->uuid, &snd_uuid) == 0)
+ break;
+
+ *end = a->handle;
+ }
+
+ return attrib;
+}
+
+static uint32_t attrib_create_sdp_new(struct gatt_adapter *gatt_adapter,
+ uint16_t handle, const char *name)
+{
+ sdp_record_t *record;
+ struct attribute *a;
+ uint16_t end = 0;
+ uuid_t svc, gap_uuid;
+ bdaddr_t addr;
+
+ a = find_primary_range(gatt_adapter, handle, &end);
+
+ if (a == NULL)
+ return 0;
+
+ if (a->len == 2)
+ sdp_uuid16_create(&svc, att_get_u16(a->data));
+ else if (a->len == 16)
+ sdp_uuid128_create(&svc, a->data);
+ else
+ return 0;
+
+ record = server_record_new(&svc, handle, end);
+ if (record == NULL)
+ return 0;
+
+ if (name)
+ sdp_set_info_attr(record, name, "BlueZ", NULL);
+
+ sdp_uuid16_create(&gap_uuid, GENERIC_ACCESS_PROFILE_ID);
+ if (sdp_uuid_cmp(&svc, &gap_uuid) == 0) {
+ sdp_set_url_attr(record, "http://www.bluez.org/",
+ "http://www.bluez.org/",
+ "http://www.bluez.org/");
+ }
+
+ adapter_get_address(gatt_adapter->adapter, &addr);
+ if (add_record_to_server(&addr, record) < 0)
+ sdp_record_free(record);
+ else
+ return record->handle;
+
+ return 0;
+}
+
static uint8_t att_check_reqs(struct gatt_channel *channel, uint8_t opcode,
int reqs)
{
@@ -586,39 +687,6 @@ static int find_by_type(uint16_t start, uint16_t end, bt_uuid_t *uuid,
return len;
}

-static struct attribute *find_primary_range(uint16_t start, uint16_t *end)
-{
- struct attribute *attrib;
- guint h = start;
- GSList *l;
-
- if (end == NULL)
- return NULL;
-
- l = g_slist_find_custom(database, GUINT_TO_POINTER(h), handle_cmp);
- if (!l)
- return NULL;
-
- attrib = l->data;
-
- if (bt_uuid_cmp(&attrib->uuid, &prim_uuid) != 0)
- return NULL;
-
- *end = start;
-
- for (l = l->next; l; l = l->next) {
- struct attribute *a = l->data;
-
- if (bt_uuid_cmp(&a->uuid, &prim_uuid) == 0 ||
- bt_uuid_cmp(&a->uuid, &snd_uuid) == 0)
- break;
-
- *end = a->handle;
- }
-
- return attrib;
-}
-
static uint16_t read_value(struct gatt_channel *channel, uint16_t handle,
uint8_t *pdu, int len)
{
@@ -998,7 +1066,7 @@ static void confirm_event(GIOChannel *io, void *user_data)
return;
}

-static gboolean register_core_services(void)
+static gboolean register_core_services(struct gatt_adapter *gatt_adapter)
{
uint8_t atval[256];
bt_uuid_t uuid;
@@ -1035,10 +1103,12 @@ static gboolean register_core_services(void)
att_put_u16(appearance, &atval[0]);
attrib_db_add(appearance_handle, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
atval, 2);
- gap_sdp_handle = attrib_create_sdp(0x0001, "Generic Access Profile");
- if (gap_sdp_handle == 0) {
+
+ gatt_adapter->gap_sdp_handle = attrib_create_sdp_new(gatt_adapter,
+ 0x0001, "Generic Access Profile");
+ if (gatt_adapter->gap_sdp_handle == 0) {
error("Failed to register GAP service record");
- goto failed;
+ return FALSE;
}

/* GATT service: primary service definition */
@@ -1046,20 +1116,14 @@ static gboolean register_core_services(void)
att_put_u16(GENERIC_ATTRIB_PROFILE_ID, &atval[0]);
attrib_db_add(0x0010, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 2);

- gatt_sdp_handle = attrib_create_sdp(0x0010,
- "Generic Attribute Profile");
- if (gatt_sdp_handle == 0) {
+ gatt_adapter->gatt_sdp_handle = attrib_create_sdp_new(gatt_adapter,
+ 0x0010, "Generic Attribute Profile");
+ if (gatt_adapter->gatt_sdp_handle == 0) {
error("Failed to register GATT service record");
- goto failed;
+ return FALSE;;
}

return TRUE;
-
-failed:
- if (gap_sdp_handle)
- remove_record_from_server(gap_sdp_handle);
-
- return FALSE;
}

static int attrib_adapter_probe(struct btd_adapter *adapter)
@@ -1090,7 +1154,7 @@ static int attrib_adapter_probe(struct btd_adapter *adapter)
return -1;
}

- if (!register_core_services()) {
+ if (!register_core_services(gatt_adapter)) {
g_io_channel_unref(gatt_adapter->l2cap_io);
free_gatt_adapter(gatt_adapter);
return -1;
@@ -1144,47 +1208,20 @@ int attrib_server_init(void)
void attrib_server_exit(void)
{
btd_unregister_adapter_driver(&attrib_adapter_driver);
+ g_slist_free_full(database, attrib_free);
}

uint32_t attrib_create_sdp(uint16_t handle, const char *name)
{
- sdp_record_t *record;
- struct attribute *a;
- uint16_t end = 0;
- uuid_t svc, gap_uuid;
-
- a = find_primary_range(handle, &end);
-
- if (a == NULL)
- return 0;
+ struct gatt_adapter *gatt_adapter;

- if (a->len == 2)
- sdp_uuid16_create(&svc, att_get_u16(a->data));
- else if (a->len == 16)
- sdp_uuid128_create(&svc, a->data);
- else
- return 0;
+ DBG("Deprecated function");

- record = server_record_new(&svc, handle, end);
- if (record == NULL)
+ gatt_adapter = get_default_gatt_adapter();
+ if (gatt_adapter == NULL)
return 0;

- if (name)
- sdp_set_info_attr(record, name, "BlueZ", NULL);
-
- sdp_uuid16_create(&gap_uuid, GENERIC_ACCESS_PROFILE_ID);
- if (sdp_uuid_cmp(&svc, &gap_uuid) == 0) {
- sdp_set_url_attr(record, "http://www.bluez.org/",
- "http://www.bluez.org/",
- "http://www.bluez.org/");
- }
-
- if (add_record_to_server(BDADDR_ANY, record) < 0)
- sdp_record_free(record);
- else
- return record->handle;
-
- return 0;
+ return attrib_create_sdp_new(gatt_adapter, handle, name);
}

void attrib_free_sdp(uint32_t sdp_handle)
--
1.7.8


2011-12-16 16:09:49

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 01/11] attrib-server: Initial steps to provide multi-adapter GATT server support

This patch prepares the structures in att-server to start and stop
GATT server whenever an adapter is plugged or unplugged.
---
src/attrib-server.c | 168 +++++++++++++++++++++++++++++++++++----------------
1 files changed, 116 insertions(+), 52 deletions(-)

diff --git a/src/attrib-server.c b/src/attrib-server.c
index b767b72..e8dade8 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -71,12 +71,23 @@ struct group_elem {
uint16_t len;
};

-static GIOChannel *l2cap_io = NULL;
static GIOChannel *le_io = NULL;
static GSList *clients = NULL;
static uint32_t gatt_sdp_handle = 0;
static uint32_t gap_sdp_handle = 0;

+struct gatt_adapter {
+ struct btd_adapter *adapter;
+ GIOChannel *l2cap_io;
+ GIOChannel *le_io;
+ GSList *clients;
+ uint32_t gatt_sdp_handle;
+ uint32_t gap_sdp_handle;
+ GSList *database;
+};
+
+static GSList *adapters = NULL;
+
/* GAP attribute handles */
static uint16_t name_handle = 0x0000;
static uint16_t appearance_handle = 0x0000;
@@ -94,6 +105,60 @@ static bt_uuid_t ccc_uuid = {
.value.u16 = GATT_CLIENT_CHARAC_CFG_UUID
};

+static void attrib_free(void *data)
+{
+ struct attribute *a = data;
+
+ g_free(a->data);
+ g_free(a);
+}
+
+static void channel_free(struct gatt_channel *channel)
+{
+ g_attrib_unref(channel->attrib);
+
+ g_free(channel);
+}
+
+static void free_gatt_adapter(struct gatt_adapter *gatt_adapter)
+{
+ g_slist_free_full(gatt_adapter->database, attrib_free);
+
+ if (gatt_adapter->l2cap_io != NULL) {
+ g_io_channel_unref(gatt_adapter->l2cap_io);
+ g_io_channel_shutdown(gatt_adapter->l2cap_io, FALSE, NULL);
+ }
+
+ if (gatt_adapter->le_io != NULL) {
+ g_io_channel_unref(gatt_adapter->le_io);
+ g_io_channel_shutdown(gatt_adapter->le_io, FALSE, NULL);
+ }
+
+ g_slist_free_full(gatt_adapter->clients, (GDestroyNotify) channel_free);
+
+ if (gatt_adapter->gatt_sdp_handle > 0)
+ remove_record_from_server(gatt_adapter->gatt_sdp_handle);
+
+ if (gatt_adapter->gap_sdp_handle > 0)
+ remove_record_from_server(gatt_adapter->gap_sdp_handle);
+
+ if (gatt_adapter->adapter != NULL)
+ btd_adapter_unref(gatt_adapter->adapter);
+
+ g_free(gatt_adapter);
+}
+
+static gint adapter_cmp(gconstpointer a, gconstpointer b)
+{
+ const struct gatt_adapter *gatt_adapter = a;
+ const struct btd_adapter *adapter = b;
+
+ if (gatt_adapter->adapter == adapter)
+ return 0;
+
+ return -1;
+}
+
static sdp_record_t *server_record_new(uuid_t *uuid, uint16_t start, uint16_t end)
{
sdp_list_t *svclass_id, *apseq, *proto[2], *root, *aproto;
@@ -689,21 +754,6 @@ static uint16_t mtu_exchange(struct gatt_channel *channel, uint16_t mtu,
return enc_mtu_resp(old_mtu, pdu, len);
}

-static void attrib_free(void *data)
-{
- struct attribute *a = data;
-
- g_free(a->data);
- g_free(a);
-}
-
-static void channel_free(struct gatt_channel *channel)
-{
- g_attrib_unref(channel->attrib);
-
- g_free(channel);
-}
-
static void channel_disconnect(void *user_data)
{
struct gatt_channel *channel = user_data;
@@ -1012,74 +1062,88 @@ failed:
return FALSE;
}

-int attrib_server_init(void)
+static int attrib_adapter_probe(struct btd_adapter *adapter)
{
+ struct gatt_adapter *gatt_adapter;
GError *gerr = NULL;
+ bdaddr_t addr;
+
+ DBG("Start GATT server in %s", adapter_get_path(adapter));
+
+ gatt_adapter = g_new0(struct gatt_adapter, 1);
+ gatt_adapter->adapter = btd_adapter_ref(adapter);
+
+ adapter_get_address(gatt_adapter->adapter, &addr);

/* BR/EDR socket */
- l2cap_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event,
+ gatt_adapter->l2cap_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event,
NULL, NULL, &gerr,
- BT_IO_OPT_SOURCE_BDADDR, BDADDR_ANY,
+ BT_IO_OPT_SOURCE_BDADDR, &addr,
BT_IO_OPT_PSM, ATT_PSM,
BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
BT_IO_OPT_INVALID);
- if (l2cap_io == NULL) {
+
+ if (gatt_adapter->l2cap_io == NULL) {
error("%s", gerr->message);
g_error_free(gerr);
+ free_gatt_adapter(gatt_adapter);
return -1;
}

- if (!register_core_services())
- goto failed;
+ if (!register_core_services()) {
+ g_io_channel_unref(gatt_adapter->l2cap_io);
+ free_gatt_adapter(gatt_adapter);
+ return -1;
+ }

/* LE socket */
- le_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event,
- &le_io, NULL, &gerr,
- BT_IO_OPT_SOURCE_BDADDR, BDADDR_ANY,
+ gatt_adapter->le_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event,
+ &gatt_adapter->le_io, NULL, &gerr,
+ BT_IO_OPT_SOURCE_BDADDR, &addr,
BT_IO_OPT_CID, ATT_CID,
BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
BT_IO_OPT_INVALID);
- if (le_io == NULL) {
+
+ if (gatt_adapter->le_io == NULL) {
error("%s", gerr->message);
g_error_free(gerr);
/* Doesn't have LE support, continue */
}

+ adapters = g_slist_prepend(adapters, gatt_adapter);
return 0;
-
-failed:
- g_io_channel_unref(l2cap_io);
- l2cap_io = NULL;
-
- if (le_io) {
- g_io_channel_unref(le_io);
- le_io = NULL;
- }
-
- return -1;
}

-void attrib_server_exit(void)
+static void attrib_adapter_remove(struct btd_adapter *adapter)
{
- g_slist_free_full(database, attrib_free);
+ struct gatt_adapter *gatt_adapter;
+ GSList *l;

- if (l2cap_io) {
- g_io_channel_unref(l2cap_io);
- g_io_channel_shutdown(l2cap_io, FALSE, NULL);
- }
+ l = g_slist_find_custom(adapters, adapter, adapter_cmp);
+ if (l == NULL)
+ return;

- if (le_io) {
- g_io_channel_unref(le_io);
- g_io_channel_shutdown(le_io, FALSE, NULL);
- }
+ DBG("Stop GATT server in %s", adapter_get_path(adapter));

- g_slist_free_full(clients, (GDestroyNotify) channel_free);
+ gatt_adapter = l->data;
+ adapters = g_slist_remove(adapters, gatt_adapter);
+ free_gatt_adapter(gatt_adapter);
+}

- if (gatt_sdp_handle)
- remove_record_from_server(gatt_sdp_handle);
+static struct btd_adapter_driver attrib_adapter_driver = {
+ .name = "attrib-adapter-driver",
+ .probe = attrib_adapter_probe,
+ .remove = attrib_adapter_remove,
+};

- if (gap_sdp_handle)
- remove_record_from_server(gap_sdp_handle);
+int attrib_server_init(void)
+{
+ return btd_register_adapter_driver(&attrib_adapter_driver);
+}
+
+void attrib_server_exit(void)
+{
+ btd_unregister_adapter_driver(&attrib_adapter_driver);
}

uint32_t attrib_create_sdp(uint16_t handle, const char *name)
--
1.7.8