2013-05-02 20:15:35

by Vinicius Costa Gomes

[permalink] [raw]
Subject: GATT Clients and Servers in the kernel (was Re:[PATCH BlueZ v3 06/16] attrib...)

Hi Marcel,

[ moving to a new thread ]

On Thu, May 2, 2013 at 1:05 PM, Marcel Holtmann <[email protected]> wrote=
:
> Hi Johan,
>
>>> -gboolean g_attrib_set_destroy_function(GAttrib *attrib,
>>> - GDestroyNotify destroy, gpointer user_data)
>>> +bool g_attrib_set_destroy_function(GAttrib *attrib, GDestroyNotify des=
troy,
>>> + gpointer user_data=
)
>>
>> I've applied patches 1-5 but stopped there since I'm still not sure that
>> we want to change this for an API which tries to follow GLib conventions
>> (after all that's why the GAttrib API has G and g_ prefixes). Marcel, do
>> you have any opinion about this one way or another?
>
> the long term plan is to use standard types like bool, char, uint8_t and =
also void * here. However we might want to also see how to get rid of g_ pr=
efix as well. Especially g_attrib seems to be a good candidate to get rid o=
f.
>
> I also like to see ATT and GATT being implemented as src/shared/ under LG=
PL so we can be easily share it in the future. I already have some (unpubli=
shed) code for src/shared/att.[ch] and src/shared/gatt.[ch] already, but I =
think what we first need to do is to figure out how we handle clients and s=
ervers from the kernel side. Especially with the background of the kernel a=
uto-connecting LE channels in the future.

I am assuming you were talking about the connection establishment. If
not, I am not following.

I can only think of an evolutionary approach of what we are already doing:

- when we are the initiating side, the kernel will only auto-connect
devices that have an associated socket blocking on connect(); the
kernel may even use the white list if it seems appropriate (no
resolvable addresses in the list of "to be connected" sockets for
example).

- accepting side, we only send connectable advertising events when
there's a listen() active, it would be nice to have a way to only
appear connectable to a set of devices, i.e. use the white list in
this case.


>
> Regards
>
> Marcel
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth=
" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html


Cheers,
--
Vinicius


2013-05-21 19:25:24

by Marcel Holtmann

[permalink] [raw]
Subject: Re: GATT Clients and Servers in the kernel (was Re:[PATCH BlueZ v3 06/16] attrib...)

Hi Andre,

> Last week we did some brainstorming about the two LE connection
> approaches. So far, the only drawback we see in this accept() approach
> is that it requires at least three new mgmt LE-specific commands to
> add, remove and clear the set of devices we want to connect to. IIRC,
> we don't want commands LE-specific in Management Interface.

I am not worried about the mgmt commands actually. My main point is that after a reboot they need to be reloaded into the kernel. So something else is needed here as well. And I do not want to hold file descriptors for devices that say are know, but only connect once per week.

What I want is that we tell the kernel what device we know about and what we expect to connect automatically once in range. So that we can program the controller properly. And to that effect not have this controller via L2CAP layer connect(). Since that layer has nothing to do with it actually.

This mgmt commands does not have to LE specific, but are most likely LE specific. I have not a big problem with this. We already have the LE long term key loading command that LE specific already. Maybe there are some common features between LE and BR/EDR possible. For example we have been talking about remote wakeup in the past. That can fit on BR/EDR and LE.

> Also, during discussion, some questions were raised and we'd like to
> share with the ML:
>
> * What happens with connect()? What should it implement?

Actually connect() will stay relevant, but I can not go into specifics here for unreleased specifications.

> * How this approach integrates with peripheral role and advertising support?

The GATT part is no different. Both roles will support client + server at the same time. They have to. With GATT over LE you only have one CID and both peers will provide a server and both peer can be a client within the same GATT transaction model.

The difference between peripheral and central is just up to bluetoothd and what kind of services are exposed for that specific LE connection. Right now, we might just disable central handling when peripheral mode is requested. However in the future I can see us running central and peripheral at the same time. We might have to tell the socket on accept() what kind of role the connecting LE device is.

Regards

Marcel


2013-05-21 19:05:10

by Andre Guedes

[permalink] [raw]
Subject: Re: GATT Clients and Servers in the kernel (was Re:[PATCH BlueZ v3 06/16] attrib...)

Hi all,

Last week we did some brainstorming about the two LE connection
approaches. So far, the only drawback we see in this accept() approach
is that it requires at least three new mgmt LE-specific commands to
add, remove and clear the set of devices we want to connect to. IIRC,
we don't want commands LE-specific in Management Interface.

Also, during discussion, some questions were raised and we'd like to
share with the ML:

* What happens with connect()? What should it implement?

* How this approach integrates with peripheral role and advertising support=
?

BR,

Andre

On Fri, May 3, 2013 at 12:17 PM, Marcel Holtmann <[email protected]> wrot=
e:
> Hi Andre,
>
>>>>>> the long term plan is to use standard types like bool, char, uint8_t
>>>>>> and also void * here. However we might want to also see how to get
>>>>>> rid of g_ prefix as well. Especially g_attrib seems to be a good
>>>>>> candidate to get rid of.
>>>>>>
>>>>>> I also like to see ATT and GATT being implemented as src/shared/
>>>>>> under LGPL so we can be easily share it in the future. I already
>>>>>> have some (unpublished) code for src/shared/att.[ch] and
>>>>>> src/shared/gatt.[ch] already, but I think what we first need to do
>>>>>> is to figure out how we handle clients and servers from the kernel
>>>>>> side. Especially with the background of the kernel auto-connecting
>>>>>> LE channels in the future.
>>>>>
>>>>> I am assuming you were talking about the connection establishment. If
>>>>> not, I am not following.
>>>>>
>>>>> I can only think of an evolutionary approach of what we are already
>>>>> doing:
>>>>>
>>>>> - when we are the initiating side, the kernel will only auto-connect
>>>>> devices that have an associated socket blocking on connect(); the
>>>>> kernel may even use the white list if it seems appropriate (no
>>>>> resolvable addresses in the list of "to be connected" sockets for
>>>>> example).
>>>>
>>>> You'll need to sync up with Marcel regarding how this should be done
>>>> (I'll be effectively offline until next Tuesday so you wont be getting
>>>> more clarifications from me before that).
>>>>
>>>> I've never thought that doing tying connect() to the auto-connect
>>>> procedure is a good idea, and based on my last chat with Marcel a few
>>>> days ago he was agreeing. Having a pending connect() for potentially
>>>> days or even months is not really very intuitive compared to how
>>>> connect() is typically used. Instead, I think the ATT server socket
>>>> should always be the point of entry of new connections, regardless of
>>>> who is initiating. We'll then have a new mgmt command to add devices t=
o
>>>> a kernel-side list, potentially along with the necessary scan
>>>> parameters, and the kernel will then do the passive scanning based on
>>>> that.
>>>
>>> that is still my thinking here. Essentially every LE connection will be=
come an incoming connection. At least from the point of bluetoothd.
>>>
>>> The reasoning so far is pretty simple. The kernel needs to take control=
over the connect and auto-connect procedures. This means it has to figure =
out the right scanning parameters. No call to connect() will be able to pro=
vide the right amount of parameters here anyway. And doing a connect() with=
an infinite timeout seems the wrong approach.
>>
>> Still in the connect() approach for the initiating side, what about if
>> we had a socket option to set up the connection parameters? The user
>> would call setsockopt() to provide the right connection parameters
>> (for this connection) and then call connect(). If there is more than
>> one LE connection attempt going on, the kernel chooses the set of
>> parameters (provided by each setsockopt()) which is more restrictive.
>>
>> This way, we wouldn't require a extra mgmt command and the whole LE
>> connection functionality would be confined in the socket interface
>> instead of a mix of socket and management interfaces.
>>
>> Regarding the connect() with no timeout, yes, I think it is a bit
>> weird too. However, it seems this is the way connection is handled by
>> the LE spec.
>
> please carefully read my statement about the number of file descriptors. =
All these file descriptors are backed by kernel sockets and its memory. Whi=
le you think 30 is not a lot, but this can easily increase.
>
> And how to you handle reboots for example. We would just load an initial =
set of settings into the kernel via one management command, but with connec=
t() we have to create x new sockets.
>
>>> So I think it is better for bluetoothd to just sit and only consume 1 f=
ile descriptor for the listen socket instead of 10 or more for keeping one =
for every connect() we are holding. Especially with cases where devices are=
running for month and only ever now and then they want to actually connect=
. This is especially important if the connection interval is actually handl=
ed by the peripheral and we have no control.
>>
>> Following the server socket approach, let's say we have a BlueZ vs
>> BlueZ scenario (one the GATT server the other the GATT client). Both
>> (server and client) would call accept() to establish a connection.
>> This seems a weird usage of socket interface.
>
>
> Why are we thinking in GATT server and GATT client terms here. That is ju=
st wrong. Every single LE connection has a GATT client + server. The proced=
ures run in both directions. This is more about what services we expose.
>
> Regards
>
> Marcel
>

2013-05-03 15:17:14

by Marcel Holtmann

[permalink] [raw]
Subject: Re: GATT Clients and Servers in the kernel (was Re:[PATCH BlueZ v3 06/16] attrib...)

Hi Andre,

>>>>> the long term plan is to use standard types like bool, char, uint8_t
>>>>> and also void * here. However we might want to also see how to get
>>>>> rid of g_ prefix as well. Especially g_attrib seems to be a good
>>>>> candidate to get rid of.
>>>>>
>>>>> I also like to see ATT and GATT being implemented as src/shared/
>>>>> under LGPL so we can be easily share it in the future. I already
>>>>> have some (unpublished) code for src/shared/att.[ch] and
>>>>> src/shared/gatt.[ch] already, but I think what we first need to do
>>>>> is to figure out how we handle clients and servers from the kernel
>>>>> side. Especially with the background of the kernel auto-connecting
>>>>> LE channels in the future.
>>>>
>>>> I am assuming you were talking about the connection establishment. If
>>>> not, I am not following.
>>>>
>>>> I can only think of an evolutionary approach of what we are already
>>>> doing:
>>>>
>>>> - when we are the initiating side, the kernel will only auto-connect
>>>> devices that have an associated socket blocking on connect(); the
>>>> kernel may even use the white list if it seems appropriate (no
>>>> resolvable addresses in the list of "to be connected" sockets for
>>>> example).
>>>
>>> You'll need to sync up with Marcel regarding how this should be done
>>> (I'll be effectively offline until next Tuesday so you wont be getting
>>> more clarifications from me before that).
>>>
>>> I've never thought that doing tying connect() to the auto-connect
>>> procedure is a good idea, and based on my last chat with Marcel a few
>>> days ago he was agreeing. Having a pending connect() for potentially
>>> days or even months is not really very intuitive compared to how
>>> connect() is typically used. Instead, I think the ATT server socket
>>> should always be the point of entry of new connections, regardless of
>>> who is initiating. We'll then have a new mgmt command to add devices to
>>> a kernel-side list, potentially along with the necessary scan
>>> parameters, and the kernel will then do the passive scanning based on
>>> that.
>>
>> that is still my thinking here. Essentially every LE connection will become an incoming connection. At least from the point of bluetoothd.
>>
>> The reasoning so far is pretty simple. The kernel needs to take control over the connect and auto-connect procedures. This means it has to figure out the right scanning parameters. No call to connect() will be able to provide the right amount of parameters here anyway. And doing a connect() with an infinite timeout seems the wrong approach.
>
> Still in the connect() approach for the initiating side, what about if
> we had a socket option to set up the connection parameters? The user
> would call setsockopt() to provide the right connection parameters
> (for this connection) and then call connect(). If there is more than
> one LE connection attempt going on, the kernel chooses the set of
> parameters (provided by each setsockopt()) which is more restrictive.
>
> This way, we wouldn't require a extra mgmt command and the whole LE
> connection functionality would be confined in the socket interface
> instead of a mix of socket and management interfaces.
>
> Regarding the connect() with no timeout, yes, I think it is a bit
> weird too. However, it seems this is the way connection is handled by
> the LE spec.

please carefully read my statement about the number of file descriptors. All these file descriptors are backed by kernel sockets and its memory. While you think 30 is not a lot, but this can easily increase.

And how to you handle reboots for example. We would just load an initial set of settings into the kernel via one management command, but with connect() we have to create x new sockets.

>> So I think it is better for bluetoothd to just sit and only consume 1 file descriptor for the listen socket instead of 10 or more for keeping one for every connect() we are holding. Especially with cases where devices are running for month and only ever now and then they want to actually connect. This is especially important if the connection interval is actually handled by the peripheral and we have no control.
>
> Following the server socket approach, let's say we have a BlueZ vs
> BlueZ scenario (one the GATT server the other the GATT client). Both
> (server and client) would call accept() to establish a connection.
> This seems a weird usage of socket interface.


Why are we thinking in GATT server and GATT client terms here. That is just wrong. Every single LE connection has a GATT client + server. The procedures run in both directions. This is more about what services we expose.

Regards

Marcel


2013-05-03 15:11:57

by Vinicius Costa Gomes

[permalink] [raw]
Subject: Re: GATT Clients and Servers in the kernel (was Re:[PATCH BlueZ v3 06/16] attrib...)

Hi Marcel,

On Fri, May 3, 2013 at 3:17 AM, Marcel Holtmann <[email protected]> wrote=
:
> Hi Johan,
>
>>>> the long term plan is to use standard types like bool, char, uint8_t
>>>> and also void * here. However we might want to also see how to get
>>>> rid of g_ prefix as well. Especially g_attrib seems to be a good
>>>> candidate to get rid of.
>>>>
>>>> I also like to see ATT and GATT being implemented as src/shared/
>>>> under LGPL so we can be easily share it in the future. I already
>>>> have some (unpublished) code for src/shared/att.[ch] and
>>>> src/shared/gatt.[ch] already, but I think what we first need to do
>>>> is to figure out how we handle clients and servers from the kernel
>>>> side. Especially with the background of the kernel auto-connecting
>>>> LE channels in the future.
>>>
>>> I am assuming you were talking about the connection establishment. If
>>> not, I am not following.
>>>
>>> I can only think of an evolutionary approach of what we are already
>>> doing:
>>>
>>> - when we are the initiating side, the kernel will only auto-connect
>>> devices that have an associated socket blocking on connect(); the
>>> kernel may even use the white list if it seems appropriate (no
>>> resolvable addresses in the list of "to be connected" sockets for
>>> example).
>>
>> You'll need to sync up with Marcel regarding how this should be done
>> (I'll be effectively offline until next Tuesday so you wont be getting
>> more clarifications from me before that).
>>
>> I've never thought that doing tying connect() to the auto-connect
>> procedure is a good idea, and based on my last chat with Marcel a few
>> days ago he was agreeing. Having a pending connect() for potentially
>> days or even months is not really very intuitive compared to how
>> connect() is typically used. Instead, I think the ATT server socket
>> should always be the point of entry of new connections, regardless of
>> who is initiating. We'll then have a new mgmt command to add devices to
>> a kernel-side list, potentially along with the necessary scan
>> parameters, and the kernel will then do the passive scanning based on
>> that.
>
> that is still my thinking here. Essentially every LE connection will beco=
me an incoming connection. At least from the point of bluetoothd.
>
> The reasoning so far is pretty simple. The kernel needs to take control o=
ver the connect and auto-connect procedures. This means it has to figure ou=
t the right scanning parameters. No call to connect() will be able to provi=
de the right amount of parameters here anyway. And doing a connect() with a=
n infinite timeout seems the wrong approach.

I agree that we need a way to feed the kernel the connection
parameters and that a new mgmt command seems the best way. This
infinite timeout argument still doesn't convince me that it is the
wrong approach.

>
> So I think it is better for bluetoothd to just sit and only consume 1 fil=
e descriptor for the listen socket instead of 10 or more for keeping one fo=
r every connect() we are holding. Especially with cases where devices are r=
unning for month and only ever now and then they want to actually connect. =
This is especially important if the connection interval is actually handled=
by the peripheral and we have no control.

This one is better, with multiple connect()s we would have a very low
"used coefficient" (rate of the number of active connection over the
number of waiting connections).

There's still the point that we will have to keep the connect() side
of things playing nicely with the rest. Having a half baked connect()
is wrong.

So we would have two alternatives for establishing connections, the
"listen way" that would be used by applications that exptect a low
"used coefficient" (bluetoothd) and the "connect way" that would be
used by applications that expect to have a high "used coefficient"
(gatttool-like applications).

>
> Regards
>
> Marcel
>



--
Vinicius

2013-05-03 15:06:04

by Andre Guedes

[permalink] [raw]
Subject: Re: GATT Clients and Servers in the kernel (was Re:[PATCH BlueZ v3 06/16] attrib...)

Hi Marcel, Johan and Vinicius,

On Fri, May 3, 2013 at 3:17 AM, Marcel Holtmann <[email protected]> wrote=
:
> Hi Johan,
>
>>>> the long term plan is to use standard types like bool, char, uint8_t
>>>> and also void * here. However we might want to also see how to get
>>>> rid of g_ prefix as well. Especially g_attrib seems to be a good
>>>> candidate to get rid of.
>>>>
>>>> I also like to see ATT and GATT being implemented as src/shared/
>>>> under LGPL so we can be easily share it in the future. I already
>>>> have some (unpublished) code for src/shared/att.[ch] and
>>>> src/shared/gatt.[ch] already, but I think what we first need to do
>>>> is to figure out how we handle clients and servers from the kernel
>>>> side. Especially with the background of the kernel auto-connecting
>>>> LE channels in the future.
>>>
>>> I am assuming you were talking about the connection establishment. If
>>> not, I am not following.
>>>
>>> I can only think of an evolutionary approach of what we are already
>>> doing:
>>>
>>> - when we are the initiating side, the kernel will only auto-connect
>>> devices that have an associated socket blocking on connect(); the
>>> kernel may even use the white list if it seems appropriate (no
>>> resolvable addresses in the list of "to be connected" sockets for
>>> example).
>>
>> You'll need to sync up with Marcel regarding how this should be done
>> (I'll be effectively offline until next Tuesday so you wont be getting
>> more clarifications from me before that).
>>
>> I've never thought that doing tying connect() to the auto-connect
>> procedure is a good idea, and based on my last chat with Marcel a few
>> days ago he was agreeing. Having a pending connect() for potentially
>> days or even months is not really very intuitive compared to how
>> connect() is typically used. Instead, I think the ATT server socket
>> should always be the point of entry of new connections, regardless of
>> who is initiating. We'll then have a new mgmt command to add devices to
>> a kernel-side list, potentially along with the necessary scan
>> parameters, and the kernel will then do the passive scanning based on
>> that.
>
> that is still my thinking here. Essentially every LE connection will beco=
me an incoming connection. At least from the point of bluetoothd.
>
> The reasoning so far is pretty simple. The kernel needs to take control o=
ver the connect and auto-connect procedures. This means it has to figure ou=
t the right scanning parameters. No call to connect() will be able to provi=
de the right amount of parameters here anyway. And doing a connect() with a=
n infinite timeout seems the wrong approach.

Still in the connect() approach for the initiating side, what about if
we had a socket option to set up the connection parameters? The user
would call setsockopt() to provide the right connection parameters
(for this connection) and then call connect(). If there is more than
one LE connection attempt going on, the kernel chooses the set of
parameters (provided by each setsockopt()) which is more restrictive.

This way, we wouldn't require a extra mgmt command and the whole LE
connection functionality would be confined in the socket interface
instead of a mix of socket and management interfaces.

Regarding the connect() with no timeout, yes, I think it is a bit
weird too. However, it seems this is the way connection is handled by
the LE spec.

> So I think it is better for bluetoothd to just sit and only consume 1 fil=
e descriptor for the listen socket instead of 10 or more for keeping one fo=
r every connect() we are holding. Especially with cases where devices are r=
unning for month and only ever now and then they want to actually connect. =
This is especially important if the connection interval is actually handled=
by the peripheral and we have no control.

Following the server socket approach, let's say we have a BlueZ vs
BlueZ scenario (one the GATT server the other the GATT client). Both
(server and client) would call accept() to establish a connection.
This seems a weird usage of socket interface.

Besides, what happens with connect()? We will have to support it
anyway, right? At the end, we will have two ways to initiate a LE
connection?

BR,

Andre

2013-05-03 06:17:41

by Marcel Holtmann

[permalink] [raw]
Subject: Re: GATT Clients and Servers in the kernel (was Re:[PATCH BlueZ v3 06/16] attrib...)

Hi Johan,

>>> the long term plan is to use standard types like bool, char, uint8_t
>>> and also void * here. However we might want to also see how to get
>>> rid of g_ prefix as well. Especially g_attrib seems to be a good
>>> candidate to get rid of.
>>>
>>> I also like to see ATT and GATT being implemented as src/shared/
>>> under LGPL so we can be easily share it in the future. I already
>>> have some (unpublished) code for src/shared/att.[ch] and
>>> src/shared/gatt.[ch] already, but I think what we first need to do
>>> is to figure out how we handle clients and servers from the kernel
>>> side. Especially with the background of the kernel auto-connecting
>>> LE channels in the future.
>>
>> I am assuming you were talking about the connection establishment. If
>> not, I am not following.
>>
>> I can only think of an evolutionary approach of what we are already
>> doing:
>>
>> - when we are the initiating side, the kernel will only auto-connect
>> devices that have an associated socket blocking on connect(); the
>> kernel may even use the white list if it seems appropriate (no
>> resolvable addresses in the list of "to be connected" sockets for
>> example).
>
> You'll need to sync up with Marcel regarding how this should be done
> (I'll be effectively offline until next Tuesday so you wont be getting
> more clarifications from me before that).
>
> I've never thought that doing tying connect() to the auto-connect
> procedure is a good idea, and based on my last chat with Marcel a few
> days ago he was agreeing. Having a pending connect() for potentially
> days or even months is not really very intuitive compared to how
> connect() is typically used. Instead, I think the ATT server socket
> should always be the point of entry of new connections, regardless of
> who is initiating. We'll then have a new mgmt command to add devices to
> a kernel-side list, potentially along with the necessary scan
> parameters, and the kernel will then do the passive scanning based on
> that.

that is still my thinking here. Essentially every LE connection will become an incoming connection. At least from the point of bluetoothd.

The reasoning so far is pretty simple. The kernel needs to take control over the connect and auto-connect procedures. This means it has to figure out the right scanning parameters. No call to connect() will be able to provide the right amount of parameters here anyway. And doing a connect() with an infinite timeout seems the wrong approach.

So I think it is better for bluetoothd to just sit and only consume 1 file descriptor for the listen socket instead of 10 or more for keeping one for every connect() we are holding. Especially with cases where devices are running for month and only ever now and then they want to actually connect. This is especially important if the connection interval is actually handled by the peripheral and we have no control.

Regards

Marcel


2013-05-03 04:43:55

by Johan Hedberg

[permalink] [raw]
Subject: Re: GATT Clients and Servers in the kernel (was Re:[PATCH BlueZ v3 06/16] attrib...)

Hi Vinicius,

On Thu, May 02, 2013, Vinicius Gomes wrote:
> > the long term plan is to use standard types like bool, char, uint8_t
> > and also void * here. However we might want to also see how to get
> > rid of g_ prefix as well. Especially g_attrib seems to be a good
> > candidate to get rid of.
> >
> > I also like to see ATT and GATT being implemented as src/shared/
> > under LGPL so we can be easily share it in the future. I already
> > have some (unpublished) code for src/shared/att.[ch] and
> > src/shared/gatt.[ch] already, but I think what we first need to do
> > is to figure out how we handle clients and servers from the kernel
> > side. Especially with the background of the kernel auto-connecting
> > LE channels in the future.
>
> I am assuming you were talking about the connection establishment. If
> not, I am not following.
>
> I can only think of an evolutionary approach of what we are already
> doing:
>
> - when we are the initiating side, the kernel will only auto-connect
> devices that have an associated socket blocking on connect(); the
> kernel may even use the white list if it seems appropriate (no
> resolvable addresses in the list of "to be connected" sockets for
> example).

You'll need to sync up with Marcel regarding how this should be done
(I'll be effectively offline until next Tuesday so you wont be getting
more clarifications from me before that).

I've never thought that doing tying connect() to the auto-connect
procedure is a good idea, and based on my last chat with Marcel a few
days ago he was agreeing. Having a pending connect() for potentially
days or even months is not really very intuitive compared to how
connect() is typically used. Instead, I think the ATT server socket
should always be the point of entry of new connections, regardless of
who is initiating. We'll then have a new mgmt command to add devices to
a kernel-side list, potentially along with the necessary scan
parameters, and the kernel will then do the passive scanning based on
that.

Johan