* Re: possible bug in blueZ 5.8 gatt tool or library
From: Anderson Lizardo @ 2014-02-04 23:05 UTC (permalink / raw)
To: Caleb Reinhold; +Cc: BlueZ development
In-Reply-To: <000201cf21ed$d18f02d0$74ad0870$@lampreynetworks.com>
Hi Caleb,
On Tue, Feb 4, 2014 at 5:12 PM, Caleb Reinhold
<creinhold@lampreynetworks.com> wrote:
> We are working with the 5.8 version of the library, kernel version 3.12.9,
> bluetoothctl, and gatttool when we encountered a possible error.
> We expected on the reconnection of two bonded devices, one of which had
> stored measurements, that data would transfer. When running gatt tool in
> medium security the first measurement to be indicated was lost.
First of all, gatttool is a developer tool, and it is far from being a
compliant GATT endpoint (e.g. it does not report to requests, which is
mandatory by the spec). With moderate effort though, the missing
features can be added.
> However upon attempting to reconnect to the simulated agent device with
> medium security two unexpected behaviors occurred. First, and more
> immediately apparent was that the simulated agent did not receive a
> confirmation of the indication. A slightly closer look using the hcidump,
> trying to find what had happened, showed that the indication had arrived at
> the hci layer but was not received at events_handler.
Are you using gatttool in interactive mode (i.e. the -I option) ? If
yes, try first connecting to the device with "connect" followed by
setting the security level to medium with "sec-level medium". This
will imitate the behavior of the BlueZ daemon when connecting to LE
devices. Also be sure to use the "--listen" option so the confirmation
is sent by gatttool.
Let us know if it works :)
> While the indication
> is sent very swiftly upon the reconnection of the devices we understand this
> to be the manner in which low energy devices are supposed to behave given
> stored measurements and a bonded device.
You are correct that this is the expected behavior. But gatttool is
far from perfect. Did you try implementing a BlueZ plugin?
Best Regards,
--
Anderson Lizardo
http://www.indt.org/?lang=en
INdT - Manaus - Brazil
^ permalink raw reply
* Re: Bluetooth qualification, AVDTP test case
From: Luiz Augusto von Dentz @ 2014-02-04 22:06 UTC (permalink / raw)
To: Artem Rakhov; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <CAD81oNbWcjW_vEzf-C8VkS9Mkh92jdaKLHc_sTY9yt1wvboM3g@mail.gmail.com>
Hi Artem,
On Tue, Feb 4, 2014 at 10:36 PM, Artem Rakhov <arakhov@google.com> wrote:
> Hi Luiz,
>
> We are currently working on the Bluetooth SIG qualification, and we are
> failing AVDTP test case "TP/SIG/SMG/BI-28-C". I've found your test in the
> BlueZ source (unit/test-avdtp.c), which seems to contain implementation of
> this test case. Could you please give us some clue on how to use it to do
> the actual testing and to produce a log?
Interesting, apparently the test spec suggests resetting the signal
identifier to 0x00:
Pass verdict
The lower tester receives the AVDTP signaling message with the fields:
Transaction_label = Transaction LowerTester
Other 10 bits = All set to '0'.
While the spec suggests to keep the original signal identifier that is
being rejected see Table 8.42: General Reject response format.
We are following the spec text in this respect, thus our unit test
checks for the original signal identifier skipping the RFA bits which
is what our AVDTP implementation does when responding when receiving
such command, either way it is easy to fix but we probably need to
file an errata so the spec and test spec are more consistent regarding
general reject response.
For the purpose of qualification I think we need the full trace up to
HCI so the unit test are not enough, but there are plans to do that
via emulator.
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: How do you install bluez for development?
From: Vinicius Costa Gomes @ 2014-02-04 21:57 UTC (permalink / raw)
To: Alejandro Exojo; +Cc: linux-bluetooth
In-Reply-To: <CACMtdhhnvG_PopNn185npxi2nSqzFSLXthoh6PPPTh4SGj_uiA@mail.gmail.com>
Hi Alejandro,
On 08:28 Tue 04 Feb, Alejandro Exojo wrote:
> 2014-02-03 Vinicius Costa Gomes <vcgomes@gmail.com>:
> >> Feb 03 17:14:38 PC-MW03 systemd[1]: Starting Bluetooth service...
> >> Feb 03 17:14:38 PC-MW03 bluetoothd[22571]: Bluetooth daemon 5.14
> >> Feb 03 17:14:38 PC-MW03 systemd[1]: Started Bluetooth service.
> >> Feb 03 17:14:38 PC-MW03 systemd[1]: Starting Bluetooth.
> >> Feb 03 17:14:38 PC-MW03 systemd[1]: Reached target Bluetooth.
> >> Feb 03 17:14:38 PC-MW03 bluetoothd[22571]: Failed to access management interface
> >
> > Two probable causes, your kernel is older than 3.4, or the user that is running
> > bluetoothd doesn't have the CAP_NET_ADMIN capability.
>
> True! I was running 3.2. I've installed a more recent one, and I got
> it working. Thank you very much, I would not have thought of the
> kernel at all.
>
> How come that at least 3.4 is needed?
That was the kernel version that enabled the management interface by default, which is a
runtime requirement for BlueZ 5.x.
>
> Thank you again.
>
> Cheers.
> --
> Alejandro Exojo Piqueras
>
> ModpoW, S.L.
> Technova LaSalle | Sant Joan de la Salle 42 | 08022 Barcelona | www.modpow.es
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
Cheers,
--
Vinicius
^ permalink raw reply
* possible bug in blueZ 5.8 gatt tool or library
From: Caleb Reinhold @ 2014-02-04 21:12 UTC (permalink / raw)
To: linux-bluetooth
[-- Attachment #1: Type: text/plain, Size: 1663 bytes --]
Hello all,
I am participating in an effort to make use of the BlueZ libraries to pull
data from Bluetooth Low Energy health devices.
We are working with the 5.8 version of the library, kernel version 3.12.9,
bluetoothctl, and gatttool when we encountered a possible error.
We expected on the reconnection of two bonded devices, one of which had
stored measurements, that data would transfer. When running gatt tool in
medium security the first measurement to be indicated was lost.
First we used Bluetooth control to pair with the simulated agent device (a
thermometer). Then we disconnected with bluetoothctl and connected with
gatttool in order to write to the C3D (client characteristic configuration
descriptors). After setting the C3D to indicate, we transferred a
measurement successfully. Up until this point we saw no unexpected
difference in behavior between low and medium security on the gatttool.
However upon attempting to reconnect to the simulated agent device with
medium security two unexpected behaviors occurred. First, and more
immediately apparent was that the simulated agent did not receive a
confirmation of the indication. A slightly closer look using the hcidump,
trying to find what had happened, showed that the indication had arrived at
the hci layer but was not received at events_handler. While the indication
is sent very swiftly upon the reconnection of the devices we understand this
to be the manner in which low energy devices are supposed to behave given
stored measurements and a bonded device.
Records of hcidumps are attached.
Caleb Reinhold
P.S. Resending after failing to attach traces
[-- Attachment #2: hci_dump.txt --]
[-- Type: text/plain, Size: 4870 bytes --]
< HCI Command: LE Create Connection (0x08|0x000d) plen 25 [hci0] 5199.285444
Scan interval: 60.000 msec (0x0060)
Scan window: 30.000 msec (0x0030)
Filter policy: White list is not used (0x00)
Peer address type: Public (0x00)
Peer address: 00:02:72:C6:A0:6B (CC&C Technologies, Inc.)
Own address type: Public (0x00)
Min connection interval: 50.00 msec (0x0028)
Max connection interval: 70.00 msec (0x0038)
Connection latency: 0x0000
Supervision timeout: 420 msec (0x002a)
Min connection length: 0.000 msec (0x0000)
Max connection length: 0.000 msec (0x0000)
> HCI Event: Command Status (0x0f) plen 4 [hci0] 5199.288196
LE Create Connection (0x08|0x000d) ncmd 1
Status: Success (0x00)
> HCI Event: LE Meta Event (0x3e) plen 19 [hci0] 5209.096157
LE Connection Complete (0x01)
Status: Success (0x00)
Handle: 64
Role: Master (0x00)
Peer address type: Public (0x00)
Peer address: 00:02:72:C6:A0:6B (CC&C Technologies, Inc.)
Connection interval: 67.50 msec (0x0036)
Connection latency: 0.00 msec (0x0000)
Supervision timeout: 420 msec (0x002a)
Master clock accuracy: 0x05
@ Device Connected: 00:02:72:C6:A0:6B (1) flags 0x0000
> ACL Data RX: Handle 64 flags 0x02 dlen 19 [hci0] 5209.129475
ATT: Handle Value Indication (0x1d) len 14
Handle: 0x0004
Data: 0363000000de0702030f1b0e
< ACL Data TX: Handle 64 flags 0x00 dlen 5 [hci0] 5209.129824
ATT: Handle Value Confirmation (0x1e) len 0
> HCI Event: Number of Completed Packets (0x13) plen 5 [hci0] 5209.338106
Num handles: 1
Handle: 64
Count: 1
< HCI Command: Disconnect (0x01|0x0006) plen 3 [hci0] 5258.609760
Handle: 64
Reason: Remote User Terminated Connection (0x13)
> HCI Event: Command Status (0x0f) plen 4 [hci0] 5258.611935
Disconnect (0x01|0x0006) ncmd 1
Status: Success (0x00)
> HCI Event: Disconnect Complete (0x05) plen 4 [hci0] 5258.674959
Status: Success (0x00)
Handle: 64
Reason: Connection Terminated By Local Host (0x16)
@ Device Disconnected: 00:02:72:C6:A0:6B (1) reason 2
< HCI Command: LE Create Connection (0x08|0x000d) plen 25 [hci0] 5302.994402
Scan interval: 60.000 msec (0x0060)
Scan window: 30.000 msec (0x0030)
Filter policy: White list is not used (0x00)
Peer address type: Public (0x00)
Peer address: 00:02:72:C6:A0:6B (CC&C Technologies, Inc.)
Own address type: Public (0x00)
Min connection interval: 50.00 msec (0x0028)
Max connection interval: 70.00 msec (0x0038)
Connection latency: 0x0000
Supervision timeout: 420 msec (0x002a)
Min connection length: 0.000 msec (0x0000)
Max connection length: 0.000 msec (0x0000)
> HCI Event: Command Status (0x0f) plen 4 [hci0] 5302.996878
LE Create Connection (0x08|0x000d) ncmd 1
Status: Success (0x00)
> HCI Event: LE Meta Event (0x3e) plen 19 [hci0] 5311.264930
LE Connection Complete (0x01)
Status: Success (0x00)
Handle: 64
Role: Master (0x00)
Peer address type: Public (0x00)
Peer address: 00:02:72:C6:A0:6B (CC&C Technologies, Inc.)
Connection interval: 67.50 msec (0x0036)
Connection latency: 0.00 msec (0x0000)
Supervision timeout: 420 msec (0x002a)
Master clock accuracy: 0x05
< HCI Command: LE Start Encryption (0x08|0x0019) plen 28 [hci0] 5311.265128
Handle: 64
Random number: 0d996e4936b9603f
Encryption diversifier: 0x13a1
Long term key: d43f4e489cc5b0746f86eac218c976e9
@ Device Connected: 00:02:72:C6:A0:6B (1) flags 0x0000
> HCI Event: Command Status (0x0f) plen 4 [hci0] 5311.267895
LE Start Encryption (0x08|0x0019) ncmd 1
Status: Success (0x00)
> ACL Data RX: Handle 64 flags 0x02 dlen 19 [hci0] 5311.326262
ATT: Handle Value Indication (0x1d) len 14
Handle: 0x0004
Data: 0363000000de0702030f1c38
> HCI Event: Encryption Change (0x08) plen 4 [hci0] 5311.730919
Status: Success (0x00)
Handle: 64
Encryption: Enabled with AES-CCM (0x01)
[-- Attachment #3: BlueZ Trace-2 indications.txt --]
[-- Type: text/plain, Size: 2797 bytes --]
< HCI Command: LE Create Connection (0x08|0x000d) plen 25 [hci0] 5302.994402
Scan interval: 60.000 msec (0x0060)
Scan window: 30.000 msec (0x0030)
Filter policy: White list is not used (0x00)
Peer address type: Public (0x00)
Peer address: 00:02:72:C6:A0:6B (CC&C Technologies, Inc.)
Own address type: Public (0x00)
Min connection interval: 50.00 msec (0x0028)
Max connection interval: 70.00 msec (0x0038)
Connection latency: 0x0000
Supervision timeout: 420 msec (0x002a)
Min connection length: 0.000 msec (0x0000)
Max connection length: 0.000 msec (0x0000)
> HCI Event: Command Status (0x0f) plen 4 [hci0] 5302.996878
LE Create Connection (0x08|0x000d) ncmd 1
Status: Success (0x00)
> HCI Event: LE Meta Event (0x3e) plen 19 [hci0] 5311.264930
LE Connection Complete (0x01)
Status: Success (0x00)
Handle: 64
Role: Master (0x00)
Peer address type: Public (0x00)
Peer address: 00:02:72:C6:A0:6B (CC&C Technologies, Inc.)
Connection interval: 67.50 msec (0x0036)
Connection latency: 0.00 msec (0x0000)
Supervision timeout: 420 msec (0x002a)
Master clock accuracy: 0x05
< HCI Command: LE Start Encryption (0x08|0x0019) plen 28 [hci0] 5311.265128
Handle: 64
Random number: 0d996e4936b9603f
Encryption diversifier: 0x13a1
Long term key: d43f4e489cc5b0746f86eac218c976e9
@ Device Connected: 00:02:72:C6:A0:6B (1) flags 0x0000
> HCI Event: Command Status (0x0f) plen 4 [hci0] 5311.267895
LE Start Encryption (0x08|0x0019) ncmd 1
Status: Success (0x00)
> ACL Data RX: Handle 64 flags 0x02 dlen 19 [hci0] 5311.326262
ATT: Handle Value Indication (0x1d) len 14
Handle: 0x0004
Data: 0363000000de0702030f1c38
> HCI Event: Encryption Change (0x08) plen 4 [hci0] 5311.730919
Status: Success (0x00)
Handle: 64
Encryption: Enabled with AES-CCM (0x01)
> ACL Data RX: Handle 64 flags 0x02 dlen 19 [hci0] 5556.355293
ATT: Handle Value Indication (0x1d) len 14
Handle: 0x0004
Data: 0363000000de0702030f2101
< ACL Data TX: Handle 64 flags 0x00 dlen 5 [hci0] 5556.355579
ATT: Handle Value Confirmation (0x1e) len 0
> HCI Event: Number of Completed Packets (0x13) plen 5 [hci0] 5556.622163
Num handles: 1
Handle: 64
Count: 1
^ permalink raw reply
* possible bug in blueZ 5.8 gatt tool or library
From: Caleb Reinhold @ 2014-02-04 21:08 UTC (permalink / raw)
To: linux-bluetooth
Hello all,
I am participating in an effort to make use of the BlueZ libraries to pull
data from Bluetooth Low Energy health devices.
We are working with the 5.8 version of the library, kernel version 3.12.9,
bluetoothctl, and gatttool when we encountered a possible error.
We expected on the reconnection of two bonded devices, one of which had
stored measurements, that data would transfer. When running gatt tool in
medium security the first measurement to be indicated was lost.
First we used Bluetooth control to pair with the simulated agent device (a
thermometer). Then we disconnected with bluetoothctl and connected with
gatttool in order to write to the C3D (client characteristic configuration
descriptors). After setting the C3D to indicate, we transferred a
measurement successfully. Up until this point we saw no unexpected
difference in behavior between low and medium security on the gatttool.
However upon attempting to reconnect to the simulated agent device with
medium security two unexpected behaviors occurred. First, and more
immediately apparent was that the simulated agent did not receive a
confirmation of the indication. A slightly closer look using the hcidump,
trying to find what had happened, showed that the indication had arrived at
the hci layer but was not received at events_handler. While the indication
is sent very swiftly upon the reconnection of the devices we understand this
to be the manner in which low energy devices are supposed to behave given
stored measurements and a bonded device.
Records of hcidumps are attached.
Caleb Reinhold
^ permalink raw reply
* Re: [PATCH 01/11] android/unit: Fix checking for expected termination
From: Szymon Janc @ 2014-02-04 20:37 UTC (permalink / raw)
To: Jakub Tyszkowski; +Cc: linux-bluetooth
In-Reply-To: <1391524749-2518-1-git-send-email-jakub.tyszkowski@tieto.com>
Hi Jakub,
On Tuesday 04 February 2014 15:38:59 Jakub Tyszkowski wrote:
> This fix makes sure that when signalled termination is expected,
> it actually happens. If IPC termination is expected no response will be
> sent, so cmd_watch will never be executed. But if it is executed when
> expecting termination, its a failure.
> ---
> android/test-ipc.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/android/test-ipc.c b/android/test-ipc.c
> index 8af5739..d0f3f6b 100644
> --- a/android/test-ipc.c
> +++ b/android/test-ipc.c
> @@ -82,6 +82,8 @@ static gboolean cmd_watch(GIOChannel *io, GIOCondition
> cond, uint8_t buf[128];
> int sk;
>
> + g_assert(test_data->expected_signal == 0);
> +
> if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
> g_assert(FALSE);
> return FALSE;
All patches are now upstream, thanks.
--
Szymon K. Janc
szymon.janc@gmail.com
^ permalink raw reply
* Re: [RFC v7 08/11] Bluetooth: Temporarily stop background scanning on discovery
From: Andre Guedes @ 2014-02-04 18:33 UTC (permalink / raw)
To: Marcel Holtmann; +Cc: BlueZ development
In-Reply-To: <9BB5F5F9-6828-491B-B918-B0909BCA2408@holtmann.org>
Hi Marcel,
On Mon, 2014-02-03 at 20:25 -0800, Marcel Holtmann wrote:
> Hi Andre,
>
> > If the user sends a mgmt start discovery command while the background
> > scanning is running, we should temporarily stop it. Once the discovery
> > finishes, we start the background scanning again.
> >
> > Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
> > ---
> > net/bluetooth/hci_core.c | 2 ++
> > net/bluetooth/mgmt.c | 12 ++++++++----
> > 2 files changed, 10 insertions(+), 4 deletions(-)
> >
> > diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
> > index 388a453..222bd07 100644
> > --- a/net/bluetooth/hci_core.c
> > +++ b/net/bluetooth/hci_core.c
> > @@ -1609,6 +1609,8 @@ void hci_discovery_set_state(struct hci_dev *hdev, int state)
> >
> > switch (state) {
> > case DISCOVERY_STOPPED:
> > + hci_update_background_scan(hdev);
> > +
> > if (hdev->discovery.state != DISCOVERY_STARTING)
> > mgmt_discovering(hdev, 0);
> > break;
> > diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
> > index ce7ef33..83af8de 100644
> > --- a/net/bluetooth/mgmt.c
> > +++ b/net/bluetooth/mgmt.c
> > @@ -3319,11 +3319,15 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
> > goto failed;
> > }
> >
> > + /* If controller is scanning, it means the background scanning
> > + * is running. Thus, we should temporarily stop it in order to
> > + * set the discovery scanning parameters.
> > + */
> > if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
> > - err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
> > - MGMT_STATUS_BUSY);
> > - mgmt_pending_remove(cmd);
> > - goto failed;
> > + memset(&enable_cp, 0, sizeof(enable_cp));
> > + enable_cp.enable = LE_SCAN_DISABLE;
> > + hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
> > + sizeof(enable_cp), &enable_cp);
> > }
>
> is the start_discovery protected enough by itself so that we do not accidentally stop some discovery that got triggered which is actually not a background scan.
A few lines above (the diff doesn't show it), we check the discovery
state, ensuring the discovery is not running at this point.
BR,
Andre
^ permalink raw reply
* Re: [RFC v7 07/11] Bluetooth: Re-enable background scan in case of error
From: Andre Guedes @ 2014-02-04 18:32 UTC (permalink / raw)
To: Marcel Holtmann; +Cc: BlueZ development
In-Reply-To: <D3ABE58A-C3B4-4BF1-8C7B-BE63ECED7C89@holtmann.org>
Hi Marcel,
On Mon, 2014-02-03 at 20:10 -0800, Marcel Holtmann wrote:
> Hi Andre,
>
> > Since we temporarily stop the background scanning in favor of
> > connection, we should re-enable it in case something goes wrong
> > with connection establishment. So this patch adds a hci_update_
> > background_scan() call in fail_conn_attempt() and hci_le_conn_
> > complete_evt() error flow.
> >
> > Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
> > ---
> > net/bluetooth/hci_conn.c | 2 ++
> > net/bluetooth/hci_event.c | 1 +
> > 2 files changed, 3 insertions(+)
> >
> > diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
> > index 127465f..2ef29c7 100644
> > --- a/net/bluetooth/hci_conn.c
> > +++ b/net/bluetooth/hci_conn.c
> > @@ -527,6 +527,8 @@ static void le_conn_failed(struct hci_conn *conn, u8 status)
> > hci_proto_connect_cfm(conn, status);
> >
> > hci_conn_del(conn);
> > +
> > + hci_update_background_scan(hdev);
> > }
> >
> > static void create_le_conn_complete(struct hci_dev *hdev, u8 status)
> > diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
> > index ef95030..8de51b1 100644
> > --- a/net/bluetooth/hci_event.c
> > +++ b/net/bluetooth/hci_event.c
> > @@ -3606,6 +3606,7 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
> > hci_proto_connect_cfm(conn, ev->status);
> > conn->state = BT_CLOSED;
> > hci_conn_del(conn);
> > + hci_update_background_scan(hdev);
> > goto unlock;
>
> please fold this patch into the one that does the disabling.
I'll squash this patch into 06/11.
- Andre
^ permalink raw reply
* Re: [RFC v7 03/11] Bluetooth: Stop scanning on LE connection
From: Andre Guedes @ 2014-02-04 18:32 UTC (permalink / raw)
To: Marcel Holtmann; +Cc: BlueZ development
In-Reply-To: <629D5403-D2BD-4DCE-B243-41CE971DE914@holtmann.org>
Hi Marcel,
On Mon, 2014-02-03 at 20:08 -0800, Marcel Holtmann wrote:
> Hi Andrei,
>
> > Some LE controllers don't support scanning and creating a connection
> > at the same time. So we should always stop scanning in order to
> > establish the connection.
> >
> > Since we may prematurely stop the discovery procedure in favor of
> > the connection establishment, we should also cancel hdev->le_scan_
> > disable delayed work and set the discovery state to DISCOVERY_STOPPED.
> >
> > This change does a small improvement since it is not mandatory the
> > user stops scanning before connecting anymore. Moreover, this change
> > is required by upcoming LE auto connection mechanism in order to work
> > properly with controllers that don't support background scanning and
> > connection establishment at the same time.
> >
> > In future, we might want to do a small optimization by checking if
> > controller is able to scan and connect at the same time. For now,
> > we want the simplest approach so we always stop scanning (even if
> > the controller is able to carry out both operations).
> >
> > Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
> > ---
> > include/net/bluetooth/hci.h | 1 +
> > net/bluetooth/hci_conn.c | 84 +++++++++++++++++++++++++++++++++++++++++++--
> > 2 files changed, 83 insertions(+), 2 deletions(-)
> >
> > diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
> > index 352d3d7..a0d5262 100644
> > --- a/include/net/bluetooth/hci.h
> > +++ b/include/net/bluetooth/hci.h
> > @@ -352,6 +352,7 @@ enum {
> >
> > /* ---- HCI Error Codes ---- */
> > #define HCI_ERROR_AUTH_FAILURE 0x05
> > +#define HCI_ERROR_MEMORY_EXCEEDED 0x07
> > #define HCI_ERROR_CONNECTION_TIMEOUT 0x08
> > #define HCI_ERROR_REJ_BAD_ADDR 0x0f
> > #define HCI_ERROR_REMOTE_USER_TERM 0x13
> > diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
> > index 6797292..63c1e4f 100644
> > --- a/net/bluetooth/hci_conn.c
> > +++ b/net/bluetooth/hci_conn.c
> > @@ -583,11 +583,71 @@ static int hci_create_le_conn(struct hci_conn *conn)
> > return 0;
> > }
> >
> > +static void create_le_conn_req(struct hci_request *req, struct hci_conn *conn)
> > +{
> > + struct hci_cp_le_create_conn cp;
> > + struct hci_dev *hdev = conn->hdev;
> > +
> > + memset(&cp, 0, sizeof(cp));
> > + cp.scan_interval = cpu_to_le16(hdev->le_scan_interval);
> > + cp.scan_window = cpu_to_le16(hdev->le_scan_window);
> > + bacpy(&cp.peer_addr, &conn->dst);
> > + cp.peer_addr_type = conn->dst_type;
> > + cp.own_address_type = conn->src_type;
> > + cp.conn_interval_min = cpu_to_le16(conn->le_conn_min_interval);
> > + cp.conn_interval_max = cpu_to_le16(conn->le_conn_max_interval);
> > + cp.supervision_timeout = __constant_cpu_to_le16(0x002a);
> > + cp.min_ce_len = __constant_cpu_to_le16(0x0000);
> > + cp.max_ce_len = __constant_cpu_to_le16(0x0000);
> > +
> > + hci_req_add(req, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp);
> > +}
> > +
> > +static void stop_scan_complete(struct hci_dev *hdev, u8 status)
> > +{
> > + struct hci_request req;
> > + struct hci_conn *conn;
> > + int err;
> > +
> > + conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT);
> > + if (!conn)
> > + return;
> > +
> > + if (status) {
> > + BT_DBG("HCI request failed to stop scanning: status 0x%2.2x",
> > + status);
> > +
> > + hci_dev_lock(hdev);
> > + le_conn_failed(conn, status);
> > + hci_dev_unlock(hdev);
> > + return;
> > + }
> > +
> > + /* Since we may have prematurely stopped discovery procedure, we should
> > + * update discovery state.
> > + */
> > + cancel_delayed_work(&hdev->le_scan_disable);
> > + hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
> > +
> > + hci_req_init(&req, hdev);
> > +
> > + create_le_conn_req(&req, conn);
> > +
> > + err = hci_req_run(&req, create_le_conn_complete);
> > + if (err) {
> > + hci_dev_lock(hdev);
> > + le_conn_failed(conn, HCI_ERROR_MEMORY_EXCEEDED);
> > + hci_dev_unlock(hdev);
> > + return;
> > + }
> > +}
> > +
> > static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
> > u8 dst_type, u8 sec_level, u8 auth_type)
> > {
> > struct hci_conn_params *params;
> > struct hci_conn *conn;
> > + struct hci_request req;
> > int err;
> >
> > if (test_bit(HCI_ADVERTISING, &hdev->flags))
> > @@ -643,9 +703,29 @@ static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
> > conn->le_conn_max_interval = hdev->le_conn_max_interval;
> > }
> >
> > - err = hci_create_le_conn(conn);
> > - if (err)
> > + hci_req_init(&req, hdev);
> > +
> > + /* If controller is scanning, we stop it since some controllers are
> > + * not able to scan and connect at the same time.
> > + */
> > + if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
> > + struct hci_cp_le_set_scan_enable cp;
> > +
> > + memset(&cp, 0, sizeof(cp));
> > + cp.enable = LE_SCAN_DISABLE;
> > + hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
> > +
> > + err = hci_req_run(&req, stop_scan_complete);
> > + } else {
> > + create_le_conn_req(&req, conn);
> > +
> > + err = hci_req_run(&req, create_le_conn_complete);
> > + }
>
> so I wonder why we not just add the disabling of the scan to the request right here. Our request queue will always fail on the first request and then do not execute the other ones. Especially when you have to send two requests this kind of request queue behavior is pretty nice.
That approach was implemented in some previous version of this patch
set. However, after some discussions with Johan (see "[RFC v4 05/12]
Bluetooth: Stop scanning on LE connection"), we realized that approach
is not good enough. Moreover, that approach makes harder to handle
discovery state properly in case of HCI command error (e.g. disable scan
command succeed but create LE connection command fails).
> I also think that this is currently a bit racy in error handling path. So you might want to check this in all cases. One other thing to consider is might be introducing helper for adding certain commands like disable LE scan if they are used more than once.
I rechecked the error handling paths and didn't find any obvious race
condition. Could you point me any suspicion so I can investigate?
Regarding the disable LE scan request helper, I think it makes sense.
I'll do this refactoring and add the patch to this patch set.
Regards,
Andre
^ permalink raw reply
* [PATCH BlueZ v6 18/18] bluetooth.conf: Add ObjectManager interface
From: Claudio Takahasi @ 2014-02-04 17:53 UTC (permalink / raw)
To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1391536429-8345-1-git-send-email-claudio.takahasi@openbossa.org>
---
src/bluetooth.conf | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/bluetooth.conf b/src/bluetooth.conf
index 0495200..ad8891a 100644
--- a/src/bluetooth.conf
+++ b/src/bluetooth.conf
@@ -18,6 +18,7 @@
<allow send_interface="org.bluez.Profile1"/>
<allow send_interface="org.bluez.HeartRateWatcher1"/>
<allow send_interface="org.bluez.CyclingSpeedWatcher1"/>
+ <allow send_interface="org.freedesktop.DBus.ObjectManager"/>
</policy>
<policy at_console="true">
--
1.8.3.1
^ permalink raw reply related
* [PATCH BlueZ v6 17/18] gatttool: Add unix socket support for interactive mode
From: Claudio Takahasi @ 2014-02-04 17:53 UTC (permalink / raw)
To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1391536429-8345-1-git-send-email-claudio.takahasi@openbossa.org>
This patch allows running GATT operations over unix socket on
interactive mode.
---
attrib/interactive.c | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)
diff --git a/attrib/interactive.c b/attrib/interactive.c
index 70c091c..67e060e 100644
--- a/attrib/interactive.c
+++ b/attrib/interactive.c
@@ -84,7 +84,7 @@ static char *get_prompt(void)
if (opt_dst)
g_string_append_printf(prompt, "[%17s]", opt_dst);
else
- g_string_append_printf(prompt, "[%17s]", "");
+ g_string_append_printf(prompt, "[LOCAL]");
if (conn_state == STATE_CONNECTED)
g_string_append(prompt, COLOR_OFF);
@@ -405,15 +405,18 @@ static void cmd_connect(int argcp, char **argvp)
opt_dst_type = g_strdup("public");
}
- if (opt_dst == NULL) {
- error("Remote Bluetooth address required\n");
- return;
+ if (opt_dst) {
+
+ rl_printf("Attempting to connect to %s\n", opt_dst);
+ set_state(STATE_CONNECTING);
+ iochannel = gatt_connect(opt_src, opt_dst, opt_dst_type,
+ opt_sec_level, opt_psm, opt_mtu,
+ connect_cb, &gerr);
+ } else {
+ rl_printf("Local connection\n");
+ iochannel = unix_connect(connect_cb, &gerr);
}
- rl_printf("Attempting to connect to %s\n", opt_dst);
- set_state(STATE_CONNECTING);
- iochannel = gatt_connect(opt_src, opt_dst, opt_dst_type, opt_sec_level,
- opt_psm, opt_mtu, connect_cb, &gerr);
if (iochannel == NULL) {
set_state(STATE_DISCONNECTED);
error("%s\n", gerr->message);
--
1.8.3.1
^ permalink raw reply related
* [PATCH BlueZ v6 16/18] gatttool: Add unix socket connect
From: Claudio Takahasi @ 2014-02-04 17:53 UTC (permalink / raw)
To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1391536429-8345-1-git-send-email-claudio.takahasi@openbossa.org>
This patch adds the initial support for GATT procedures over unix
socket transport on command line mode (one-shot command). Temporary
solution to allow local GATT procedures testing.
---
attrib/gatttool.c | 27 ++++++++++++++++++++-------
attrib/gatttool.h | 1 +
attrib/utils.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 75 insertions(+), 7 deletions(-)
diff --git a/attrib/gatttool.c b/attrib/gatttool.c
index 9f2ead9..cf106de 100644
--- a/attrib/gatttool.c
+++ b/attrib/gatttool.c
@@ -29,7 +29,6 @@
#include <errno.h>
#include <glib.h>
#include <stdlib.h>
-#include <unistd.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
@@ -53,6 +52,7 @@ static int opt_end = 0xffff;
static int opt_handle = -1;
static int opt_mtu = 0;
static int opt_psm = 0;
+static gboolean opt_local = FALSE;
static gboolean opt_primary = FALSE;
static gboolean opt_characteristics = FALSE;
static gboolean opt_char_read = FALSE;
@@ -511,6 +511,8 @@ static GOptionEntry options[] = {
"Specify local adapter interface", "hciX" },
{ "device", 'b', 0, G_OPTION_ARG_STRING, &opt_dst,
"Specify remote Bluetooth address", "MAC" },
+ { "local", 'L', 0, G_OPTION_ARG_NONE, &opt_local,
+ "Use unix socket transport (local communication)", NULL },
{ "addr-type", 't', 0, G_OPTION_ARG_STRING, &opt_dst_type,
"Set LE address type. Default: public", "[public | random]"},
{ "mtu", 'm', 0, G_OPTION_ARG_INT, &opt_mtu,
@@ -563,6 +565,11 @@ int main(int argc, char *argv[])
g_clear_error(&gerr);
}
+ if (opt_local) {
+ opt_src = NULL;
+ opt_dst = NULL;
+ }
+
if (opt_interactive) {
interactive(opt_src, opt_dst, opt_dst_type, opt_psm);
goto done;
@@ -588,14 +595,20 @@ int main(int argc, char *argv[])
goto done;
}
- if (opt_dst == NULL) {
- g_print("Remote Bluetooth address required\n");
- got_error = TRUE;
- goto done;
+ if (opt_local)
+ chan = unix_connect(connect_cb, &gerr);
+ else {
+ if (opt_dst == NULL) {
+ g_print("Remote Bluetooth address required\n");
+ got_error = TRUE;
+ goto done;
+ }
+
+ chan = gatt_connect(opt_src, opt_dst, opt_dst_type,
+ opt_sec_level, opt_psm, opt_mtu,
+ connect_cb, &gerr);
}
- chan = gatt_connect(opt_src, opt_dst, opt_dst_type, opt_sec_level,
- opt_psm, opt_mtu, connect_cb, &gerr);
if (chan == NULL) {
g_printerr("%s\n", gerr->message);
g_clear_error(&gerr);
diff --git a/attrib/gatttool.h b/attrib/gatttool.h
index 8f0913c..be8e236 100644
--- a/attrib/gatttool.h
+++ b/attrib/gatttool.h
@@ -27,4 +27,5 @@ GIOChannel *gatt_connect(const char *src, const char *dst,
const char *dst_type, const char *sec_level,
int psm, int mtu, BtIOConnect connect_cb,
GError **gerr);
+GIOChannel *unix_connect(BtIOConnect connect_cb, GError **gerr);
size_t gatt_attr_data_from_string(const char *str, uint8_t **data);
diff --git a/attrib/utils.c b/attrib/utils.c
index 17f02be..7d2966f 100644
--- a/attrib/utils.c
+++ b/attrib/utils.c
@@ -25,7 +25,12 @@
#include "config.h"
#endif
+#include <errno.h>
#include <stdlib.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
#include <glib.h>
#include <bluetooth/bluetooth.h>
@@ -101,6 +106,55 @@ GIOChannel *gatt_connect(const char *src, const char *dst,
return chan;
}
+static gboolean unix_connect_cb(GIOChannel *io, GIOCondition cond,
+ gpointer user_data)
+{
+ BtIOConnect connect_cb = user_data;
+ GError *gerr;
+
+ if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
+ gerr = g_error_new_literal(G_IO_CHANNEL_ERROR,
+ G_IO_CHANNEL_ERROR_FAILED,
+ "connection attempt failed");
+ connect_cb(io, gerr, user_data);
+ g_clear_error(&gerr);
+ } else {
+ connect_cb(io, NULL, user_data);
+ }
+
+ return FALSE;
+}
+
+GIOChannel *unix_connect(BtIOConnect connect_cb, GError **gerr)
+{
+ GIOChannel *io;
+ struct sockaddr_un uaddr = {
+ .sun_family = AF_UNIX,
+ .sun_path = "\0/bluetooth/unix_att",
+ };
+ int sk;
+
+ sk = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC , 0);
+ if (sk < 0) {
+ g_set_error_literal(gerr, G_IO_CHANNEL_ERROR,
+ G_IO_CHANNEL_ERROR_FAILED, strerror(errno));
+ return NULL;
+ }
+
+ if (connect(sk, (struct sockaddr *) &uaddr, sizeof(uaddr)) < 0) {
+ g_set_error_literal(gerr, G_IO_CHANNEL_ERROR,
+ G_IO_CHANNEL_ERROR_FAILED, strerror(errno));
+ close(sk);
+ return NULL;
+ }
+
+ io = g_io_channel_unix_new(sk);
+ g_io_add_watch(io, G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ unix_connect_cb, connect_cb);
+
+ return io;
+}
+
size_t gatt_attr_data_from_string(const char *str, uint8_t **data)
{
char tmp[3];
--
1.8.3.1
^ permalink raw reply related
* [PATCH BlueZ v6 15/18] test: Add registering external service
From: Claudio Takahasi @ 2014-02-04 17:53 UTC (permalink / raw)
To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1391536429-8345-1-git-send-email-claudio.takahasi@openbossa.org>
This patch extends gatt-service to call RegisterService() when org.bluez
service gets connected to the system bus.
---
test/gatt-service.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 67 insertions(+)
diff --git a/test/gatt-service.c b/test/gatt-service.c
index 4059336..b656ef3 100644
--- a/test/gatt-service.c
+++ b/test/gatt-service.c
@@ -35,6 +35,7 @@
#include <dbus/dbus.h>
#include <gdbus/gdbus.h>
+#define GATT_MGR_IFACE "org.bluez.GattManager1"
#define SERVICE_IFACE "org.bluez.GattService1"
/* Immediate Alert Service UUID */
@@ -100,6 +101,65 @@ static void create_services(DBusConnection *conn)
printf("Registered service: %s\n", service_path);
}
+static void register_external_service_reply(DBusPendingCall *call,
+ void *user_data)
+{
+ DBusMessage *reply = dbus_pending_call_steal_reply(call);
+ DBusError derr;
+
+ dbus_error_init(&derr);
+ dbus_set_error_from_message(&derr, reply);
+
+ if (dbus_error_is_set(&derr))
+ printf("RegisterService: %s\n", derr.message);
+ else
+ printf("RegisterService: OK\n");
+
+ dbus_message_unref(reply);
+ dbus_error_free(&derr);
+}
+
+static void register_external_service(gpointer a, gpointer b)
+{
+ DBusConnection *conn = b;
+ const char *path = a;
+ DBusMessage *msg;
+ DBusPendingCall *call;
+ DBusMessageIter iter, dict;
+
+ msg = dbus_message_new_method_call("org.bluez", "/org/bluez",
+ GATT_MGR_IFACE, "RegisterService");
+ if (msg == NULL) {
+ printf("Couldn't allocate D-Bus message\n");
+ return;
+ }
+
+ dbus_message_iter_init_append(msg, &iter);
+
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &dict);
+
+ /* TODO: Add options dictionary */
+
+ dbus_message_iter_close_container(&iter, &dict);
+
+ if (g_dbus_send_message_with_reply(conn, msg, &call, -1) == FALSE) {
+ dbus_message_unref(msg);
+ return;
+ }
+
+ dbus_pending_call_set_notify(call, register_external_service_reply,
+ NULL, NULL);
+
+ dbus_pending_call_unref(call);
+}
+
+static void connect_handler(DBusConnection *conn, void *user_data)
+{
+ g_slist_foreach(services, register_external_service, conn);
+}
+
static gboolean signal_handler(GIOChannel *channel, GIOCondition cond,
gpointer user_data)
{
@@ -171,6 +231,7 @@ static guint setup_signalfd(void)
int main(int argc, char *argv[])
{
+ GDBusClient *client;
DBusConnection *dbus_conn;
guint signal;
@@ -189,8 +250,14 @@ int main(int argc, char *argv[])
create_services(dbus_conn);
+ client = g_dbus_client_new(dbus_conn, "org.bluez", "/org/bluez");
+
+ g_dbus_client_set_connect_watch(client, connect_handler, NULL);
+
g_main_loop_run(main_loop);
+ g_dbus_client_unref(client);
+
g_source_remove(signal);
g_slist_free_full(services, g_free);
--
1.8.3.1
^ permalink raw reply related
* [PATCH BlueZ v6 14/18] test: Add signal handling for gatt-service
From: Claudio Takahasi @ 2014-02-04 17:53 UTC (permalink / raw)
To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1391536429-8345-1-git-send-email-claudio.takahasi@openbossa.org>
This patch implements signal handling to run cleanup tasks before
exiting.
---
test/gatt-service.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 79 insertions(+)
diff --git a/test/gatt-service.c b/test/gatt-service.c
index 769fd37..4059336 100644
--- a/test/gatt-service.c
+++ b/test/gatt-service.c
@@ -27,6 +27,9 @@
#include <errno.h>
#include <stdio.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <sys/signalfd.h>
#include <glib.h>
#include <dbus/dbus.h>
@@ -97,9 +100,83 @@ static void create_services(DBusConnection *conn)
printf("Registered service: %s\n", service_path);
}
+static gboolean signal_handler(GIOChannel *channel, GIOCondition cond,
+ gpointer user_data)
+{
+ static bool __terminated = false;
+ struct signalfd_siginfo si;
+ ssize_t result;
+ int fd;
+
+ if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP))
+ return FALSE;
+
+ fd = g_io_channel_unix_get_fd(channel);
+
+ result = read(fd, &si, sizeof(si));
+ if (result != sizeof(si))
+ return FALSE;
+
+ switch (si.ssi_signo) {
+ case SIGINT:
+ case SIGTERM:
+ if (!__terminated) {
+ printf("Terminating\n");
+ g_main_loop_quit(main_loop);
+ }
+
+ __terminated = true;
+ break;
+ }
+
+ return TRUE;
+}
+
+static guint setup_signalfd(void)
+{
+ GIOChannel *channel;
+ guint source;
+ sigset_t mask;
+ int fd;
+
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGINT);
+ sigaddset(&mask, SIGTERM);
+
+ if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
+ perror("Failed to set signal mask");
+ return 0;
+ }
+
+ fd = signalfd(-1, &mask, 0);
+ if (fd < 0) {
+ perror("Failed to create signal descriptor");
+ return 0;
+ }
+
+ channel = g_io_channel_unix_new(fd);
+
+ g_io_channel_set_close_on_unref(channel, TRUE);
+ g_io_channel_set_encoding(channel, NULL, NULL);
+ g_io_channel_set_buffered(channel, FALSE);
+
+ source = g_io_add_watch(channel,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ signal_handler, NULL);
+
+ g_io_channel_unref(channel);
+
+ return source;
+}
+
int main(int argc, char *argv[])
{
DBusConnection *dbus_conn;
+ guint signal;
+
+ signal = setup_signalfd();
+ if (signal == 0)
+ return -errno;
dbus_conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
@@ -114,6 +191,8 @@ int main(int argc, char *argv[])
g_main_loop_run(main_loop);
+ g_source_remove(signal);
+
g_slist_free_full(services, g_free);
dbus_connection_unref(dbus_conn);
--
1.8.3.1
^ permalink raw reply related
* [PATCH BlueZ v6 13/18] gitignore: Add test/gatt-service
From: Claudio Takahasi @ 2014-02-04 17:53 UTC (permalink / raw)
To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1391536429-8345-1-git-send-email-claudio.takahasi@openbossa.org>
---
.gitignore | 1 +
1 file changed, 1 insertion(+)
diff --git a/.gitignore b/.gitignore
index b86deae..3f3c7d4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -75,6 +75,7 @@ test/sap_client.pyc
test/bluezutils.pyc
unit/test-ringbuf
unit/test-queue
+test/gatt-service
unit/test-eir
unit/test-uuid
unit/test-crc
--
1.8.3.1
^ permalink raw reply related
* [PATCH BlueZ v6 12/18] test: Add external service GATT skeleton
From: Claudio Takahasi @ 2014-02-04 17:53 UTC (permalink / raw)
To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1391536429-8345-1-git-send-email-claudio.takahasi@openbossa.org>
This patch adds the initial code for an external GATT service example.
It implements the API defined at doc/gatt-api.txt
---
Makefile.tools | 5 +++
test/gatt-service.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 126 insertions(+)
create mode 100644 test/gatt-service.c
diff --git a/Makefile.tools b/Makefile.tools
index 9199222..a468272 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -374,3 +374,8 @@ test_scripts += test/sap_client.py test/bluezutils.py \
test/test-heartrate test/test-alert test/test-hfp \
test/test-cyclingspeed test/opp-client test/ftp-client \
test/pbap-client test/map-client
+
+noinst_PROGRAMS += test/gatt-service
+
+test_gatt_service_SOURCES = test/gatt-service.c
+test_gatt_service_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ gdbus/libgdbus-internal.la
diff --git a/test/gatt-service.c b/test/gatt-service.c
new file mode 100644
index 0000000..769fd37
--- /dev/null
+++ b/test/gatt-service.c
@@ -0,0 +1,121 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2013 Instituto Nokia de Tecnologia - INdT
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <gdbus/gdbus.h>
+
+#define SERVICE_IFACE "org.bluez.GattService1"
+
+/* Immediate Alert Service UUID */
+#define IAS_UUID "00001802-0000-1000-8000-00805f9b34fb"
+
+static GMainLoop *main_loop;
+static GSList *services;
+
+static gboolean service_get_uuid(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *user_data)
+{
+ const char *uuid = user_data;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &uuid);
+
+ return TRUE;
+}
+
+static gboolean service_get_includes(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *user_data)
+{
+ return TRUE;
+}
+
+static gboolean service_exist_includes(const GDBusPropertyTable *property,
+ void *user_data)
+{
+ return FALSE;
+}
+
+static const GDBusPropertyTable service_properties[] = {
+ { "UUID", "s", service_get_uuid },
+ { "Includes", "ao", service_get_includes, NULL,
+ service_exist_includes },
+ { }
+};
+
+static char *register_service(DBusConnection *conn, const char *uuid)
+{
+ static int id = 1;
+ char *path;
+
+ path = g_strdup_printf("/service%d", id++);
+ if (g_dbus_register_interface(conn, path, SERVICE_IFACE,
+ NULL, NULL, service_properties,
+ g_strdup(uuid), g_free) == FALSE) {
+ printf("Couldn't register service interface\n");
+ g_free(path);
+ return NULL;
+ }
+
+ return path;
+}
+
+static void create_services(DBusConnection *conn)
+{
+ char *service_path;
+
+ service_path = register_service(conn, IAS_UUID);
+
+ services = g_slist_prepend(services, service_path);
+
+ printf("Registered service: %s\n", service_path);
+}
+
+int main(int argc, char *argv[])
+{
+ DBusConnection *dbus_conn;
+
+ dbus_conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
+
+ main_loop = g_main_loop_new(NULL, FALSE);
+
+ g_dbus_attach_object_manager(dbus_conn);
+
+ printf("gatt-service unique name: %s\n",
+ dbus_bus_get_unique_name(dbus_conn));
+
+ create_services(dbus_conn);
+
+ g_main_loop_run(main_loop);
+
+ g_slist_free_full(services, g_free);
+ dbus_connection_unref(dbus_conn);
+
+ return 0;
+}
--
1.8.3.1
^ permalink raw reply related
* [PATCH BlueZ v6 11/18] gatt: Add Discover All Primary Services
From: Claudio Takahasi @ 2014-02-04 17:53 UTC (permalink / raw)
To: linux-bluetooth; +Cc: claudio.takahasi, Alvaro Silva
In-Reply-To: <1391536429-8345-1-git-send-email-claudio.takahasi@openbossa.org>
From: Alvaro Silva <alvaro.silva@openbossa.org>
This patch adds ATT Read By Group request handling to the attribute
server. It is the primitive to implement Discover All Primary Services
procedure.
---
src/gatt.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 128 insertions(+), 1 deletion(-)
diff --git a/src/gatt.c b/src/gatt.c
index ec8f381..f00f52a 100644
--- a/src/gatt.c
+++ b/src/gatt.c
@@ -114,6 +114,130 @@ static void send_error(int sk, uint8_t opcode, uint16_t handle, uint8_t ecode)
write_pdu(sk, pdu, plen);
}
+static void read_by_group_resp(int sk, uint16_t start,
+ uint16_t end, bt_uuid_t *pattern)
+{
+ uint8_t opdu[ATT_DEFAULT_LE_MTU];
+ GList *list;
+ struct btd_attribute *last = NULL;
+ uint8_t *group_start, *group_end = NULL, *group_uuid;
+ unsigned int uuid_type = BT_UUID_UNSPEC;
+ size_t group_len = 0, plen = 0;
+
+ /*
+ * Read By Group Type Response format:
+ * Attribute Opcode: 1 byte
+ * Length: 1 byte (size of each group)
+ * Group: start | end | <<UUID>>
+ */
+
+ opdu[0] = ATT_OP_READ_BY_GROUP_RESP;
+ group_start = &opdu[2];
+ group_uuid = &opdu[6];
+
+ for (list = local_attribute_db; list;
+ last = list->data, list = g_list_next(list)) {
+ struct btd_attribute *attr = list->data;
+
+ if (attr->handle < start)
+ continue;
+
+ if (attr->handle > end)
+ break;
+
+ if (bt_uuid_cmp(&attr->type, pattern) != 0)
+ continue;
+
+ if (uuid_type != BT_UUID_UNSPEC &&
+ uuid_type != attr->type.type) {
+ /*
+ * Groups should contain the same length: UUID16 and
+ * UUID128 should be sent on different ATT PDUs
+ */
+ break;
+ }
+
+ /*
+ * MTU checking should not be shifted up, otherwise the
+ * handle of last end group will not be set properly.
+ */
+ if ((plen + group_len) >= ATT_DEFAULT_LE_MTU)
+ break;
+
+ /* Start Grouping handle */
+ att_put_u16(attr->handle, group_start);
+
+ /* Grouping <<UUID>>: Value is little endian */
+ memcpy(group_uuid, attr->value, attr->value_len);
+
+ if (last && group_end) {
+ att_put_u16(last->handle, group_end);
+ group_end += group_len;
+ plen += group_len;
+ }
+
+ /* Grouping initial settings: First grouping */
+ if (uuid_type == BT_UUID_UNSPEC) {
+ uuid_type = attr->type.type;
+
+ /* start(0xXXXX) | end(0xXXXX) | <<UUID>> */
+ group_len = 2 + 2 + bt_uuid_len(&attr->type);
+
+ /* 2: ATT Opcode and Length */
+ plen = 2 + group_len;
+
+ /* Size of each Attribute Data */
+ opdu[1] = group_len;
+
+ group_end = &opdu[4];
+ }
+
+ group_start += group_len;
+ group_uuid += group_len;
+ }
+
+ if (plen == 0) {
+ send_error(sk, ATT_OP_READ_BY_GROUP_REQ, start,
+ ATT_ECODE_ATTR_NOT_FOUND);
+ return;
+ }
+
+ if (group_end)
+ att_put_u16(last->handle, group_end);
+
+ write_pdu(sk, opdu, plen);
+}
+
+static void read_by_group(int sk, const uint8_t *ipdu, ssize_t ilen)
+{
+ uint16_t decoded, start, end;
+ bt_uuid_t pattern;
+
+ decoded = dec_read_by_grp_req(ipdu, ilen, &start, &end, &pattern);
+ if (decoded == 0) {
+ send_error(sk, ipdu[0], 0x0000, ATT_ECODE_INVALID_PDU);
+ return;
+ }
+
+ if (start > end || start == 0x0000) {
+ send_error(sk, ipdu[0], start, ATT_ECODE_INVALID_HANDLE);
+ return;
+ }
+
+ /*
+ * Restricting Read By Group Type to <<Primary>>.
+ * Removing the checking below requires changes to support
+ * dynamic values(defined in the upper layer) and additional
+ * security verification.
+ */
+ if (bt_uuid_cmp(&pattern, &primary_uuid) != 0) {
+ send_error(sk, ipdu[0], start, ATT_ECODE_UNSUPP_GRP_TYPE);
+ return;
+ }
+
+ read_by_group_resp(sk, start, end, &pattern);
+}
+
static bool channel_handler_cb(struct io *io, void *user_data)
{
uint8_t ipdu[ATT_DEFAULT_LE_MTU];
@@ -143,11 +267,14 @@ static bool channel_handler_cb(struct io *io, void *user_data)
case ATT_OP_READ_MULTI_REQ:
case ATT_OP_PREP_WRITE_REQ:
case ATT_OP_EXEC_WRITE_REQ:
- case ATT_OP_READ_BY_GROUP_REQ:
case ATT_OP_SIGNED_WRITE_CMD:
send_error(sk, ipdu[0], 0x0000, ATT_ECODE_REQ_NOT_SUPP);
break;
+ case ATT_OP_READ_BY_GROUP_REQ:
+ read_by_group(sk, ipdu, ilen);
+ break;
+
/* Responses */
case ATT_OP_MTU_RESP:
case ATT_OP_FIND_INFO_RESP:
--
1.8.3.1
^ permalink raw reply related
* [PATCH BlueZ v6 10/18] gatt: Register ATT command/event handler
From: Claudio Takahasi @ 2014-02-04 17:53 UTC (permalink / raw)
To: linux-bluetooth; +Cc: claudio.takahasi, Alvaro Silva
In-Reply-To: <1391536429-8345-1-git-send-email-claudio.takahasi@openbossa.org>
From: Alvaro Silva <alvaro.silva@openbossa.org>
This patch registers the ATT channel handler to manage incoming ATT
commands and events.
---
src/gatt.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 89 insertions(+), 2 deletions(-)
diff --git a/src/gatt.c b/src/gatt.c
index 7a595c6..ec8f381 100644
--- a/src/gatt.c
+++ b/src/gatt.c
@@ -55,6 +55,13 @@ static struct io *server_io;
static GList *local_attribute_db;
static uint16_t next_handle = 0x0001;
+static void write_pdu(int sk, const uint8_t *pdu, size_t plen)
+{
+ if (write(sk, pdu, plen) < 0)
+ error("Error sending ATT PDU (0x%02X): %s (%d)", pdu[0],
+ strerror(errno), errno);
+}
+
static int local_database_add(uint16_t handle, struct btd_attribute *attr)
{
attr->handle = handle;
@@ -98,10 +105,85 @@ struct btd_attribute *btd_gatt_add_service(const bt_uuid_t *uuid)
return attr;
}
+static void send_error(int sk, uint8_t opcode, uint16_t handle, uint8_t ecode)
+{
+ uint8_t pdu[ATT_DEFAULT_LE_MTU];
+ size_t plen;
+
+ plen = enc_error_resp(opcode, handle, ecode, pdu, sizeof(pdu));
+ write_pdu(sk, pdu, plen);
+}
+
+static bool channel_handler_cb(struct io *io, void *user_data)
+{
+ uint8_t ipdu[ATT_DEFAULT_LE_MTU];
+ ssize_t ilen;
+ int sk = io_get_fd(io);
+
+ ilen = read(sk, ipdu, sizeof(ipdu));
+ if (ilen < 0) {
+ int err = errno;
+ DBG("ATT channel read: %s(%d)", strerror(err), err);
+ return false;
+ }
+
+ switch (ipdu[0]) {
+ case ATT_OP_ERROR:
+ break;
+
+ /* Requests */
+ case ATT_OP_WRITE_CMD:
+ case ATT_OP_WRITE_REQ:
+ case ATT_OP_READ_REQ:
+ case ATT_OP_READ_BY_TYPE_REQ:
+ case ATT_OP_MTU_REQ:
+ case ATT_OP_FIND_INFO_REQ:
+ case ATT_OP_FIND_BY_TYPE_REQ:
+ case ATT_OP_READ_BLOB_REQ:
+ case ATT_OP_READ_MULTI_REQ:
+ case ATT_OP_PREP_WRITE_REQ:
+ case ATT_OP_EXEC_WRITE_REQ:
+ case ATT_OP_READ_BY_GROUP_REQ:
+ case ATT_OP_SIGNED_WRITE_CMD:
+ send_error(sk, ipdu[0], 0x0000, ATT_ECODE_REQ_NOT_SUPP);
+ break;
+
+ /* Responses */
+ case ATT_OP_MTU_RESP:
+ case ATT_OP_FIND_INFO_RESP:
+ case ATT_OP_FIND_BY_TYPE_RESP:
+ case ATT_OP_READ_BY_TYPE_RESP:
+ case ATT_OP_READ_RESP:
+ case ATT_OP_READ_BLOB_RESP:
+ case ATT_OP_READ_MULTI_RESP:
+ case ATT_OP_READ_BY_GROUP_RESP:
+ case ATT_OP_WRITE_RESP:
+ case ATT_OP_PREP_WRITE_RESP:
+ case ATT_OP_EXEC_WRITE_RESP:
+ case ATT_OP_HANDLE_CNF:
+ break;
+
+ /* Notification & Indication */
+ case ATT_OP_HANDLE_NOTIFY:
+ case ATT_OP_HANDLE_IND:
+ break;
+ }
+
+ return true;
+}
+
+static void channel_watch_destroy(void *user_data)
+{
+ struct io *io = user_data;
+
+ io_destroy(io);
+}
+
static bool unix_accept_cb(struct io *io, void *user_data)
{
struct sockaddr_un uaddr;
socklen_t len = sizeof(uaddr);
+ struct io *nio;
int err, nsk, sk;
sk = io_get_fd(io);
@@ -110,12 +192,17 @@ static bool unix_accept_cb(struct io *io, void *user_data)
if (nsk < 0) {
err = errno;
error("ATT UNIX socket accept: %s(%d)", strerror(err), err);
- return TRUE;
+ return true;
}
DBG("ATT UNIX socket: %d", nsk);
+ nio = io_new(nsk);
+
+ io_set_close_on_destroy(nio, true);
+ io_set_read_handler(nio, channel_handler_cb, nio,
+ channel_watch_destroy);
- return TRUE;
+ return true;
}
void gatt_init(void)
--
1.8.3.1
^ permalink raw reply related
* [PATCH BlueZ v6 09/18] gattrib: Use default ATT LE MTU for non-standard sockets
From: Claudio Takahasi @ 2014-02-04 17:53 UTC (permalink / raw)
To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1391536429-8345-1-git-send-email-claudio.takahasi@openbossa.org>
This patch forces the MTU to 23 (default ATT MTU) if the transport
is not Bluetooth. This is a development purpose change to allow
testing GATT procedures over non-Bluetooth sockets.
---
attrib/gattrib.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/attrib/gattrib.c b/attrib/gattrib.c
index daf6312..b5b8529 100644
--- a/attrib/gattrib.c
+++ b/attrib/gattrib.c
@@ -468,18 +468,18 @@ GAttrib *g_attrib_new(GIOChannel *io)
struct _GAttrib *attrib;
uint16_t imtu;
uint16_t att_mtu;
- uint16_t cid;
- GError *gerr = NULL;
+ uint16_t cid = 0;
g_io_channel_set_encoding(io, NULL, NULL);
g_io_channel_set_buffered(io, FALSE);
- bt_io_get(io, &gerr, BT_IO_OPT_IMTU, &imtu,
- BT_IO_OPT_CID, &cid, BT_IO_OPT_INVALID);
- if (gerr) {
- error("%s", gerr->message);
- g_error_free(gerr);
- return NULL;
+ if (bt_io_get(io, NULL, BT_IO_OPT_IMTU, &imtu, BT_IO_OPT_CID, &cid,
+ BT_IO_OPT_INVALID) == FALSE) {
+ /*
+ * Use default ATT LE MTU for non-standard transports. Used
+ * for testing purpose only. eg: Unix sockets
+ */
+ imtu = ATT_DEFAULT_LE_MTU;
}
attrib = g_try_new0(struct _GAttrib, 1);
--
1.8.3.1
^ permalink raw reply related
* [PATCH BlueZ v6 08/18] gatt: Add server unix socket
From: Claudio Takahasi @ 2014-02-04 17:53 UTC (permalink / raw)
To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1391536429-8345-1-git-send-email-claudio.takahasi@openbossa.org>
This patch adds a server unix socket to handle local ATT traffic. This
is a development purpose feature used to allow local testing without
breaking the current attribute server.
---
src/gatt.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 59 insertions(+)
diff --git a/src/gatt.c b/src/gatt.c
index f7b74d6..7a595c6 100644
--- a/src/gatt.c
+++ b/src/gatt.c
@@ -25,11 +25,17 @@
#include <config.h>
#endif
+#include <unistd.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
#include <glib.h>
#include "log.h"
#include "lib/uuid.h"
#include "attrib/att.h"
+#include "src/shared/io.h"
#include "gatt-dbus.h"
#include "gatt.h"
@@ -45,6 +51,7 @@ struct btd_attribute {
uint8_t value[0];
};
+static struct io *server_io;
static GList *local_attribute_db;
static uint16_t next_handle = 0x0001;
@@ -91,11 +98,62 @@ struct btd_attribute *btd_gatt_add_service(const bt_uuid_t *uuid)
return attr;
}
+static bool unix_accept_cb(struct io *io, void *user_data)
+{
+ struct sockaddr_un uaddr;
+ socklen_t len = sizeof(uaddr);
+ int err, nsk, sk;
+
+ sk = io_get_fd(io);
+
+ nsk = accept(sk, (struct sockaddr *) &uaddr, &len);
+ if (nsk < 0) {
+ err = errno;
+ error("ATT UNIX socket accept: %s(%d)", strerror(err), err);
+ return TRUE;
+ }
+
+ DBG("ATT UNIX socket: %d", nsk);
+
+ return TRUE;
+}
+
void gatt_init(void)
{
+ struct sockaddr_un uaddr = {
+ .sun_family = AF_UNIX,
+ .sun_path = "\0/bluetooth/unix_att",
+ };
+ int sk, err;
+
DBG("Starting GATT server");
gatt_dbus_manager_register();
+
+ sk = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC , 0);
+ if (sk < 0) {
+ err = errno;
+ error("ATT UNIX socket: %s(%d)", strerror(err), err);
+ return;
+ }
+
+ if (bind(sk, (struct sockaddr *) &uaddr, sizeof(uaddr)) < 0) {
+ err = errno;
+ error("binding ATT UNIX socket: %s(%d)", strerror(err), err);
+ close(sk);
+ return;
+ }
+
+ if (listen(sk, 5) < 0) {
+ err = errno;
+ error("listen ATT UNIX socket: %s(%d)", strerror(err), err);
+ close(sk);
+ return;
+ }
+
+ server_io = io_new(sk);
+ io_set_close_on_destroy(server_io, true);
+ io_set_read_handler(server_io, unix_accept_cb, NULL, NULL);
}
void gatt_cleanup(void)
@@ -103,4 +161,5 @@ void gatt_cleanup(void)
DBG("Stopping GATT server");
gatt_dbus_manager_unregister();
+ io_destroy(server_io);
}
--
1.8.3.1
^ permalink raw reply related
* [PATCH BlueZ v6 07/18] gatt: Add external services tracking
From: Claudio Takahasi @ 2014-02-04 17:53 UTC (permalink / raw)
To: linux-bluetooth; +Cc: claudio.takahasi, Alvaro Silva
In-Reply-To: <1391536429-8345-1-git-send-email-claudio.takahasi@openbossa.org>
From: Alvaro Silva <alvaro.silva@openbossa.org>
All primary services declarations provided by an external application
will be automatically inserted in the attribute database.
---
src/gatt-dbus.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 109 insertions(+)
diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
index fd614f9..000d7ae 100644
--- a/src/gatt-dbus.c
+++ b/src/gatt-dbus.c
@@ -39,15 +39,21 @@
#include "log.h"
#include "error.h"
+#include "gatt.h"
#include "gatt-dbus.h"
#define GATT_MGR_IFACE "org.bluez.GattManager1"
+#define SERVICE_IFACE "org.bluez.GattService1"
+
+#define REGISTER_TIMER 1
struct external_app {
char *owner;
char *path;
GDBusClient *client;
+ GSList *proxies;
unsigned int watch;
+ guint register_timer;
};
static GSList *external_apps;
@@ -60,6 +66,36 @@ static int external_app_path_cmp(gconstpointer a, gconstpointer b)
return g_strcmp0(eapp->path, path);
}
+static void proxy_added(GDBusProxy *proxy, void *user_data)
+{
+ struct external_app *eapp = user_data;
+ const char *interface, *path;
+
+ interface = g_dbus_proxy_get_interface(proxy);
+ path = g_dbus_proxy_get_path(proxy);
+
+ DBG("path %s iface %s", path, interface);
+
+ if (g_strcmp0(interface, SERVICE_IFACE) != 0)
+ return;
+
+ eapp->proxies = g_slist_append(eapp->proxies, proxy);
+}
+
+static void proxy_removed(GDBusProxy *proxy, void *user_data)
+{
+ struct external_app *eapp = user_data;
+ const char *interface, *path;
+
+ interface = g_dbus_proxy_get_interface(proxy);
+ path = g_dbus_proxy_get_path(proxy);
+
+ DBG("path %s iface %s", path, interface);
+
+ eapp->proxies = g_slist_remove(eapp->proxies, proxy);
+}
+
+
static void external_app_watch_destroy(gpointer user_data)
{
struct external_app *eapp = user_data;
@@ -70,6 +106,9 @@ static void external_app_watch_destroy(gpointer user_data)
g_dbus_client_unref(eapp->client);
+ if (eapp->register_timer)
+ g_source_remove(eapp->register_timer);
+
g_free(eapp->owner);
g_free(eapp->path);
g_free(eapp);
@@ -99,9 +138,75 @@ static struct external_app *new_external_app(DBusConnection *conn,
eapp->client = client;
eapp->path = g_strdup(path);
+ g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed,
+ NULL, eapp);
+
return eapp;
}
+static int register_external_service(GDBusProxy *proxy)
+{
+ DBusMessageIter iter;
+ const char *uuid;
+ bt_uuid_t btuuid;
+
+ if (!g_dbus_proxy_get_property(proxy, "UUID", &iter))
+ return -EINVAL;
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ return -EINVAL;
+
+ dbus_message_iter_get_basic(&iter, &uuid);
+
+ if (bt_string_to_uuid(&btuuid, uuid) < 0)
+ return -EINVAL;
+
+ if (btd_gatt_add_service(&btuuid) == NULL)
+ return -EINVAL;
+
+ return 0;
+}
+
+static gboolean finish_register(gpointer user_data)
+{
+ struct external_app *eapp = user_data;
+ GSList *list;
+
+ /*
+ * It is not possible to detect when the last proxy object
+ * was reported. "Proxy added" handler reports objects
+ * added on demand or returned by GetManagedObjects().
+ * This timer helps to register all the GATT declarations
+ * (services, characteristics and descriptors) after fetching
+ * all the D-Bus objects.
+ */
+
+ eapp->register_timer = 0;
+
+ for (list = eapp->proxies; list; list = g_slist_next(list)) {
+ const char *interface, *path;
+ GDBusProxy *proxy = list->data;
+
+ interface = g_dbus_proxy_get_interface(proxy);
+ path = g_dbus_proxy_get_path(proxy);
+
+ if (g_strcmp0(SERVICE_IFACE, interface) != 0)
+ continue;
+
+ if (g_strcmp0(path, eapp->path) != 0)
+ continue;
+
+ if (register_external_service(proxy) < 0) {
+ DBG("Inconsistent external service: %s", path);
+ continue;
+ }
+
+ DBG("External service: %s", path);
+ }
+
+ return FALSE;
+}
+
static DBusMessage *register_service(DBusConnection *conn,
DBusMessage *msg, void *user_data)
{
@@ -109,6 +214,8 @@ static DBusMessage *register_service(DBusConnection *conn,
DBusMessageIter iter;
const char *path;
+ DBG("Registering GATT Service");
+
if (!dbus_message_iter_init(msg, &iter))
return btd_error_invalid_args(msg);
@@ -127,6 +234,8 @@ static DBusMessage *register_service(DBusConnection *conn,
external_apps = g_slist_prepend(external_apps, eapp);
DBG("New app %p: %s", eapp, path);
+ eapp->register_timer = g_timeout_add_seconds(REGISTER_TIMER,
+ finish_register, eapp);
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
}
--
1.8.3.1
^ permalink raw reply related
* [PATCH BlueZ v6 06/18] gatt: Add helper for creating GATT services
From: Claudio Takahasi @ 2014-02-04 17:53 UTC (permalink / raw)
To: linux-bluetooth; +Cc: claudio.takahasi, Andre Guedes
In-Reply-To: <1391536429-8345-1-git-send-email-claudio.takahasi@openbossa.org>
From: Andre Guedes <andre.guedes@openbossa.org>
This patch adds the btd_gatt_add_service() helper which adds a
GATT Service declaration to the local attribute database.
---
lib/uuid.h | 5 +++++
src/gatt.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/gatt.h | 10 ++++++++++
3 files changed, 74 insertions(+)
diff --git a/lib/uuid.h b/lib/uuid.h
index c24cee5..237145b 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -158,6 +158,11 @@ void bt_uuid_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst);
int bt_uuid_to_string(const bt_uuid_t *uuid, char *str, size_t n);
int bt_string_to_uuid(bt_uuid_t *uuid, const char *string);
+static inline int bt_uuid_len(const bt_uuid_t *uuid)
+{
+ return uuid->type / 8;
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/src/gatt.c b/src/gatt.c
index e8b691a..f7b74d6 100644
--- a/src/gatt.c
+++ b/src/gatt.c
@@ -28,10 +28,69 @@
#include <glib.h>
#include "log.h"
+#include "lib/uuid.h"
+#include "attrib/att.h"
#include "gatt-dbus.h"
#include "gatt.h"
+/* Common GATT UUIDs */
+static const bt_uuid_t primary_uuid = { .type = BT_UUID16,
+ .value.u16 = GATT_PRIM_SVC_UUID };
+
+struct btd_attribute {
+ uint16_t handle;
+ bt_uuid_t type;
+ uint16_t value_len;
+ uint8_t value[0];
+};
+
+static GList *local_attribute_db;
+static uint16_t next_handle = 0x0001;
+
+static int local_database_add(uint16_t handle, struct btd_attribute *attr)
+{
+ attr->handle = handle;
+
+ local_attribute_db = g_list_append(local_attribute_db, attr);
+
+ return 0;
+}
+
+struct btd_attribute *btd_gatt_add_service(const bt_uuid_t *uuid)
+{
+ uint16_t len = bt_uuid_len(uuid);
+ struct btd_attribute *attr = g_malloc0(sizeof(struct btd_attribute) +
+ len);
+
+ /*
+ * Service DECLARATION
+ *
+ * TYPE ATTRIBUTE VALUE
+ * +-------+---------------------------------+
+ * |0x2800 | 0xYYYY... |
+ * | (1) | (2) |
+ * +------+----------------------------------+
+ * (1) - 2 octets: Primary/Secondary Service UUID
+ * (2) - 2 or 16 octets: Service UUID
+ */
+
+ attr->type = primary_uuid;
+
+ att_put_uuid(*uuid, attr->value);
+ attr->value_len = len;
+
+ if (local_database_add(next_handle, attr) < 0) {
+ g_free(attr);
+ return NULL;
+ }
+
+ /* TODO: missing overflow checking */
+ next_handle = next_handle + 1;
+
+ return attr;
+}
+
void gatt_init(void)
{
DBG("Starting GATT server");
diff --git a/src/gatt.h b/src/gatt.h
index 3a320b4..8dd1312 100644
--- a/src/gatt.h
+++ b/src/gatt.h
@@ -21,6 +21,16 @@
*
*/
+struct btd_attribute;
+
void gatt_init(void);
void gatt_cleanup(void);
+
+/* btd_gatt_add_service - Add a service declaration to local attribute database.
+ * @uuid: Service UUID.
+ *
+ * Returns a reference to service declaration attribute. In case of error,
+ * NULL is returned.
+ */
+struct btd_attribute *btd_gatt_add_service(const bt_uuid_t *uuid);
--
1.8.3.1
^ permalink raw reply related
* [PATCH BlueZ v6 05/18] lib: Move GATT UUID to uuid.h
From: Claudio Takahasi @ 2014-02-04 17:53 UTC (permalink / raw)
To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1391536429-8345-1-git-send-email-claudio.takahasi@openbossa.org>
This patch moves GATT UUIDs definitions to a common header. uuid.h contains
helper functions to manipulate Bluetooth UUIDs and some common BR/EDR services
UUIDs.
---
attrib/gatt.h | 25 -------------------------
lib/uuid.h | 25 +++++++++++++++++++++++++
2 files changed, 25 insertions(+), 25 deletions(-)
diff --git a/attrib/gatt.h b/attrib/gatt.h
index 0f113e7..4fea3eb 100644
--- a/attrib/gatt.h
+++ b/attrib/gatt.h
@@ -24,31 +24,6 @@
#include <bluetooth/sdp.h>
-/* GATT Profile Attribute types */
-#define GATT_PRIM_SVC_UUID 0x2800
-#define GATT_SND_SVC_UUID 0x2801
-#define GATT_INCLUDE_UUID 0x2802
-#define GATT_CHARAC_UUID 0x2803
-
-/* GATT Characteristic Types */
-#define GATT_CHARAC_DEVICE_NAME 0x2A00
-#define GATT_CHARAC_APPEARANCE 0x2A01
-#define GATT_CHARAC_PERIPHERAL_PRIV_FLAG 0x2A02
-#define GATT_CHARAC_RECONNECTION_ADDRESS 0x2A03
-#define GATT_CHARAC_PERIPHERAL_PREF_CONN 0x2A04
-#define GATT_CHARAC_SERVICE_CHANGED 0x2A05
-
-/* GATT Characteristic Descriptors */
-#define GATT_CHARAC_EXT_PROPER_UUID 0x2900
-#define GATT_CHARAC_USER_DESC_UUID 0x2901
-#define GATT_CLIENT_CHARAC_CFG_UUID 0x2902
-#define GATT_SERVER_CHARAC_CFG_UUID 0x2903
-#define GATT_CHARAC_FMT_UUID 0x2904
-#define GATT_CHARAC_AGREG_FMT_UUID 0x2905
-#define GATT_CHARAC_VALID_RANGE_UUID 0x2906
-#define GATT_EXTERNAL_REPORT_REFERENCE 0x2907
-#define GATT_REPORT_REFERENCE 0x2908
-
/* Client Characteristic Configuration bit field */
#define GATT_CLIENT_CHARAC_CFG_NOTIF_BIT 0x0001
#define GATT_CLIENT_CHARAC_CFG_IND_BIT 0x0002
diff --git a/lib/uuid.h b/lib/uuid.h
index 95e5a9a..c24cee5 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -105,6 +105,31 @@ extern "C" {
#define OBEX_MNS_UUID "00001133-0000-1000-8000-00805f9b34fb"
#define OBEX_MAP_UUID "00001134-0000-1000-8000-00805f9b34fb"
+/* GATT UUIDs section */
+#define GATT_PRIM_SVC_UUID 0x2800
+#define GATT_SND_SVC_UUID 0x2801
+#define GATT_INCLUDE_UUID 0x2802
+#define GATT_CHARAC_UUID 0x2803
+
+/* GATT Characteristic Types */
+#define GATT_CHARAC_DEVICE_NAME 0x2A00
+#define GATT_CHARAC_APPEARANCE 0x2A01
+#define GATT_CHARAC_PERIPHERAL_PRIV_FLAG 0x2A02
+#define GATT_CHARAC_RECONNECTION_ADDRESS 0x2A03
+#define GATT_CHARAC_PERIPHERAL_PREF_CONN 0x2A04
+#define GATT_CHARAC_SERVICE_CHANGED 0x2A05
+
+/* GATT Characteristic Descriptors */
+#define GATT_CHARAC_EXT_PROPER_UUID 0x2900
+#define GATT_CHARAC_USER_DESC_UUID 0x2901
+#define GATT_CLIENT_CHARAC_CFG_UUID 0x2902
+#define GATT_SERVER_CHARAC_CFG_UUID 0x2903
+#define GATT_CHARAC_FMT_UUID 0x2904
+#define GATT_CHARAC_AGREG_FMT_UUID 0x2905
+#define GATT_CHARAC_VALID_RANGE_UUID 0x2906
+#define GATT_EXTERNAL_REPORT_REFERENCE 0x2907
+#define GATT_REPORT_REFERENCE 0x2908
+
typedef struct {
enum {
BT_UUID_UNSPEC = 0,
--
1.8.3.1
^ permalink raw reply related
* [PATCH BlueZ v6 04/18] gatt: Add registering external service
From: Claudio Takahasi @ 2014-02-04 17:53 UTC (permalink / raw)
To: linux-bluetooth; +Cc: claudio.takahasi, Alvaro Silva
In-Reply-To: <1391536429-8345-1-git-send-email-claudio.takahasi@openbossa.org>
From: Alvaro Silva <alvaro.silva@openbossa.org>
This patch allows external applications register a given service on
Bluez. Applications must provide an object path and a dictionary of
options. Options dictionary will be used later to provide additional
service information.
---
src/gatt-dbus.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 88 insertions(+), 1 deletion(-)
diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
index 183c611..fd614f9 100644
--- a/src/gatt-dbus.c
+++ b/src/gatt-dbus.c
@@ -26,22 +26,109 @@
#endif
#include <stdint.h>
+#include <errno.h>
#include <glib.h>
#include <dbus/dbus.h>
#include <gdbus/gdbus.h>
+#include "adapter.h"
+#include "device.h"
+#include "lib/uuid.h"
#include "dbus-common.h"
#include "log.h"
+#include "error.h"
#include "gatt-dbus.h"
#define GATT_MGR_IFACE "org.bluez.GattManager1"
+struct external_app {
+ char *owner;
+ char *path;
+ GDBusClient *client;
+ unsigned int watch;
+};
+
+static GSList *external_apps;
+
+static int external_app_path_cmp(gconstpointer a, gconstpointer b)
+{
+ const struct external_app *eapp = a;
+ const char *path = b;
+
+ return g_strcmp0(eapp->path, path);
+}
+
+static void external_app_watch_destroy(gpointer user_data)
+{
+ struct external_app *eapp = user_data;
+
+ /* TODO: Remove from the database */
+
+ external_apps = g_slist_remove(external_apps, eapp);
+
+ g_dbus_client_unref(eapp->client);
+
+ g_free(eapp->owner);
+ g_free(eapp->path);
+ g_free(eapp);
+}
+
+static struct external_app *new_external_app(DBusConnection *conn,
+ const char *sender, const char *path)
+{
+ struct external_app *eapp;
+ GDBusClient *client;
+
+ client = g_dbus_client_new(conn, sender, "/");
+ if (client == NULL)
+ return NULL;
+
+ eapp = g_new0(struct external_app, 1);
+
+ eapp->watch = g_dbus_add_disconnect_watch(btd_get_dbus_connection(),
+ sender, NULL, eapp, external_app_watch_destroy);
+ if (eapp->watch == 0) {
+ g_dbus_client_unref(client);
+ g_free(eapp);
+ return NULL;
+ }
+
+ eapp->owner = g_strdup(sender);
+ eapp->client = client;
+ eapp->path = g_strdup(path);
+
+ return eapp;
+}
+
static DBusMessage *register_service(DBusConnection *conn,
DBusMessage *msg, void *user_data)
{
- return dbus_message_new_method_return(msg);
+ struct external_app *eapp;
+ DBusMessageIter iter;
+ const char *path;
+
+ if (!dbus_message_iter_init(msg, &iter))
+ return btd_error_invalid_args(msg);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
+ return btd_error_invalid_args(msg);
+
+ dbus_message_iter_get_basic(&iter, &path);
+
+ if (g_slist_find_custom(external_apps, path, external_app_path_cmp))
+ return btd_error_already_exists(msg);
+
+ eapp = new_external_app(conn, dbus_message_get_sender(msg), path);
+ if (eapp == NULL)
+ return btd_error_failed(msg, "Not enough resources");
+
+ external_apps = g_slist_prepend(external_apps, eapp);
+
+ DBG("New app %p: %s", eapp, path);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
}
static DBusMessage *unregister_service(DBusConnection *conn,
--
1.8.3.1
^ permalink raw reply related
* [PATCH BlueZ v6 03/18] gatt: Register Manager D-Bus Interface
From: Claudio Takahasi @ 2014-02-04 17:53 UTC (permalink / raw)
To: linux-bluetooth; +Cc: claudio.takahasi, Alvaro Silva
In-Reply-To: <1391536429-8345-1-git-send-email-claudio.takahasi@openbossa.org>
From: Alvaro Silva <alvaro.silva@openbossa.org>
This patch registers GATT Service Manager D-Bus Interface. This
interface implements the methods to allow external application register
and unregister GATT Services.
---
Makefile.am | 1 +
src/gatt-dbus.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/gatt-dbus.h | 25 +++++++++++++++++++
src/gatt.c | 9 +++++++
4 files changed, 110 insertions(+)
create mode 100644 src/gatt-dbus.c
create mode 100644 src/gatt-dbus.h
diff --git a/Makefile.am b/Makefile.am
index 5f61d50..e630fcb 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -146,6 +146,7 @@ src_bluetoothd_SOURCES = $(builtin_sources) \
src/adapter.h src/adapter.c \
src/profile.h src/profile.c \
src/service.h src/service.c \
+ src/gatt-dbus.h src/gatt-dbus.c \
src/gatt.h src/gatt.c \
src/device.h src/device.c src/attio.h \
src/dbus-common.c src/dbus-common.h \
diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
new file mode 100644
index 0000000..183c611
--- /dev/null
+++ b/src/gatt-dbus.c
@@ -0,0 +1,75 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2014 Instituto Nokia de Tecnologia - INdT
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdint.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <gdbus/gdbus.h>
+
+#include "dbus-common.h"
+#include "log.h"
+
+#include "gatt-dbus.h"
+
+#define GATT_MGR_IFACE "org.bluez.GattManager1"
+
+static DBusMessage *register_service(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *unregister_service(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ return dbus_message_new_method_return(msg);
+}
+
+static const GDBusMethodTable methods[] = {
+ { GDBUS_EXPERIMENTAL_METHOD("RegisterService",
+ GDBUS_ARGS({ "service", "o"},
+ { "options", "a{sv}"}),
+ NULL, register_service) },
+ { GDBUS_EXPERIMENTAL_METHOD("UnregisterService",
+ GDBUS_ARGS({"service", "o"}),
+ NULL, unregister_service) },
+ { }
+};
+
+gboolean gatt_dbus_manager_register(void)
+{
+ return g_dbus_register_interface(btd_get_dbus_connection(),
+ "/org/bluez", GATT_MGR_IFACE,
+ methods, NULL, NULL, NULL, NULL);
+}
+
+void gatt_dbus_manager_unregister(void)
+{
+ g_dbus_unregister_interface(btd_get_dbus_connection(), "/org/bluez",
+ GATT_MGR_IFACE);
+}
diff --git a/src/gatt-dbus.h b/src/gatt-dbus.h
new file mode 100644
index 0000000..310cfa9
--- /dev/null
+++ b/src/gatt-dbus.h
@@ -0,0 +1,25 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2014 Instituto Nokia de Tecnologia - INdT
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+gboolean gatt_dbus_manager_register(void);
+void gatt_dbus_manager_unregister(void);
diff --git a/src/gatt.c b/src/gatt.c
index 06619f0..e8b691a 100644
--- a/src/gatt.c
+++ b/src/gatt.c
@@ -25,14 +25,23 @@
#include <config.h>
#endif
+#include <glib.h>
+
+#include "log.h"
+
+#include "gatt-dbus.h"
#include "gatt.h"
void gatt_init(void)
{
+ DBG("Starting GATT server");
+ gatt_dbus_manager_register();
}
void gatt_cleanup(void)
{
+ DBG("Stopping GATT server");
+ gatt_dbus_manager_unregister();
}
--
1.8.3.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox