* [PATCH v2 0/2] core: Add plugin-support for Manufacturer Specific Data EIR
From: Alfonso Acosta @ 2014-10-10 15:23 UTC (permalink / raw)
To: linux-bluetooth
Athough the Manufacturer Specific Data (MSD) field is not used
internally, it's useful for external plugins, e.g. iBeacon.
For instance we are dealing with a device which, when losing its LTK
on a reset, notifies the master about the need of rebonding by broadcasting
specific content in the MSD field of ADV_IND reports.
The first patch simply adds the field and parsing support.
The second one adds a subscription mechanism for plugins so that they can
be notified about new Manufacturer Specific Data being received.
Alfonso Acosta (2):
core: Add Manufacturer Specific Data EIR field
core: Add subscription API for Manufacturer Specific Data
plugins/neard.c | 1 -
src/adapter.c | 38 +++++++++++++++++++++++++++++++++++++-
src/adapter.h | 10 ++++++++++
src/eir.c | 11 +++++++++++
src/eir.h | 8 ++++++++
5 files changed, 66 insertions(+), 2 deletions(-)
--
1.9.1
^ permalink raw reply
* Bluez dual-mode support
From: Boulais, Marc-Andre @ 2014-10-10 15:15 UTC (permalink / raw)
To: linux-bluetooth@vger.kernel.org
Hi,
Does BlueZ support a "dual mode" where both Bluetooth "classic" and "low-energy" are enabled? I need to support classic and LE Bluetooth devices in my network.
Furthermore, is there an recent list of Bluetooth chipsets supported by BlueZ for Low Energy? any chipset recommendations would be greatly appreciated.
Thanks,
Marc
^ permalink raw reply
* Re: [PATCH BlueZ 1/8] android/avrcp-lib: Add support for SetBrowsedPlayer PDU
From: Luiz Augusto von Dentz @ 2014-10-10 14:15 UTC (permalink / raw)
To: linux-bluetooth@vger.kernel.org
In-Reply-To: <1412771509-7996-1-git-send-email-luiz.dentz@gmail.com>
Hi,
On Wed, Oct 8, 2014 at 3:31 PM, Luiz Augusto von Dentz
<luiz.dentz@gmail.com> wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
>
> ---
> android/avrcp-lib.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++
> android/avrcp-lib.h | 6 +++++
> 2 files changed, 83 insertions(+)
>
> diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
> index 9a074ae..8350497 100644
> --- a/android/avrcp-lib.c
> +++ b/android/avrcp-lib.c
> @@ -1243,6 +1243,30 @@ static void avrcp_set_control_handlers(struct avrcp *session,
> session->control_data = user_data;
> }
>
> +static ssize_t set_browsed(struct avrcp *session, uint8_t transaction,
> + uint16_t params_len, uint8_t *params,
> + void *user_data)
> +{
> + struct avrcp_player *player = user_data;
> + struct set_browsed_req *req;
> + uint16_t id;
> +
> + DBG("");
> +
> + if (!player->ind || !player->ind->set_browsed)
> + return -ENOSYS;
> +
> + if (!params || params_len != sizeof(*req))
> + return -EINVAL;
> +
> + req = (void *) params;
> +
> + id = get_be16(&req->id);
> +
> + return player->ind->set_browsed(session, transaction, id,
> + player->user_data);
> +}
> +
> static ssize_t get_folder_items(struct avrcp *session, uint8_t transaction,
> uint16_t params_len, uint8_t *params,
> void *user_data)
> @@ -1449,6 +1473,7 @@ static ssize_t add_to_now_playing(struct avrcp *session, uint8_t transaction,
> }
>
> static const struct avrcp_browsing_handler browsing_handlers[] = {
> + { AVRCP_SET_BROWSED_PLAYER, set_browsed },
> { AVRCP_GET_FOLDER_ITEMS, get_folder_items },
> { AVRCP_CHANGE_PATH, change_path },
> { AVRCP_GET_ITEM_ATTRIBUTES, get_item_attributes },
> @@ -3295,6 +3320,58 @@ int avrcp_set_addressed_player_rsp(struct avrcp *session, uint8_t transaction,
> &iov, 1);
> }
>
> +int avrcp_set_browsed_player_rsp(struct avrcp *session, uint8_t transaction,
> + uint8_t status, uint16_t counter,
> + uint32_t items, uint8_t depth,
> + const char **folders)
> +{
> + struct iovec iov[UINT8_MAX * 2 + 1];
> + struct set_browsed_rsp rsp;
> + uint16_t len[UINT8_MAX];
> + int i;
> +
> + if (status != AVRCP_STATUS_SUCCESS) {
> + iov[0].iov_base = &status;
> + iov[0].iov_len = sizeof(status);
> + return avrcp_send_browsing(session, transaction,
> + AVRCP_SET_BROWSED_PLAYER,
> + iov, 1);
> + }
> +
> + rsp.status = status;
> + put_be16(counter, &rsp.counter);
> + put_be32(items, &rsp.items);
> + put_be16(AVRCP_CHARSET_UTF8, &rsp.charset);
> + rsp.depth = depth;
> +
> + iov[0].iov_base = &rsp;
> + iov[0].iov_len = sizeof(rsp);
> +
> + if (!depth)
> + return avrcp_send_browsing(session, transaction,
> + AVRCP_SET_BROWSED_PLAYER,
> + iov, 1);
> +
> + for (i = 0; i < depth; i++) {
> + if (!folders[i])
> + return -EINVAL;
> +
> + len[i] = strlen(folders[i]);
> +
> + iov[i * 2 + 2].iov_base = (void *) folders[i];
> + iov[i * 2 + 2].iov_len = len[i];
> +
> + put_be16(len[i], &len[i]);
> +
> + iov[i * 2 + 1].iov_base = &len[i];
> + iov[i * 2 + 1].iov_len = sizeof(len[i]);
> + }
> +
> + return avrcp_send_browsing(session, transaction,
> + AVRCP_SET_BROWSED_PLAYER, iov,
> + depth * 2 + 1);
> +}
> +
> int avrcp_get_folder_items_rsp(struct avrcp *session, uint8_t transaction,
> uint16_t counter, uint8_t number,
> uint8_t *type, uint16_t *len,
> diff --git a/android/avrcp-lib.h b/android/avrcp-lib.h
> index 2b6eccb..dd82deb 100644
> --- a/android/avrcp-lib.h
> +++ b/android/avrcp-lib.h
> @@ -161,6 +161,8 @@ struct avrcp_control_ind {
> uint8_t volume, void *user_data);
> int (*set_addressed) (struct avrcp *session, uint8_t transaction,
> uint16_t id, void *user_data);
> + int (*set_browsed) (struct avrcp *session, uint8_t transaction,
> + uint16_t id, void *user_data);
> int (*get_folder_items) (struct avrcp *session, uint8_t transaction,
> uint8_t scope, uint32_t start,
> uint32_t end, uint16_t number,
> @@ -319,6 +321,10 @@ int avrcp_set_volume_rsp(struct avrcp *session, uint8_t transaction,
> uint8_t volume);
> int avrcp_set_addressed_player_rsp(struct avrcp *session, uint8_t transaction,
> uint8_t status);
> +int avrcp_set_browsed_player_rsp(struct avrcp *session, uint8_t transaction,
> + uint8_t status, uint16_t counter,
> + uint32_t items, uint8_t depth,
> + const char **folders);
> int avrcp_get_folder_items_rsp(struct avrcp *session, uint8_t transaction,
> uint16_t counter, uint8_t number,
> uint8_t *type, uint16_t *len,
> --
> 1.9.3
Applied.
--
Luiz Augusto von Dentz
^ permalink raw reply
* [PATCH v2 2/2] Bluetooth: Improve RFCOMM __test_pf macro robustness
From: Szymon Janc @ 2014-10-10 13:43 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1412948593-32106-1-git-send-email-szymon.janc@tieto.com>
Value returned by this macro might be used as bit value so it should
return either 0 or 1 to avoid possible bugs (similar to NSC bug)
when shifting it.
Signed-off-by: Szymon Janc <szymon.janc@tieto.com>
---
net/bluetooth/rfcomm/core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index aa38fa8..7e9ed17 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -79,7 +79,7 @@ static struct rfcomm_session *rfcomm_session_del(struct rfcomm_session *s);
#define __test_ea(b) ((b & 0x01))
#define __test_cr(b) (!!(b & 0x02))
-#define __test_pf(b) ((b & 0x10))
+#define __test_pf(b) (!!(b & 0x10))
#define __addr(cr, dlci) (((dlci & 0x3f) << 2) | (cr << 1) | 0x01)
#define __ctrl(type, pf) (((type & 0xef) | (pf << 4)))
--
1.9.1
^ permalink raw reply related
* [PATCH v2 1/2] Bluetooth: Fix RFCOMM NSC response
From: Szymon Janc @ 2014-10-10 13:43 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
rfcomm_send_nsc expects cr to be either 0 or 1 since it is later
passed to __mcc_type macro and shitfed. Unfortunatelly cr extracted
from received frame type was not sanitized and shifted value was passed
resulting in bogus response.
Note: shifted value was also passed to other functions but was used
only in if satements so this bug appears only for NSC case.
This was affecting TC_RFC_BV_25_C PTS qualification test.
Signed-off-by: Szymon Janc <szymon.janc@tieto.com>
---
V2: moved sanitization to macro ifself
added second patch that also fix __test_pf
net/bluetooth/rfcomm/core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index ca957d3..aa38fa8 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -78,7 +78,7 @@ static struct rfcomm_session *rfcomm_session_del(struct rfcomm_session *s);
#define __get_type(b) ((b & 0xef))
#define __test_ea(b) ((b & 0x01))
-#define __test_cr(b) ((b & 0x02))
+#define __test_cr(b) (!!(b & 0x02))
#define __test_pf(b) ((b & 0x10))
#define __addr(cr, dlci) (((dlci & 0x3f) << 2) | (cr << 1) | 0x01)
--
1.9.1
^ permalink raw reply related
* [PATCH] Bluetooth: Fix RFCOMM NSC response
From: Szymon Janc @ 2014-10-10 13:21 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
rfcomm_send_nsc expects cr to be either 0 or 1 since it is later
passed to __mcc_type macro and shitfed. Unfortunatelly cr extracted
from received frame type was not sanitized and shifted value was passed
resulting in bogus response.
Note: shifted value was also passed to other functions but was used
only in if satements so this bug appears only for NSC case.
This was affecting TC_RFC_BV_25_C PTS qualification test.
Signed-off-by: Szymon Janc <szymon.janc@tieto.com>
---
net/bluetooth/rfcomm/core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index ca957d3..d340577 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -1558,7 +1558,7 @@ static int rfcomm_recv_mcc(struct rfcomm_session *s, struct sk_buff *skb)
struct rfcomm_mcc *mcc = (void *) skb->data;
u8 type, cr, len;
- cr = __test_cr(mcc->type);
+ cr = !!__test_cr(mcc->type);
type = __get_mcc_type(mcc->type);
len = __get_mcc_len(mcc->len);
--
1.9.1
^ permalink raw reply related
* [PATCH 2/2] android/pts: Update PTS files for SPP
From: Sebastian Chlad @ 2014-10-10 12:10 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Sebastian Chlad
In-Reply-To: <1412943017-17823-1-git-send-email-sebastian.chlad@tieto.com>
---
android/pics-spp.txt | 2 +-
android/pixit-spp.txt | 2 +-
android/pts-spp.txt | 4 ++--
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/android/pics-spp.txt b/android/pics-spp.txt
index 3296738..f015236 100644
--- a/android/pics-spp.txt
+++ b/android/pics-spp.txt
@@ -1,6 +1,6 @@
SPP PICS for the PTS tool.
-PTS version: 5.2
+PTS version: 5.3
* - different than PTS defaults
# - not yet implemented/supported
diff --git a/android/pixit-spp.txt b/android/pixit-spp.txt
index bb9605e..a8a8202 100644
--- a/android/pixit-spp.txt
+++ b/android/pixit-spp.txt
@@ -1,6 +1,6 @@
SPP PIXIT for the PTS tool.
-PTS version: 5.2
+PTS version: 5.3
* - different than PTS defaults
& - should be set to IUT Bluetooth address
diff --git a/android/pts-spp.txt b/android/pts-spp.txt
index ba511eb..328c949 100644
--- a/android/pts-spp.txt
+++ b/android/pts-spp.txt
@@ -1,7 +1,7 @@
PTS test results for SPP
-PTS version: 5.2
-Tested: 21-July-2014
+PTS version: 5.3
+Tested: 10-October-2014
Android version: 4.4.4
Results:
--
1.8.5.3
^ permalink raw reply related
* [PATCH 1/2] android/pts: Update HSP files for PTS 5.3
From: Sebastian Chlad @ 2014-10-10 12:10 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Sebastian Chlad
---
android/pics-hsp.txt | 2 +-
android/pixit-hsp.txt | 2 +-
android/pts-hsp.txt | 4 ++--
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/android/pics-hsp.txt b/android/pics-hsp.txt
index 330a197..7e71b14 100644
--- a/android/pics-hsp.txt
+++ b/android/pics-hsp.txt
@@ -1,6 +1,6 @@
HSP PICS for the PTS tool.
-PTS version: 5.2
+PTS version: 5.3
* - different than PTS defaults
# - not yet implemented/supported
diff --git a/android/pixit-hsp.txt b/android/pixit-hsp.txt
index a097277..6be4731 100644
--- a/android/pixit-hsp.txt
+++ b/android/pixit-hsp.txt
@@ -1,6 +1,6 @@
HSP PIXIT for the PTS tool.
-PTS version: 5.2
+PTS version: 5.3
* - different than PTS defaults
& - should be set to IUT Bluetooth address
diff --git a/android/pts-hsp.txt b/android/pts-hsp.txt
index 0df9806..9031b82 100644
--- a/android/pts-hsp.txt
+++ b/android/pts-hsp.txt
@@ -1,7 +1,7 @@
PTS test results for HSP
-PTS version: 5.2
-Tested: 15-July-2014
+PTS version: 5.3
+Tested: 10-October-2014
Android version: 4.4.4
Results:
--
1.8.5.3
^ permalink raw reply related
* [PATCH] core: Add Manufacturer Specific Data EIR field
From: Alfonso Acosta @ 2014-10-10 11:37 UTC (permalink / raw)
To: linux-bluetooth
Athough the Manufacturer Specific Data field is not used internally,
it's useful for external plugins, e.g. iBeacon.
---
src/eir.c | 8 ++++++++
src/eir.h | 4 ++++
2 files changed, 12 insertions(+)
diff --git a/src/eir.c b/src/eir.c
index d22ad91..f130855 100644
--- a/src/eir.c
+++ b/src/eir.c
@@ -240,6 +240,14 @@ void eir_parse(struct eir_data *eir, const uint8_t *eir_data, uint8_t eir_len)
eir->did_product = data[4] | (data[5] << 8);
eir->did_version = data[6] | (data[7] << 8);
break;
+
+ case EIR_MANUFACTURER_DATA:
+ if (data_len < 2)
+ break;
+ eir->msd_company = get_le16(data);
+ eir->msd_data_len = data_len - 2;
+ memcpy(&eir->msd_data, data+2, eir->msd_data_len);
+ break;
}
eir_data += field_len + 1;
diff --git a/src/eir.h b/src/eir.h
index e486fa2..88a5bf0 100644
--- a/src/eir.h
+++ b/src/eir.h
@@ -37,6 +37,7 @@
#define EIR_SSP_RANDOMIZER 0x0F /* SSP Randomizer */
#define EIR_DEVICE_ID 0x10 /* device ID */
#define EIR_GAP_APPEARANCE 0x19 /* GAP appearance */
+#define EIR_MANUFACTURER_DATA 0xFF /* Manufacturer Specific Data */
/* Flags Descriptions */
#define EIR_LIM_DISC 0x01 /* LE Limited Discoverable Mode */
@@ -62,6 +63,9 @@ struct eir_data {
uint16_t did_product;
uint16_t did_version;
uint16_t did_source;
+ uint16_t msd_company;
+ uint8_t msd_data[HCI_MAX_EIR_LENGTH];
+ uint8_t msd_data_len;
};
void eir_data_free(struct eir_data *eir);
--
1.9.1
^ permalink raw reply related
* Re: [RFC] need for new scan api for bluetooth low energy.
From: Marcel Holtmann @ 2014-10-10 10:52 UTC (permalink / raw)
To: Jakub Pawlowski; +Cc: Arman Uguray, BlueZ development, Scott James Remnant
In-Reply-To: <93AC6768-49F3-43CC-8014-83DD3C0EA3D3@holtmann.org>
Hi Jakub,
>>>> Ok, new updated version - we do only passive scan, and we send Device
>>>> found event:
>>>>
>>>>
>>>> diff --git a/doc/mgmt-api.txt b/doc/mgmt-api.txt
>>>> index 11e2490..3d03617 100644
>>>> --- a/doc/mgmt-api.txt
>>>> +++ b/doc/mgmt-api.txt
>>>> @@ -2135,6 +2135,29 @@ Set Public Address Command
>>>> Invalid Index
>>>>
>>>>
>>>> +Start Passive LE Filtered Device Scan
>>>> +=======================
>>>> +
>>>> + Command Code: 0x003A
>>>> + Controller Index: <controller id>
>>>> + Command Parameters: UUID (16 Octets)
>>>> + max_pathloss (1 octet)
>>>> +
>>>> + Return Parameters:
>>>> +
>>>> + This command starts passive LE scan, and filter received
>>>> advertisements: if AD contains both TX power level and Service
>>>> Solicitation, and UUID is contained in Service Solicitation and
>>>> computed pathloss is smaller than max_pathloss parameter, then a
>>>> Device Found event will be sent.
>>>
>>> generally we tried to avoid to specific LE only commands. Our attempts with the kernel APIs where to make them as generic as possible. So I think something along the lines of adding and removing UUID filters should be something we should target at.
>>>
>>> Add UUID Notification Filter
>>> ============================
>>>
>>> Command Parameters: Address_Type (1 Octet)
>>> UUID (16 Octets)
>>> Max_Pathloss (1 Octet)
>>> Return Parameters: Address_Type (1 Octet)
>>>
>>>
>>> Remove UUID Notification Filter
>>> ===============================
>>>
>>> Command Parameters: Address_Type (1 Octet)
>>> UUID (16 Octets)
>>> Return Parameters: Address_Type (1 Octet)
>>>
>>> The Address_Type would be defined the same way as for Start Discovery command.
>>>
>>> Now we can discuss if on the mgmt level we want to use pathloss or rather a range of RSSI. I have seen that RSSI is preferred and that the translation from RSSI and advertising data with TX power level is done in the daemon. So for kernel API it might be better to expose RSSI range.
>>>
>>> Besides a RSSI range, we might also want to allow giving a RSSI threshold that defines how much the RSSI to change between events to be reported again.
>>
>> Some mobile devices that I'm working can change power level for
>> advertising, that makes raw RSSI filter useless. It must be pathloss,
>> that's why I require TX power in advertisement.
>
> you will still get it, but just have to do the math in the daemon. The only difference is that the daemon gets woken up for RSSI ranges that in the end you might filter out.
>
>>>
>>> That said, the danger with a generic notification filter like this is that we can not implement it efficiently with current hardware without vendor commands. If you use duplicate filtering, then Broadcom and CSR chips behave fully different. Broadcom only filters on BD_ADDR and report devices once no matter what the RSSI, while CSR will report the same device again if the RSSI changes.
>>>
>>> With that in mind, it might be safer to introduce a one-shot mgmt API that needs to be repeatedly called to keep scanning for new devices.
>>>
>>> Start Service Discovery
>>> =======================
>>>
>>> Command Parameters: Address_Type (1 Octet)
>>> Min_RSSI (1 Octet)
>>> Max_RSSI (1 Octet)
>>> Num_UUID (1 Octet)
>>> UUID[i] (16 Octets)
>>> Return Parameters: Address_Type (1 Octet)
>>>
>>> Stop Service Discovery
>>> ======================
>>>
>>> Command Parameters: Address_Type (1 Octet)
>>> Return Parameters: Address_Type (1 Octet)
>>>
>>> Without having dedicated controller support for filtering, having such a dedicated discovery for services with a specific UUID seems to be more appropriate and more safe. Since we could always add controller based filtering for background scanning once there is controller support.
>>
>> I preffer the "Add UUID Notification Filter" and "Remove UUID
>> Notification Filter". For controllers like Broadcom that reports only
>> one advertisement can we restart scan internally in kernel ? Why
>> propagate that event higher ?
>
> Personally I would prefer just adding another filter as well. However it might be better to start with something like a one-shot handling and see where that is taking us. It is a little bit less intrusive and you could also use active scanning. At the same time you could also easily make it work for BR/EDR. I am thinking here along the lines of something wanting to pair a mouse. You just give the HID UUID and start interleaved discovery for that service on both transports.
I send a proposal for doing an one-shot service discovery. So you can propose a RSSI Threshold and a list of possible UUIDs to look for.
If RSSI Threshold is 127 or the Num_UUID is 0, then it will behave the same way as Start Discovery. I think this is how we should get started to tackle this problem.
Regards
Marcel
^ permalink raw reply
* [PATCH] doc: Add commands for Start Service Discovery and Stop Service Discovery
From: Marcel Holtmann @ 2014-10-10 10:49 UTC (permalink / raw)
To: linux-bluetooth
---
doc/mgmt-api.txt | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 87 insertions(+), 1 deletion(-)
diff --git a/doc/mgmt-api.txt b/doc/mgmt-api.txt
index daf036b4c1ec..2038f883cc95 100644
--- a/doc/mgmt-api.txt
+++ b/doc/mgmt-api.txt
@@ -2135,6 +2135,89 @@ Set Public Address Command
Invalid Index
+Start Service Discovery Command
+===============================
+
+ Command Code: 0x003a
+ Controller Index: <controller id>
+ Command Parameters: Address_Type (1 Octet)
+ RSSI_Threshold (1 Octet)
+ Num_UUID (1 Octet)
+ UUID[i] (16 Octets)
+ Return Parameters: Address_Type (1 Octet)
+
+ This command is used to start the process of discovering remote
+ devices with a specific UUID. A Device Found event will be sent
+ for each discovered device.
+
+ Possible values for the Address_Type parameter are a bit-wise or
+ of the following bits:
+
+ 0 BR/EDR
+ 1 LE Public
+ 2 LE Random
+
+ By combining these e.g. the following values are possible:
+
+ 1 BR/EDR
+ 6 LE (public & random)
+ 7 BR/EDR/LE (interleaved discovery)
+
+ The service discovery uses active scanning for Low Energy scanning
+ and will search for UUID in both advertising data and scan response
+ data.
+
+ Found devices that have a RSSI value smaller than RSSI_Threshold
+ are not reported via DeviceFound event. Setting a value of 127
+ will cause all devices to be reported.
+
+ The list of UUIDs identifies a logical OR. Only one of the UUIDs
+ have to match to cause a DeviceFound event. Providing an empty
+ list of UUIDs with Num_UUID set to 0 which means that DeviceFound
+ events are send out for all devices above the RSSI_Threshold.
+
+ In case the RSSI_Threshold is set to 127 and the Num_UUID is 0,
+ then this command behaves exactly the same as Start Discovery.
+
+ When the discovery procedure starts the Discovery event will
+ notify this similar to Start Discovery.
+
+ This command can only be used when the controller is powered.
+
+ This command generates a Command Complete event on success
+ or failure.
+
+ Possible errors: Busy
+ Not Supported
+ Invalid Parameters
+ Not Powered
+ Invalid Index
+
+
+Stop Service Discovery Command
+==============================
+
+ Command Code: 0x003b
+ Controller Index: <controller id>
+ Command Parameters: Address_Type (1 Octet)
+ Return Parameters: Address_Type (1 Octet)
+
+ This command is used to stop the service discovery process started
+ using the Start Service Discovery command.
+
+ When the discovery procedure stops the Discovery event will
+ notify this similar to Stop Discovery.
+
+ This command can only be used when the controller is powered.
+
+ This command generates a Command Complete event on success
+ or failure.
+
+ Possible errors: Rejected
+ Invalid Parameters
+ Invalid Index
+
+
Command Complete Event
======================
@@ -2555,7 +2638,10 @@ Discovering Event
This event indicates that the controller has started discovering
devices. This discovering state can come and go multiple times
- between a StartDiscover and a StopDiscovery command.
+ between a Start Discover and a Stop Discovery commands.
+
+ The Start Service Discovery and Stop Service Discovery commands
+ will also trigger this event.
The valid values for the Discovering parameter are 0x01
(enabled) and 0x00 (disabled).
--
1.9.3
^ permalink raw reply related
* Re: [PATCH] Adds Sony Move Navigation controller.
From: Szymon Janc @ 2014-10-10 10:07 UTC (permalink / raw)
To: Alex Gal; +Cc: linux-bluetooth
In-Reply-To: <1412697877-7508-1-git-send-email-a.gal@miip.ca>
Hi Alex,
Thanks for patch, some small comments from my side.
On Tuesday 07 of October 2014 12:04:37 Alex Gal wrote:
> Signed-off-by: Alex <a.gal@miip.ca>
We don't use SOB in userspace so this is not needed.
Also I'd prefer if you could put plugin change into separate patch.
And prefix them appropriately ie. "sixaxis: " for plugin and "input: "
for input change.
> ---
> plugins/sixaxis.c | 7 +++++++
> profiles/input/server.c | 4 ++++
> 2 files changed, 11 insertions(+)
>
> diff --git a/plugins/sixaxis.c b/plugins/sixaxis.c
> index b09404a..6f7893e 100644
> --- a/plugins/sixaxis.c
> +++ b/plugins/sixaxis.c
> @@ -60,6 +60,13 @@ static const struct {
> .pid = 0x0268,
> .version = 0x0000,
> },
> + {
> + .name = "PLAYSTATION(R)3 Controller", /* Move Navigation */
Does Move Navigation use same name as DS3?
> + .source = 0x0002,
> + .vid = 0x054c,
> + .pid = 0x042f,
> + .version = 0x0000,
> + },
> };
>
> struct leds_data {
> diff --git a/profiles/input/server.c b/profiles/input/server.c
> index 307db96..5463311 100644
> --- a/profiles/input/server.c
> +++ b/profiles/input/server.c
> @@ -140,6 +140,10 @@ static bool dev_is_sixaxis(const bdaddr_t *src, const bdaddr_t *dst)
> if (vid == 0x054c && pid == 0x05c4)
> return true;
>
> + /* Move Navigation */
> + if (vid == 0x054c && pid == 0x042f)
> + return true;
> +
> return false;
> }
>
>
--
Best regards,
Szymon Janc
^ permalink raw reply
* [PATCH v2] Bluetooth: Defer connection-parameter removal when unpairing without disconnecting
From: Alfonso Acosta @ 2014-10-10 9:16 UTC (permalink / raw)
To: linux-bluetooth
Systematically removing the LE connection parameters and autoconnect
action is inconvenient for rebonding without disconnecting from
userland (i.e. unpairing followed by repairing without
disconnecting). The parameters will be lost after unparing and
userland needs to take care of book-keeping them and re-adding them.
This patch allows userland to forget about parameter management when
rebonding without disconnecting. It defers clearing the connection
parameters when unparing without disconnecting, giving a chance of
keeping the parameters if a repairing happens before the connection is
closed.
Signed-off-by: Alfonso Acosta <fons@spotify.com>
---
include/net/bluetooth/hci_core.h | 1 +
net/bluetooth/hci_conn.c | 6 ++++++
net/bluetooth/mgmt.c | 27 +++++++++++++++++++++------
3 files changed, 28 insertions(+), 6 deletions(-)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 07ddeed62..b8685a7 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -555,6 +555,7 @@ enum {
HCI_CONN_STK_ENCRYPT,
HCI_CONN_AUTH_INITIATOR,
HCI_CONN_DROP,
+ HCI_CONN_PARAM_REMOVAL_PEND,
};
static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index b9517bd..eb9988f 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -356,6 +356,9 @@ static void hci_conn_timeout(struct work_struct *work)
conn->state = BT_CLOSED;
break;
}
+
+ if (test_and_clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags))
+ hci_conn_params_del(conn->hdev, &conn->dst, conn->dst_type);
}
/* Enter sniff mode */
@@ -544,6 +547,9 @@ int hci_conn_del(struct hci_conn *conn)
hci_conn_del_sysfs(conn);
+ if (test_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags))
+ hci_conn_params_del(conn->hdev, &conn->dst, conn->dst_type);
+
hci_dev_put(hdev);
hci_conn_put(conn);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 3fd88b0..943df45 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -2699,7 +2699,7 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
struct mgmt_rp_unpair_device rp;
struct hci_cp_disconnect dc;
struct pending_cmd *cmd;
- struct hci_conn *conn;
+ struct hci_conn *uninitialized_var(conn);
int err;
memset(&rp, 0, sizeof(rp));
@@ -2736,7 +2736,17 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type);
- hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
+ conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
+ &cp->addr.bdaddr);
+
+ /* If the BLE connection is being used, defer clearing up
+ * the connection parameters until closing to give a
+ * chance of keeping them if a repairing happens.
+ */
+ if (conn && !cp->disconnect)
+ set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
+ else
+ hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type);
}
@@ -2748,12 +2758,12 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
}
if (cp->disconnect) {
+ /* Only lookup the connection in the BR/EDR since the
+ * LE connection was already looked up earlier.
+ */
if (cp->addr.type == BDADDR_BREDR)
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
&cp->addr.bdaddr);
- else
- conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
- &cp->addr.bdaddr);
} else {
conn = NULL;
}
@@ -3212,8 +3222,13 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
cmd->user_data = hci_conn_get(conn);
if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
- hci_conn_security(conn, sec_level, auth_type, true))
+ hci_conn_security(conn, sec_level, auth_type, true)) {
+ /* The device is paired so there is no need to remove
+ * its connection parameters anymore.
+ */
+ clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
pairing_complete(cmd, 0);
+ }
err = 0;
--
1.9.1
^ permalink raw reply related
* [PATCHv4 14/14] shared/gatt: Fix searching descriptors
From: Marcin Kraglak @ 2014-10-10 9:15 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1412932548-28363-1-git-send-email-marcin.kraglak@tieto.com>
Descriptor discovery range started from characteristic value handle + 1
and end with characteristic end handle. If characteristic value handle
is 0xffff, then discovery range was set to 0x0000-0xffff.
Found during PTS test case TC_GAD_CL_BV_03_C.
---
src/shared/gatt-client.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index 679242c..045f9f9 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
@@ -714,8 +714,8 @@ static void discover_chrcs_cb(bool success, uint8_t att_ecode,
for (i = 0; i < chrc_count; i++) {
op->cur_chrc_index = i;
op->cur_chrc = chrcs + i;
- desc_start = chrcs[i].chrc_external.value_handle + 1;
- if (desc_start > chrcs[i].chrc_external.end_handle)
+ desc_start = chrcs[i].chrc_external.value_handle;
+ if (desc_start++ == chrcs[i].chrc_external.end_handle)
continue;
if (bt_gatt_discover_descriptors(client->att, desc_start,
--
1.9.3
^ permalink raw reply related
* [PATCHv4 13/14] tools/btgatt-client: Print found include services
From: Marcin Kraglak @ 2014-10-10 9:15 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1412932548-28363-1-git-send-email-marcin.kraglak@tieto.com>
---
tools/btgatt-client.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/tools/btgatt-client.c b/tools/btgatt-client.c
index 5c692ff..5465d53 100644
--- a/tools/btgatt-client.c
+++ b/tools/btgatt-client.c
@@ -174,7 +174,9 @@ static void print_uuid(const uint8_t uuid[16])
static void print_service(const bt_gatt_service_t *service)
{
struct bt_gatt_characteristic_iter iter;
+ struct bt_gatt_incl_service_iter include_iter;
const bt_gatt_characteristic_t *chrc;
+ const bt_gatt_included_service_t *incl;
size_t i;
if (!bt_gatt_characteristic_iter_init(&iter, service)) {
@@ -182,12 +184,24 @@ static void print_service(const bt_gatt_service_t *service)
return;
}
+ if (!bt_gatt_include_service_iter_init(&include_iter, service)) {
+ PRLOG("Failed to initialize include service iterator\n");
+ return;
+ }
printf(COLOR_RED "service %s" COLOR_OFF " - start: 0x%04x, "
"end: 0x%04x, uuid: ",
service->primary ? "primary" : "second.",
service->start_handle, service->end_handle);
print_uuid(service->uuid);
+ while (bt_gatt_include_service_iter_next(&include_iter, &incl)) {
+ printf("\t " COLOR_GREEN "include" COLOR_OFF " - handle: "
+ "0x%04x, - start: 0x%04x, end: 0x%04x,"
+ "uuid: ", incl->handle,
+ incl->start_handle, incl->end_handle);
+ print_uuid(incl->uuid);
+ }
+
while (bt_gatt_characteristic_iter_next(&iter, &chrc)) {
printf("\t " COLOR_YELLOW "charac" COLOR_OFF
" - start: 0x%04x, end: 0x%04x, "
--
1.9.3
^ permalink raw reply related
* [PATCHv4 12/14] shared/gatt: Add gatt-client include service iterator
From: Marcin Kraglak @ 2014-10-10 9:15 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1412932548-28363-1-git-send-email-marcin.kraglak@tieto.com>
It will allow user to take value, handle, start and end handle
of included service.
---
src/shared/gatt-client.c | 30 ++++++++++++++++++++++++++++++
src/shared/gatt-client.h | 10 ++++++++++
2 files changed, 40 insertions(+)
diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index 80d7a1a..679242c 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
@@ -1673,6 +1673,36 @@ bool bt_gatt_characteristic_iter_next(struct bt_gatt_characteristic_iter *iter,
return true;
}
+bool bt_gatt_include_service_iter_init(struct bt_gatt_incl_service_iter *iter,
+ const bt_gatt_service_t *service)
+{
+ if (!iter || !service)
+ return false;
+
+ memset(iter, 0, sizeof(*iter));
+ iter->service = (struct service_list *) service;
+
+ return true;
+}
+
+bool bt_gatt_include_service_iter_next(struct bt_gatt_incl_service_iter *iter,
+ const bt_gatt_included_service_t **incl)
+{
+ struct service_list *service;
+
+ if (!iter || !incl)
+ return false;
+
+ service = iter->service;
+
+ if (iter->pos >= service->num_includes)
+ return false;
+
+ *incl = &service->includes[iter->pos++];
+
+ return true;
+}
+
struct read_op {
bt_gatt_client_read_callback_t callback;
void *user_data;
diff --git a/src/shared/gatt-client.h b/src/shared/gatt-client.h
index 05b4838..bf4e7bb 100644
--- a/src/shared/gatt-client.h
+++ b/src/shared/gatt-client.h
@@ -113,6 +113,11 @@ struct bt_gatt_characteristic_iter {
size_t pos;
};
+struct bt_gatt_incl_service_iter {
+ void *service;
+ size_t pos;
+};
+
bool bt_gatt_service_iter_init(struct bt_gatt_service_iter *iter,
struct bt_gatt_client *client);
bool bt_gatt_service_iter_next(struct bt_gatt_service_iter *iter,
@@ -129,6 +134,11 @@ bool bt_gatt_characteristic_iter_init(struct bt_gatt_characteristic_iter *iter,
bool bt_gatt_characteristic_iter_next(struct bt_gatt_characteristic_iter *iter,
const bt_gatt_characteristic_t **chrc);
+bool bt_gatt_include_service_iter_init(struct bt_gatt_incl_service_iter *iter,
+ const bt_gatt_service_t *service);
+bool bt_gatt_include_service_iter_next(struct bt_gatt_incl_service_iter *iter,
+ const bt_gatt_included_service_t **inc);
+
typedef void (*bt_gatt_client_read_callback_t)(bool success, uint8_t att_ecode,
const uint8_t *value, uint16_t length,
void *user_data);
--
1.9.3
^ permalink raw reply related
* [PATCHv4 11/14] shared/gatt: Discover included services
From: Marcin Kraglak @ 2014-10-10 9:15 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1412932548-28363-1-git-send-email-marcin.kraglak@tieto.com>
---
src/shared/gatt-client.c | 114 +++++++++++++++++++++++++++++++++++++++++++++--
src/shared/gatt-client.h | 7 +++
2 files changed, 117 insertions(+), 4 deletions(-)
diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index 9a0ec35..80d7a1a 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
@@ -69,6 +69,8 @@ struct service_list {
bt_gatt_service_t service;
struct chrc_data *chrcs;
size_t num_chrcs;
+ bt_gatt_included_service_t *includes;
+ size_t num_includes;
struct service_list *next;
};
@@ -253,6 +255,14 @@ static void service_destroy_characteristics(struct service_list *service)
free(service->chrcs);
}
+static void service_destroy_includes(struct service_list *service)
+{
+ free(service->includes);
+
+ service->includes = NULL;
+ service->num_includes = 0;
+}
+
static void service_list_clear(struct service_list **head,
struct service_list **tail)
{
@@ -265,6 +275,7 @@ static void service_list_clear(struct service_list **head,
while (l) {
service_destroy_characteristics(l);
+ service_destroy_includes(l);
tmp = l;
l = tmp->next;
free(tmp);
@@ -293,6 +304,7 @@ static void service_list_clear_range(struct service_list **head,
}
service_destroy_characteristics(cur);
+ service_destroy_includes(cur);
if (!prev)
*head = cur->next;
@@ -428,6 +440,99 @@ static int uuid_cmp(const uint8_t uuid128[16], uint16_t uuid16)
return memcmp(uuid128, rhs_uuid, sizeof(rhs_uuid));
}
+static void discover_incl_cb(bool success, uint8_t att_ecode,
+ struct bt_gatt_result *result,
+ void *user_data)
+{
+ struct discovery_op *op = user_data;
+ struct bt_gatt_client *client = op->client;
+ struct bt_gatt_iter iter;
+ char uuid_str[MAX_LEN_UUID_STR];
+ bt_gatt_included_service_t *includes;
+ unsigned int includes_count, i;
+
+ if (!success) {
+ if (att_ecode == BT_ATT_ERROR_ATTRIBUTE_NOT_FOUND) {
+ success = true;
+ goto next;
+ }
+
+ goto done;
+ }
+
+ if (!result || !bt_gatt_iter_init(&iter, result)) {
+ success = false;
+ goto done;
+ }
+
+ includes_count = bt_gatt_result_included_count(result);
+ if (includes_count == 0) {
+ success = false;
+ goto done;
+ }
+
+ includes = new0(bt_gatt_included_service_t, includes_count);
+ if (!includes) {
+ success = false;
+ goto done;
+ }
+
+ util_debug(client->debug_callback, client->debug_data,
+ "Included services found: %u",
+ includes_count);
+
+ i = 0;
+ while (bt_gatt_iter_next_included_service(&iter, &includes[i].handle,
+ &includes[i].start_handle,
+ &includes[i].end_handle,
+ includes[i].uuid)) {
+ uuid_to_string(includes[i].uuid, uuid_str);
+ util_debug(client->debug_callback, client->debug_data,
+ "handle: 0x%04x, start: 0x%04x, end: 0x%04x,"
+ "uuid: %s", includes[i].handle,
+ includes[i].start_handle,
+ includes[i].end_handle, uuid_str);
+ i++;
+ }
+
+ op->cur_service->includes = includes;
+ op->cur_service->num_includes = includes_count;
+
+next:
+ if (!op->cur_service->next) {
+ op->cur_service = op->result_head;
+ if (bt_gatt_discover_characteristics(client->att,
+ op->cur_service->service.start_handle,
+ op->cur_service->service.end_handle,
+ discover_chrcs_cb,
+ discovery_op_ref(op),
+ discovery_op_unref))
+ return;
+
+ util_debug(client->debug_callback, client->debug_data,
+ "Failed to start characteristic discovery");
+ discovery_op_unref(op);
+ success = false;
+ goto done;
+ }
+
+ op->cur_service = op->cur_service->next;
+ if (bt_gatt_discover_included_services(client->att,
+ op->cur_service->service.start_handle,
+ op->cur_service->service.end_handle,
+ discover_incl_cb,
+ discovery_op_ref(op),
+ discovery_op_unref))
+ return;
+ util_debug(client->debug_callback, client->debug_data,
+ "Failed to start included discovery");
+ discovery_op_unref(op);
+ success = false;
+
+done:
+ op->complete_func(op, success, att_ecode);
+}
+
static void discover_descs_cb(bool success, uint8_t att_ecode,
struct bt_gatt_result *result,
void *user_data)
@@ -532,6 +637,7 @@ done:
op->complete_func(op, success, att_ecode);
}
+
static void discover_chrcs_cb(bool success, uint8_t att_ecode,
struct bt_gatt_result *result,
void *user_data)
@@ -702,18 +808,18 @@ static void discover_secondary_cb(bool success, uint8_t att_ecode,
}
next:
- /* Sequentially discover the characteristics of all services */
+ /* Sequentially discover included services */
op->cur_service = op->result_head;
- if (bt_gatt_discover_characteristics(client->att,
+ if (bt_gatt_discover_included_services(client->att,
op->cur_service->service.start_handle,
op->cur_service->service.end_handle,
- discover_chrcs_cb,
+ discover_incl_cb,
discovery_op_ref(op),
discovery_op_unref))
return;
util_debug(client->debug_callback, client->debug_data,
- "Failed to start characteristic discovery");
+ "Failed to start included services discovery");
discovery_op_unref(op);
success = false;
diff --git a/src/shared/gatt-client.h b/src/shared/gatt-client.h
index 22d4dc0..05b4838 100644
--- a/src/shared/gatt-client.h
+++ b/src/shared/gatt-client.h
@@ -96,6 +96,13 @@ typedef struct {
size_t num_descs;
} bt_gatt_characteristic_t;
+typedef struct {
+ uint16_t handle;
+ uint16_t start_handle;
+ uint16_t end_handle;
+ uint8_t uuid[BT_GATT_UUID_SIZE];
+} bt_gatt_included_service_t;
+
struct bt_gatt_service_iter {
struct bt_gatt_client *client;
void *ptr;
--
1.9.3
^ permalink raw reply related
* [PATCHv4 10/14] shared/gatt: Discover secondary services
From: Marcin Kraglak @ 2014-10-10 9:15 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1412932548-28363-1-git-send-email-marcin.kraglak@tieto.com>
Add searching of secondary services in gatt-client.
---
src/shared/gatt-client.c | 116 +++++++++++++++++++++++++++++++++++++++++------
1 file changed, 103 insertions(+), 13 deletions(-)
diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index 724fde2..9a0ec35 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
@@ -200,23 +200,36 @@ static void mark_notify_data_invalid_if_in_range(void *data, void *user_data)
notify_data->invalid = true;
}
-static bool service_list_add_service(struct service_list **head,
- struct service_list **tail,
- bool primary, uint16_t start,
- uint16_t end,
+static struct service_list *new_service_list(uint16_t start, uint16_t end,
+ bool primary,
uint8_t uuid[BT_GATT_UUID_SIZE])
{
struct service_list *list;
list = new0(struct service_list, 1);
if (!list)
- return false;
+ return NULL;
list->service.primary = primary;
list->service.start_handle = start;
list->service.end_handle = end;
memcpy(list->service.uuid, uuid, UUID_BYTES);
+ return list;
+}
+
+static bool service_list_add_service(struct service_list **head,
+ struct service_list **tail,
+ bool primary, uint16_t start,
+ uint16_t end,
+ uint8_t uuid[BT_GATT_UUID_SIZE])
+{
+ struct service_list *list;
+
+ list = new_service_list(start, end, primary, uuid);
+ if (!list)
+ return false;
+
if (!(*head))
*head = *tail = list;
else {
@@ -364,6 +377,8 @@ struct discovery_op {
struct bt_gatt_client *client;
struct service_list *result_head, *result_tail, *cur_service;
struct chrc_data *cur_chrc;
+ uint16_t start;
+ uint16_t end;
int cur_chrc_index;
int ref_count;
void (*complete_func)(struct discovery_op *op, bool success,
@@ -634,6 +649,78 @@ done:
op->complete_func(op, success, att_ecode);
}
+static void discover_secondary_cb(bool success, uint8_t att_ecode,
+ struct bt_gatt_result *result,
+ void *user_data)
+{
+ struct discovery_op *op = user_data;
+ struct bt_gatt_client *client = op->client;
+ struct bt_gatt_iter iter;
+ uint16_t start, end;
+ uint8_t uuid[BT_GATT_UUID_SIZE];
+ char uuid_str[MAX_LEN_UUID_STR];
+ struct service_list *service;
+
+ if (!success) {
+ util_debug(client->debug_callback, client->debug_data,
+ "Secondary service discovery failed."
+ " ATT ECODE: 0x%02x", att_ecode);
+ if (att_ecode == BT_ATT_ERROR_ATTRIBUTE_NOT_FOUND) {
+ success = true;
+ goto next;
+ }
+
+ goto done;
+ }
+
+ if (!result || !bt_gatt_iter_init(&iter, result)) {
+ success = false;
+ goto done;
+ }
+
+ util_debug(client->debug_callback, client->debug_data,
+ "Secondary services found: %u",
+ bt_gatt_result_service_count(result));
+
+ while (bt_gatt_iter_next_service(&iter, &start, &end, uuid)) {
+ uuid_to_string(uuid, uuid_str);
+ util_debug(client->debug_callback, client->debug_data,
+ "start: 0x%04x, end: 0x%04x, uuid: %s",
+ start, end, uuid_str);
+
+ /* Store the service */
+ service = new_service_list(start, end, false, uuid);
+ if (!service) {
+ util_debug(client->debug_callback, client->debug_data,
+ "Failed to create service");
+ success = false;
+ goto done;
+ }
+
+ service_list_insert_services(&op->result_head, &op->result_tail,
+ service, service);
+ }
+
+next:
+ /* Sequentially discover the characteristics of all services */
+ op->cur_service = op->result_head;
+ if (bt_gatt_discover_characteristics(client->att,
+ op->cur_service->service.start_handle,
+ op->cur_service->service.end_handle,
+ discover_chrcs_cb,
+ discovery_op_ref(op),
+ discovery_op_unref))
+ return;
+
+ util_debug(client->debug_callback, client->debug_data,
+ "Failed to start characteristic discovery");
+ discovery_op_unref(op);
+ success = false;
+
+done:
+ op->complete_func(op, success, att_ecode);
+}
+
static void discover_primary_cb(bool success, uint8_t att_ecode,
struct bt_gatt_result *result,
void *user_data)
@@ -686,18 +773,17 @@ static void discover_primary_cb(bool success, uint8_t att_ecode,
if (!op->result_head)
goto done;
- /* Sequentially discover the characteristics of all services */
+ /* Discover secondary services */
op->cur_service = op->result_head;
- if (bt_gatt_discover_characteristics(client->att,
- op->cur_service->service.start_handle,
- op->cur_service->service.end_handle,
- discover_chrcs_cb,
- discovery_op_ref(op),
- discovery_op_unref))
+ if (bt_gatt_discover_secondary_services(client->att, NULL,
+ op->start, op->end,
+ discover_secondary_cb,
+ discovery_op_ref(op),
+ discovery_op_unref))
return;
util_debug(client->debug_callback, client->debug_data,
- "Failed to start characteristic discovery");
+ "Failed to start secondary service discovery");
discovery_op_unref(op);
success = false;
@@ -870,6 +956,8 @@ static void process_service_changed(struct bt_gatt_client *client,
op->client = client;
op->complete_func = service_changed_complete;
+ op->start = start_handle;
+ op->end = end_handle;
if (!bt_gatt_discover_primary_services(client->att, NULL,
start_handle, end_handle,
@@ -1002,6 +1090,8 @@ static bool gatt_client_init(struct bt_gatt_client *client, uint16_t mtu)
op->client = client;
op->complete_func = init_complete;
+ op->start = 0x0001;
+ op->end = 0xffff;
/* Configure the MTU */
if (!bt_gatt_exchange_mtu(client->att, MAX(BT_ATT_DEFAULT_LE_MTU, mtu),
--
1.9.3
^ permalink raw reply related
* [PATCHv4 09/14] tools/btgatt-client: Print type of service
From: Marcin Kraglak @ 2014-10-10 9:15 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1412932548-28363-1-git-send-email-marcin.kraglak@tieto.com>
---
tools/btgatt-client.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/tools/btgatt-client.c b/tools/btgatt-client.c
index d900e08..5c692ff 100644
--- a/tools/btgatt-client.c
+++ b/tools/btgatt-client.c
@@ -182,8 +182,9 @@ static void print_service(const bt_gatt_service_t *service)
return;
}
- printf(COLOR_RED "service" COLOR_OFF " - start: 0x%04x, "
+ printf(COLOR_RED "service %s" COLOR_OFF " - start: 0x%04x, "
"end: 0x%04x, uuid: ",
+ service->primary ? "primary" : "second.",
service->start_handle, service->end_handle);
print_uuid(service->uuid);
--
1.9.3
^ permalink raw reply related
* [PATCHv4 08/14] shared/gatt: Distinguish Primary from Secondary services
From: Marcin Kraglak @ 2014-10-10 9:15 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1412932548-28363-1-git-send-email-marcin.kraglak@tieto.com>
Add flag primary to distinguish service as primary or secondary.
---
src/shared/gatt-client.c | 7 +++++--
src/shared/gatt-client.h | 1 +
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index 03d722f..724fde2 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
@@ -202,7 +202,8 @@ static void mark_notify_data_invalid_if_in_range(void *data, void *user_data)
static bool service_list_add_service(struct service_list **head,
struct service_list **tail,
- uint16_t start, uint16_t end,
+ bool primary, uint16_t start,
+ uint16_t end,
uint8_t uuid[BT_GATT_UUID_SIZE])
{
struct service_list *list;
@@ -211,6 +212,7 @@ static bool service_list_add_service(struct service_list **head,
if (!list)
return false;
+ list->service.primary = primary;
list->service.start_handle = start;
list->service.end_handle = end;
memcpy(list->service.uuid, uuid, UUID_BYTES);
@@ -668,7 +670,8 @@ static void discover_primary_cb(bool success, uint8_t att_ecode,
/* Store the service */
if (!service_list_add_service(&op->result_head,
- &op->result_tail, start, end, uuid)) {
+ &op->result_tail, true, start, end,
+ uuid)) {
util_debug(client->debug_callback, client->debug_data,
"Failed to store service");
success = false;
diff --git a/src/shared/gatt-client.h b/src/shared/gatt-client.h
index 6807f6b..22d4dc0 100644
--- a/src/shared/gatt-client.h
+++ b/src/shared/gatt-client.h
@@ -75,6 +75,7 @@ bool bt_gatt_client_set_debug(struct bt_gatt_client *client,
bt_gatt_client_destroy_func_t destroy);
typedef struct {
+ bool primary;
uint16_t start_handle;
uint16_t end_handle;
uint8_t uuid[BT_GATT_UUID_SIZE];
--
1.9.3
^ permalink raw reply related
* [PATCHv4 07/14] shared/gatt: Add function bt_gatt_result_included_count()
From: Marcin Kraglak @ 2014-10-10 9:15 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1412932548-28363-1-git-send-email-marcin.kraglak@tieto.com>
It will return number of included services in result.
---
src/shared/gatt-helpers.c | 21 +++++++++++++++++++++
src/shared/gatt-helpers.h | 1 +
2 files changed, 22 insertions(+)
diff --git a/src/shared/gatt-helpers.c b/src/shared/gatt-helpers.c
index 48e7379..92d0696 100644
--- a/src/shared/gatt-helpers.c
+++ b/src/shared/gatt-helpers.c
@@ -140,6 +140,27 @@ unsigned int bt_gatt_result_descriptor_count(struct bt_gatt_result *result)
return result_element_count(result);
}
+unsigned int bt_gatt_result_included_count(struct bt_gatt_result *result)
+{
+ struct bt_gatt_result *cur;
+ unsigned int count = 0;
+
+ if (!result)
+ return 0;
+
+ if (result->opcode != BT_ATT_OP_READ_BY_TYPE_RSP)
+ return 0;
+
+ if (result->data_len != 6 && result->data_len != 8)
+ return 0;
+
+ for (cur = result; cur; cur = cur->next)
+ if (cur->opcode == BT_ATT_OP_READ_BY_TYPE_RSP)
+ count += cur->pdu_len / cur->data_len;
+
+ return count;
+}
+
bool bt_gatt_iter_init(struct bt_gatt_iter *iter, struct bt_gatt_result *result)
{
if (!iter || !result)
diff --git a/src/shared/gatt-helpers.h b/src/shared/gatt-helpers.h
index f2c7ec5..07c145d 100644
--- a/src/shared/gatt-helpers.h
+++ b/src/shared/gatt-helpers.h
@@ -38,6 +38,7 @@ struct bt_gatt_iter {
unsigned int bt_gatt_result_service_count(struct bt_gatt_result *result);
unsigned int bt_gatt_result_characteristic_count(struct bt_gatt_result *result);
unsigned int bt_gatt_result_descriptor_count(struct bt_gatt_result *result);
+unsigned int bt_gatt_result_included_count(struct bt_gatt_result *result);
bool bt_gatt_iter_init(struct bt_gatt_iter *iter, struct bt_gatt_result *result);
bool bt_gatt_iter_next_service(struct bt_gatt_iter *iter,
--
1.9.3
^ permalink raw reply related
* [PATCHv4 06/14] shared/gatt: Remove not needed function parameter
From: Marcin Kraglak @ 2014-10-10 9:15 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1412932548-28363-1-git-send-email-marcin.kraglak@tieto.com>
According to SPEC 4.1 4.5.1 "Find Included Services" there is no need
to pass UUID to discover_included_services() function.
---
src/shared/gatt-helpers.c | 1 -
src/shared/gatt-helpers.h | 1 -
2 files changed, 2 deletions(-)
diff --git a/src/shared/gatt-helpers.c b/src/shared/gatt-helpers.c
index fd8d06c..48e7379 100644
--- a/src/shared/gatt-helpers.c
+++ b/src/shared/gatt-helpers.c
@@ -1002,7 +1002,6 @@ done:
bool bt_gatt_discover_included_services(struct bt_att *att,
uint16_t start, uint16_t end,
- bt_uuid_t *uuid,
bt_gatt_discovery_callback_t callback,
void *user_data,
bt_gatt_destroy_func_t destroy)
diff --git a/src/shared/gatt-helpers.h b/src/shared/gatt-helpers.h
index 8c434c1..f2c7ec5 100644
--- a/src/shared/gatt-helpers.h
+++ b/src/shared/gatt-helpers.h
@@ -82,7 +82,6 @@ bool bt_gatt_discover_secondary_services(struct bt_att *att, bt_uuid_t *uuid,
bt_gatt_destroy_func_t destroy);
bool bt_gatt_discover_included_services(struct bt_att *att,
uint16_t start, uint16_t end,
- bt_uuid_t *uuid,
bt_gatt_discovery_callback_t callback,
void *user_data,
bt_gatt_destroy_func_t destroy);
--
1.9.3
^ permalink raw reply related
* [PATCHv4 05/14] shared/gatt: Add included service iterator
From: Marcin Kraglak @ 2014-10-10 9:15 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1412932548-28363-1-git-send-email-marcin.kraglak@tieto.com>
It will fetch included services from result.
---
src/shared/gatt-helpers.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++
src/shared/gatt-helpers.h | 3 +++
2 files changed, 61 insertions(+)
diff --git a/src/shared/gatt-helpers.c b/src/shared/gatt-helpers.c
index 58104d9..fd8d06c 100644
--- a/src/shared/gatt-helpers.c
+++ b/src/shared/gatt-helpers.c
@@ -186,6 +186,64 @@ struct discovery_op {
bt_gatt_destroy_func_t destroy;
};
+bool bt_gatt_iter_next_included_service(struct bt_gatt_iter *iter,
+ uint16_t *handle, uint16_t *start_handle,
+ uint16_t *end_handle, uint8_t uuid[16])
+{
+ struct bt_gatt_result *read_result;
+ const void *pdu_ptr;
+ int i = 0;
+
+ if (!iter || !iter->result || !handle || !start_handle || !end_handle
+ || !uuid)
+ return false;
+
+ if (iter->result->opcode != BT_ATT_OP_READ_BY_TYPE_RSP)
+ return false;
+
+ if (iter->result->data_len != 8 && iter->result->data_len != 6)
+ return false;
+
+ pdu_ptr = iter->result->pdu + iter->pos;
+
+ if (iter->result->data_len == 8) {
+ *handle = get_le16(pdu_ptr);
+ *start_handle = get_le16(pdu_ptr + 2);
+ *end_handle = get_le16(pdu_ptr + 4);
+ convert_uuid_le(pdu_ptr + 6, 2, uuid);
+
+ iter->pos += iter->result->data_len;
+
+ if (iter->pos == iter->result->pdu_len) {
+ iter->result = iter->result->next;
+ iter->pos = 0;
+ }
+
+ return true;
+ }
+
+ *handle = get_le16(pdu_ptr);
+ *start_handle = get_le16(pdu_ptr + 2);
+ *end_handle = get_le16(pdu_ptr + 4);
+ read_result = iter->result;
+
+ do {
+ read_result = read_result->next;
+ } while (read_result && i++ < (iter->pos / iter->result->data_len));
+
+ if (!read_result)
+ return false;
+
+ convert_uuid_le(read_result->pdu, read_result->data_len, uuid);
+ iter->pos += iter->result->data_len;
+ if (iter->pos == iter->result->pdu_len) {
+ iter->result = read_result->next;
+ iter->pos = 0;
+ }
+
+ return true;
+}
+
bool bt_gatt_iter_next_service(struct bt_gatt_iter *iter,
uint16_t *start_handle, uint16_t *end_handle,
uint8_t uuid[16])
diff --git a/src/shared/gatt-helpers.h b/src/shared/gatt-helpers.h
index 8a25dea..8c434c1 100644
--- a/src/shared/gatt-helpers.h
+++ b/src/shared/gatt-helpers.h
@@ -49,6 +49,9 @@ bool bt_gatt_iter_next_characteristic(struct bt_gatt_iter *iter,
uint8_t uuid[16]);
bool bt_gatt_iter_next_descriptor(struct bt_gatt_iter *iter, uint16_t *handle,
uint8_t uuid[16]);
+bool bt_gatt_iter_next_included_service(struct bt_gatt_iter *iter,
+ uint16_t *handle, uint16_t *start_handle,
+ uint16_t *end_handle, uint8_t uuid[16]);
typedef void (*bt_gatt_destroy_func_t)(void *user_data);
--
1.9.3
^ permalink raw reply related
* [PATCHv4 04/14] shared/gatt: Add extra check in characteristic iterator
From: Marcin Kraglak @ 2014-10-10 9:15 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1412932548-28363-1-git-send-email-marcin.kraglak@tieto.com>
Avoid incorrect reading of included service discovery results.
---
src/shared/gatt-helpers.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/shared/gatt-helpers.c b/src/shared/gatt-helpers.c
index c18f738..58104d9 100644
--- a/src/shared/gatt-helpers.c
+++ b/src/shared/gatt-helpers.c
@@ -123,6 +123,9 @@ unsigned int bt_gatt_result_characteristic_count(struct bt_gatt_result *result)
if (result->opcode != BT_ATT_OP_READ_BY_TYPE_RSP)
return 0;
+ if (result->data_len != 21 && result->data_len != 7)
+ return 0;
+
return result_element_count(result);
}
@@ -239,6 +242,9 @@ bool bt_gatt_iter_next_characteristic(struct bt_gatt_iter *iter,
if (iter->result->opcode != BT_ATT_OP_READ_BY_TYPE_RSP)
return false;
+ if (iter->result->data_len != 21 && iter->result->data_len != 7)
+ return false;
+
op = iter->result->op;
pdu_ptr = iter->result->pdu + iter->pos;
--
1.9.3
^ permalink raw reply related
* [PATCHv4 03/14] shared/gatt: Discover included services 128 bit UUIDS
From: Marcin Kraglak @ 2014-10-10 9:15 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1412932548-28363-1-git-send-email-marcin.kraglak@tieto.com>
If included services has 128 bit UUID, it won't be returned in
READ_BY_TYPE_RSP. To get UUID READ_REQUEST is used.
This procedure is described in CORE SPEC 4.5.1 "Find Included Services".
---
src/shared/gatt-helpers.c | 170 +++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 169 insertions(+), 1 deletion(-)
diff --git a/src/shared/gatt-helpers.c b/src/shared/gatt-helpers.c
index dcb2a2f..c18f738 100644
--- a/src/shared/gatt-helpers.c
+++ b/src/shared/gatt-helpers.c
@@ -692,6 +692,160 @@ bool bt_gatt_discover_secondary_services(struct bt_att *att, bt_uuid_t *uuid,
destroy, false);
}
+struct read_incl_data {
+ struct discovery_op *op;
+ struct bt_gatt_result *result;
+ int pos;
+ int ref_count;
+};
+
+static struct read_incl_data *new_read_included(struct bt_gatt_result *res)
+{
+ struct read_incl_data *data;
+
+ data = new0(struct read_incl_data, 1);
+ if (!data)
+ return NULL;
+
+ data->op = discovery_op_ref(res->op);
+ data->result = res;
+
+ return data;
+};
+
+static struct read_incl_data *read_included_ref(struct read_incl_data *data)
+{
+ __sync_fetch_and_add(&data->ref_count, 1);
+
+ return data;
+}
+
+static void read_included_unref(void *data)
+{
+ struct read_incl_data *read_data = data;
+
+ if (__sync_sub_and_fetch(&read_data->ref_count, 1))
+ return;
+
+ discovery_op_unref(read_data->op);
+
+ free(read_data);
+}
+
+static void discover_included_cb(uint8_t opcode, const void *pdu,
+ uint16_t length, void *user_data);
+
+static void read_included_cb(uint8_t opcode, const void *pdu,
+ uint16_t length, void *user_data)
+{
+ struct read_incl_data *data = user_data;
+ struct bt_gatt_result *final_result = NULL;
+ struct discovery_op *op = data->op;
+ struct bt_gatt_result *cur_result;
+ uint8_t att_ecode = 0;
+ uint16_t handle;
+ uint8_t read_pdu[2];
+ bool success;
+
+ if (opcode == BT_ATT_OP_ERROR_RSP) {
+ success = false;
+ att_ecode = process_error(pdu, length);
+ goto done;
+ }
+
+ if (opcode != BT_ATT_OP_READ_RSP || (!pdu && length)) {
+ success = false;
+ goto done;
+ }
+
+ if (length != 16) {
+ success = false;
+ goto done;
+ }
+ cur_result = result_create(opcode, pdu, length, length, op);
+ if (!cur_result) {
+ success = false;
+ goto done;
+ }
+
+ if (!op->result_head)
+ op->result_head = op->result_tail = cur_result;
+ else {
+ op->result_tail->next = cur_result;
+ op->result_tail = cur_result;
+ }
+
+ if (data->pos == data->result->pdu_len) {
+ uint16_t last_handle, data_len;
+ uint8_t pdu[6];
+
+ data_len = data->result->data_len;
+ last_handle = get_le16(data->result->pdu + data->pos -
+ data_len);
+ if (last_handle == op->end_handle) {
+ final_result = op->result_head;
+ success = true;
+ goto done;
+ }
+
+ put_le16(last_handle + 1, pdu);
+ put_le16(op->end_handle, pdu + 2);
+ put_le16(GATT_INCLUDE_UUID, pdu + 4);
+
+ if (bt_att_send(op->att, BT_ATT_OP_READ_BY_TYPE_REQ,
+ pdu, sizeof(pdu),
+ discover_included_cb,
+ discovery_op_ref(op),
+ discovery_op_unref))
+ return;
+
+ discovery_op_unref(op);
+ success = false;
+ goto done;
+ }
+
+ handle = get_le16(data->result->pdu + data->pos + 2);
+ put_le16(handle, read_pdu);
+
+ data->pos += data->result->data_len;
+
+ if (bt_att_send(op->att, BT_ATT_OP_READ_REQ, read_pdu, sizeof(read_pdu),
+ read_included_cb,
+ read_included_ref(data),
+ read_included_unref))
+ return;
+
+ read_included_unref(data);
+ success = false;
+
+done:
+ if (op->callback)
+ op->callback(success, att_ecode, final_result, op->user_data);
+}
+
+static void read_included(struct read_incl_data *data)
+{
+ struct discovery_op *op = data->op;
+ uint16_t handle;
+ uint8_t pdu[2];
+
+ handle = get_le16(data->result->pdu + 2);
+ put_le16(handle, pdu);
+
+ data->pos += data->result->data_len;
+
+ if (bt_att_send(op->att, BT_ATT_OP_READ_REQ, pdu, sizeof(pdu),
+ read_included_cb,
+ read_included_ref(data),
+ read_included_unref))
+ return;
+
+ read_included_unref(data);
+
+ if (op->callback)
+ op->callback(false, 0, NULL, data->op->user_data);
+}
+
static void discover_included_cb(uint8_t opcode, const void *pdu,
uint16_t length, void *user_data)
{
@@ -721,7 +875,8 @@ static void discover_included_cb(uint8_t opcode, const void *pdu,
data_length = ((uint8_t *) pdu)[0];
- if ((length - 1) % data_length || data_length != 8) {
+ if (((length - 1) % data_length) ||
+ (data_length != 8 && data_length != 6)) {
success = false;
goto done;
}
@@ -740,6 +895,19 @@ static void discover_included_cb(uint8_t opcode, const void *pdu,
op->result_tail = cur_result;
}
+ if (data_length == 6) {
+ struct read_incl_data *data;
+
+ data = new_read_included(cur_result);
+ if (!data) {
+ success = false;
+ goto done;
+ }
+
+ read_included(data);
+ return;
+ }
+
last_handle = get_le16(pdu + length - data_length);
if (last_handle != op->end_handle) {
uint8_t pdu[6];
--
1.9.3
^ 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