* [RFC v2 02/14] Use host byte order when converting UUID16/32 to UUID128
From: Claudio Takahasi @ 2011-02-18 22:29 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1298068173-16518-1-git-send-email-claudio.takahasi@openbossa.org>
uuid_t should store the UUID-128 values in the host byte order to
keep the consistency with UUID-16 and UUID32.
---
lib/sdp.c | 20 ++++++++++++++------
1 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/lib/sdp.c b/lib/sdp.c
index d24d1e2..af50a16 100644
--- a/lib/sdp.c
+++ b/lib/sdp.c
@@ -2629,6 +2629,8 @@ int sdp_uuid128_cmp(const void *p1, const void *p2)
*/
void sdp_uuid16_to_uuid128(uuid_t *uuid128, const uuid_t *uuid16)
{
+ uint128_t n128;
+
/*
* We have a 16 bit value, which needs to be added to
* bytes 3 and 4 (at indices 2 and 3) of the Bluetooth base
@@ -2636,8 +2638,7 @@ void sdp_uuid16_to_uuid128(uuid_t *uuid128, const uuid_t *uuid16)
unsigned short data1;
/* allocate a 128bit UUID and init to the Bluetooth base UUID */
- uuid128->value.uuid128 = bluetooth_base_uuid;
- uuid128->type = SDP_UUID128;
+ n128 = bluetooth_base_uuid;
/* extract bytes 2 and 3 of 128bit BT base UUID */
memcpy(&data1, &bluetooth_base_uuid.data[2], 2);
@@ -2646,11 +2647,16 @@ void sdp_uuid16_to_uuid128(uuid_t *uuid128, const uuid_t *uuid16)
data1 += htons(uuid16->value.uuid16);
/* set bytes 2 and 3 of the 128 bit value */
- memcpy(&uuid128->value.uuid128.data[2], &data1, 2);
+ memcpy(&n128.data[2], &data1, 2);
+
+ uuid128->type = SDP_UUID128;
+ ntoh128(&n128, &uuid128->value.uuid128);
}
void sdp_uuid32_to_uuid128(uuid_t *uuid128, const uuid_t *uuid32)
{
+ uint128_t n128;
+
/*
* We have a 32 bit value, which needs to be added to
* bytes 1->4 (at indices 0 thru 3) of the Bluetooth base
@@ -2658,8 +2664,7 @@ void sdp_uuid32_to_uuid128(uuid_t *uuid128, const uuid_t *uuid32)
unsigned int data0;
/* allocate a 128bit UUID and init to the Bluetooth base UUID */
- uuid128->value.uuid128 = bluetooth_base_uuid;
- uuid128->type = SDP_UUID128;
+ n128 = bluetooth_base_uuid;
/* extract first 4 bytes */
memcpy(&data0, &bluetooth_base_uuid.data[0], 4);
@@ -2668,7 +2673,10 @@ void sdp_uuid32_to_uuid128(uuid_t *uuid128, const uuid_t *uuid32)
data0 += htonl(uuid32->value.uuid32);
/* set the 4 bytes of the 128 bit value */
- memcpy(&uuid128->value.uuid128.data[0], &data0, 4);
+ memcpy(&n128.data[0], &data0, 4);
+
+ uuid128->type = SDP_UUID128;
+ ntoh128(&n128, &uuid128->value.uuid128);
}
uuid_t *sdp_uuid_to_uuid128(const uuid_t *uuid)
--
1.7.4.1
^ permalink raw reply related
* [RFC v2 01/14] Move 64 and 128 bits byte order functions to bluetooth.h
From: Claudio Takahasi @ 2011-02-18 22:29 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1298068173-16518-1-git-send-email-claudio.takahasi@openbossa.org>
---
attrib/example.c | 1 +
attrib/gatt.c | 1 +
attrib/interactive.c | 1 +
health/hdp_manager.c | 1 +
health/mcap_sync.c | 17 -----------------
lib/bluetooth.h | 41 +++++++++++++++++++++++++++++++++++++++++
lib/sdp.c | 43 -------------------------------------------
lib/sdp.h | 4 ----
src/sdp-xml.c | 1 +
test/hciemu.c | 16 ----------------
10 files changed, 46 insertions(+), 80 deletions(-)
diff --git a/attrib/example.c b/attrib/example.c
index 1911912..f5fcf1b 100644
--- a/attrib/example.c
+++ b/attrib/example.c
@@ -29,6 +29,7 @@
#include <arpa/inet.h>
+#include <bluetooth/bluetooth.h>
#include <bluetooth/sdp.h>
#include <bluetooth/sdp_lib.h>
diff --git a/attrib/gatt.c b/attrib/gatt.c
index 20bb96f..b99d39c 100644
--- a/attrib/gatt.c
+++ b/attrib/gatt.c
@@ -24,6 +24,7 @@
#include <stdint.h>
#include <glib.h>
+#include <bluetooth/bluetooth.h>
#include <bluetooth/sdp.h>
#include <bluetooth/sdp_lib.h>
diff --git a/attrib/interactive.c b/attrib/interactive.c
index edc465a..f797f71 100644
--- a/attrib/interactive.c
+++ b/attrib/interactive.c
@@ -25,6 +25,7 @@
#include <stdio.h>
#include <glib.h>
+#include <bluetooth/bluetooth.h>
#include <bluetooth/sdp.h>
#include <bluetooth/sdp_lib.h>
diff --git a/health/hdp_manager.c b/health/hdp_manager.c
index 88b49fc..8ba1720 100644
--- a/health/hdp_manager.c
+++ b/health/hdp_manager.c
@@ -27,6 +27,7 @@
#include <config.h>
#endif
+#include <bluetooth/bluetooth.h>
#include <bluetooth/sdp.h>
#include <bluetooth/sdp_lib.h>
diff --git a/health/mcap_sync.c b/health/mcap_sync.c
index 6f90344..20311a2 100644
--- a/health/mcap_sync.c
+++ b/health/mcap_sync.c
@@ -92,23 +92,6 @@ struct sync_set_data {
gboolean role;
};
-/* Ripped from lib/sdp.c */
-
-#if __BYTE_ORDER == __BIG_ENDIAN
-#define ntoh64(x) (x)
-#else
-static inline uint64_t ntoh64(uint64_t n)
-{
- uint64_t h;
- uint64_t tmp = ntohl(n & 0x00000000ffffffff);
- h = ntohl(n >> 32);
- h |= tmp << 32;
- return h;
-}
-#endif
-
-#define hton64(x) ntoh64(x)
-
static gboolean csp_caps_initialized = FALSE;
struct csp_caps _caps;
diff --git a/lib/bluetooth.h b/lib/bluetooth.h
index bc0921e..d8f36f8 100644
--- a/lib/bluetooth.h
+++ b/lib/bluetooth.h
@@ -35,6 +35,7 @@ extern "C" {
#include <string.h>
#include <endian.h>
#include <byteswap.h>
+#include <arpa/inet.h>
#ifndef AF_BLUETOOTH
#define AF_BLUETOOTH 31
@@ -88,21 +89,61 @@ enum {
BT_CLOSED
};
+typedef struct {
+ uint8_t data[16];
+} uint128_t;
+
/* Byte order conversions */
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define htobs(d) (d)
#define htobl(d) (d)
#define btohs(d) (d)
#define btohl(d) (d)
+static inline uint64_t ntoh64(uint64_t n)
+{
+ uint64_t h;
+ uint64_t tmp = ntohl(n & 0x00000000ffffffff);
+ h = ntohl(n >> 32);
+ h |= tmp << 32;
+ return h;
+}
+
+static inline void ntoh128(const uint128_t *src, uint128_t *dst)
+{
+ int i;
+ for (i = 0; i < 16; i++)
+ dst->data[15 - i] = src->data[i];
+}
+
+static inline void btoh128(const uint128_t *src, uint128_t *dst)
+{
+ memcpy(dst, src, sizeof(uint128_t));
+}
#elif __BYTE_ORDER == __BIG_ENDIAN
#define htobs(d) bswap_16(d)
#define htobl(d) bswap_32(d)
#define btohs(d) bswap_16(d)
#define btohl(d) bswap_32(d)
+#define ntoh64(x) (x)
+static inline void ntoh128(const uint128_t *src, uint128_t *dst)
+{
+ memcpy(dst, src, sizeof(uint128_t));
+}
+
+static inline void btoh128(const uint128_t *src, uint128_t *dst)
+{
+ int i;
+ for (i = 0; i < 16; i++)
+ dst->data[15 - i] = src->data[i];
+}
#else
#error "Unknown byte order"
#endif
+#define hton64(x) ntoh64(x)
+#define hton128(x, y) ntoh128(x, y)
+#define htob128(x, y) btoh128(x, y)
+
/* Bluetooth unaligned access */
#define bt_get_unaligned(ptr) \
({ \
diff --git a/lib/sdp.c b/lib/sdp.c
index e782aec..d24d1e2 100644
--- a/lib/sdp.c
+++ b/lib/sdp.c
@@ -60,49 +60,6 @@
#define SDPDBG(fmt...)
#endif
-#if __BYTE_ORDER == __BIG_ENDIAN
-#define ntoh64(x) (x)
-static inline void ntoh128(const uint128_t *src, uint128_t *dst)
-{
- memcpy(dst, src, sizeof(uint128_t));
-}
-
-static inline void btoh128(const uint128_t *src, uint128_t *dst)
-{
- int i;
- for (i = 0; i < 16; i++)
- dst->data[15 - i] = src->data[i];
-
-}
-
-#else
-static inline uint64_t ntoh64(uint64_t n)
-{
- uint64_t h;
- uint64_t tmp = ntohl(n & 0x00000000ffffffff);
- h = ntohl(n >> 32);
- h |= tmp << 32;
- return h;
-}
-
-static inline void ntoh128(const uint128_t *src, uint128_t *dst)
-{
- int i;
- for (i = 0; i < 16; i++)
- dst->data[15 - i] = src->data[i];
-}
-
-static inline void btoh128(const uint128_t *src, uint128_t *dst)
-{
- memcpy(dst, src, sizeof(uint128_t));
-}
-
-#endif
-
-#define hton64(x) ntoh64(x)
-#define hton128(x, y) ntoh128(x, y)
-#define htob128(x, y) btoh128(x, y)
-
#define BASE_UUID "00000000-0000-1000-8000-00805F9B34FB"
static uint128_t bluetooth_base_uuid = {
diff --git a/lib/sdp.h b/lib/sdp.h
index e901b2a..4e0396a 100644
--- a/lib/sdp.h
+++ b/lib/sdp.h
@@ -421,10 +421,6 @@ typedef struct {
* Should the type of any of these change, you need only make a change here.
*/
typedef struct {
- uint8_t data[16];
-} uint128_t;
-
-typedef struct {
uint8_t type;
union {
uint16_t uuid16;
diff --git a/src/sdp-xml.c b/src/sdp-xml.c
index 3aa9df0..48a3808 100644
--- a/src/sdp-xml.c
+++ b/src/sdp-xml.c
@@ -33,6 +33,7 @@
#include <limits.h>
#include <stdlib.h>
+#include <bluetooth/bluetooth.h>
#include <bluetooth/sdp.h>
#include <bluetooth/sdp_lib.h>
diff --git a/test/hciemu.c b/test/hciemu.c
index 5227766..757a75c 100644
--- a/test/hciemu.c
+++ b/test/hciemu.c
@@ -52,22 +52,6 @@
#include <glib.h>
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-static inline uint64_t ntoh64(uint64_t n)
-{
- uint64_t h;
- uint64_t tmp = ntohl(n & 0x00000000ffffffff);
- h = ntohl(n >> 32);
- h |= tmp << 32;
- return h;
-}
-#elif __BYTE_ORDER == __BIG_ENDIAN
-#define ntoh64(x) (x)
-#else
-#error "Unknown byte order"
-#endif
-#define hton64(x) ntoh64(x)
-
#define GHCI_DEV "/dev/ghci"
#define VHCI_DEV "/dev/vhci"
--
1.7.4.1
^ permalink raw reply related
* [RFC v2 00/14] Store UUID-128 on host order
From: Claudio Takahasi @ 2011-02-18 22:29 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Claudio Takahasi
It must NOT be included in the next release until proper testing.
Any good soul wants to test it if I am not breaking SDP?
The following patches convert the internal UUID128 values representation
to host order. Currently, SDP functions use host order to store UUID-16
/UUID32 and network order to store UUID-128 values. The reason is to
keep the consistency and re-use the UUID functions for ATT protocol
which uses little endian.
Changes from the first RFC:
- Changes sdptool
- Changes SDP XML parsing function
- Changes attribute example
Claudio Takahasi (14):
Move 64 and 128 bits byte order functions to bluetooth.h
Use host byte order when converting UUID16/32 to UUID128
Add att_get_u128
Convert UUID128 value to host order when extracting SDP data
Convert to network order before use it on sdp_uuid128_to_uuid
Convert from host to network order before to print UUID128 values
Convert from network to host order on bt_string2uuid function
Change UUID128 host order on SDP PDU generation function
Replace UUID128 values from char array to uint128_t on sdptool
Create UUID128 on host order on sdptool
Change SDP XML parser to create UUID128 values on host order
Convert from little endian to host order when parsing EIR data
Add att_put_u128
Change Attribute example to create UUID128 on host order
attrib/att.c | 16 ++++--
attrib/att.h | 17 ++++++
attrib/example.c | 24 +++++---
attrib/gatt.c | 14 +++--
attrib/gatttool.c | 6 ++-
attrib/interactive.c | 1 +
health/hdp_manager.c | 1 +
health/mcap_sync.c | 17 ------
lib/bluetooth.h | 41 ++++++++++++++
lib/sdp.c | 108 ++++++++++++++-----------------------
lib/sdp.h | 4 --
src/event.c | 6 +--
src/glib-helper.c | 31 ++++++-----
src/sdp-xml.c | 74 +++++++++++--------------
test/hciemu.c | 16 ------
tools/sdptool.c | 145 ++++++++++++++++++++++++++++++-------------------
16 files changed, 280 insertions(+), 241 deletions(-)
--
1.7.4.1
^ permalink raw reply
* Re: [PATCH 1/1 rev2] Add SDP registration of Primary GATT services
From: Anderson Lizardo @ 2011-02-18 22:03 UTC (permalink / raw)
To: Brian Gix; +Cc: linux-bluetooth, johan.hedberg, padovan
In-Reply-To: <1298061379-4816-2-git-send-email-bgix@codeaurora.org>
Hi Brian,
On Fri, Feb 18, 2011 at 5:36 PM, Brian Gix <bgix@codeaurora.org> wrote:
> Add capability to register SDP record for Primary Services.
> ---
> attrib/example.c | 29 +++++++++-
> src/attrib-server.c | 162 +++++++++++++++++++++++++++++++++++++++------------
> src/attrib-server.h | 3 +-
> 3 files changed, 155 insertions(+), 39 deletions(-)
>
> diff --git a/attrib/example.c b/attrib/example.c
> index 1911912..f0648e4 100644
> --- a/attrib/example.c
> +++ b/attrib/example.c
> @@ -59,6 +59,9 @@
> #define FMT_KILOGRAM_UUID 0xA010
> #define FMT_HANGING_UUID 0xA011
>
> +#define SDP_RECORD_COUNT 10
> +uint32_t sdp_handles[SDP_RECORD_COUNT];
> +
This should be static, right?
What about using a GSList *, instead of a statically allocated structure?
> static int register_attributes(void)
> {
> const char *desc_out_temp = "Outside Temperature";
> @@ -77,6 +80,7 @@ static int register_attributes(void)
> uint8_t atval[256];
> uuid_t uuid;
> int len;
> + int i = 0;
>
> /* Battery state service: primary service definition */
> sdp_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
> @@ -101,6 +105,11 @@ static int register_attributes(void)
> atval[1] = 0x00;
> attrib_db_add(0x0111, &uuid, ATT_NONE, ATT_AUTHENTICATION, atval, 2);
>
> + /* Add an SDP record for the above service */
> + sdp_handles[i] = attrib_create_sdp(0x0100, "Battery State Service");
> + if (sdp_handles[i])
> + i++;
> +
> /* Thermometer: primary service definition */
> sdp_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
> att_put_u16(THERM_HUMIDITY_SVC_UUID, &atval[0]);
> @@ -116,7 +125,8 @@ static int register_attributes(void)
> /* Thermometer: Include */
> att_put_u16(0x0550, &atval[0]);
> att_put_u16(0x0568, &atval[2]);
> - attrib_db_add(0x0202, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 4);
> + att_put_u16(VENDOR_SPECIFIC_SVC_UUID, &atval[4]);
> + attrib_db_add(0x0202, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 6);
This change does not seem realted to the patch.
>
> /* Thermometer: temperature characteristic */
> sdp_uuid16_create(&uuid, GATT_CHARAC_UUID);
> @@ -173,6 +183,11 @@ static int register_attributes(void)
> strncpy((char *) atval, desc_out_hum, len);
> attrib_db_add(0x0214, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, len);
>
> + /* Add an SDP record for the above service */
> + sdp_handles[i] = attrib_create_sdp(0x0200, "Thermometer");
> + if (sdp_handles[i])
> + i++;
> +
> /* Secondary Service: Manufacturer Service */
> sdp_uuid16_create(&uuid, GATT_SND_SVC_UUID);
> att_put_u16(MANUFACTURER_SVC_UUID, &atval[0]);
> @@ -299,6 +314,11 @@ static int register_attributes(void)
> strncpy((char *) atval, desc_weight, len);
> attrib_db_add(0x0685, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, len);
>
> + /* Add an SDP record for the above service */
> + sdp_handles[i] = attrib_create_sdp(0x0680, "Weight Service");
> + if (sdp_handles[i])
> + i++;
> +
> return 0;
> }
>
> @@ -309,4 +329,11 @@ int server_example_init(void)
>
> void server_example_exit(void)
> {
> + int i;
> +
> + for (i = 0; i < SDP_RECORD_COUNT; i++)
> + if (sdp_handles[i]) {
> + attrib_free_sdp(sdp_handles[i]);
> + sdp_handles[i] = 0;
> + }
Again, using GSList will make this simpler.
> }
> diff --git a/src/attrib-server.c b/src/attrib-server.c
> index 5e00601..78e347c 100644
> --- a/src/attrib-server.c
> +++ b/src/attrib-server.c
> @@ -70,7 +70,8 @@ struct group_elem {
> static GIOChannel *l2cap_io = NULL;
> static GIOChannel *le_io = NULL;
> static GSList *clients = NULL;
> -static uint32_t sdp_handle = 0;
> +static uint32_t gatt_sdp_handle = 0;
> +static uint32_t gap_sdp_handle = 0;
>
> /* GAP attribute handles */
> static uint16_t name_handle = 0x0000;
> @@ -85,14 +86,19 @@ static uuid_t snd_uuid = {
> .value.uuid16 = GATT_SND_SVC_UUID
> };
>
> -static sdp_record_t *server_record_new(void)
> +static sdp_record_t *server_record_new(uuid_t *uuid, uint16_t start, uint16_t end)
> {
> - sdp_list_t *svclass_id, *apseq, *proto[2], *profiles, *root, *aproto;
> + sdp_list_t *svclass_id, *apseq, *proto[2], *root, *aproto;
> uuid_t root_uuid, proto_uuid, gatt_uuid, l2cap;
> - sdp_profile_desc_t profile;
> sdp_record_t *record;
> sdp_data_t *psm, *sh, *eh;
> - uint16_t lp = GATT_PSM, start = 0x0001, end = 0xffff;
> + uint16_t lp = GATT_PSM;
> +
> + if (uuid == NULL)
> + return NULL;
> +
> + if (start > end)
> + return NULL;
>
> record = sdp_record_alloc();
> if (record == NULL)
> @@ -103,17 +109,10 @@ static sdp_record_t *server_record_new(void)
> sdp_set_browse_groups(record, root);
> sdp_list_free(root, NULL);
>
> - sdp_uuid16_create(&gatt_uuid, GENERIC_ATTRIB_SVCLASS_ID);
> - svclass_id = sdp_list_append(NULL, &gatt_uuid);
> + svclass_id = sdp_list_append(NULL, uuid);
> sdp_set_service_classes(record, svclass_id);
> sdp_list_free(svclass_id, NULL);
>
> - sdp_uuid16_create(&profile.uuid, GENERIC_ATTRIB_PROFILE_ID);
> - profile.version = 0x0100;
> - profiles = sdp_list_append(NULL, &profile);
> - sdp_set_profile_descs(record, profiles);
> - sdp_list_free(profiles, NULL);
> -
> sdp_uuid16_create(&l2cap, L2CAP_UUID);
> proto[0] = sdp_list_append(NULL, &l2cap);
> psm = sdp_data_alloc(SDP_UINT16, &lp);
> @@ -131,11 +130,6 @@ static sdp_record_t *server_record_new(void)
> aproto = sdp_list_append(NULL, apseq);
> sdp_set_access_protos(record, aproto);
>
> - sdp_set_info_attr(record, "Generic Attribute Profile", "BlueZ", NULL);
> -
> - sdp_set_url_attr(record, "http://www.bluez.org/",
> - "http://www.bluez.org/", "http://www.bluez.org/");
> -
> sdp_set_service_id(record, gatt_uuid);
>
> sdp_data_free(psm);
> @@ -180,6 +174,40 @@ static uint8_t att_check_reqs(struct gatt_channel *channel, uint8_t opcode,
> return 0;
> }
>
> +static struct attribute *find_primary_range(uint16_t start, uint16_t *end)
> +{
> + struct attribute *a, *attrib = NULL;
Move declaration of "struct attribute *a" to the for(), because it is
used only there.
> + GSList *l;
> + gboolean found = FALSE;
> +
> + if (end == NULL)
> + return NULL;
> +
> + for (l = database; l; l = l->next) {
> + a = l->data;
> +
> + if (a->handle < start)
> + continue;
I find the logic of this loop too complex.
What about using g_slist_find_custom() (like in other places of GATT
code) to find the attribute with the given handle, them check it is a
primary service definition? You can then iterate directly from the
next attribute, e.g.:
guint h = handle;
l = g_slist_find_custom(database, GUINT_TO_POINTER(h), handle_cmp);
if (!l)
return NULL;
attrib = found_prim->data;
*end = start; // a sane default
for (l = found_prim->next; l; l = l->next) {
Then, you could the check for primary/secondary service to know if the
service has ended (just pasting your own code):
> + if (sdp_uuid_cmp(&a->uuid, &prim_uuid) == 0 ||
> + sdp_uuid_cmp(&a->uuid, &snd_uuid) == 0)
> + break;
You can then update the *end:
*end = a->handle;
} // end of for()
return attrib;
At this point *end should contain the corrent *end. Not tested :)
Next, you could check if the iteration was until the end of the list:
> +
> + if ((a->handle == start) &&
> + sdp_uuid_cmp(&a->uuid, &prim_uuid) == 0) {
> + found = TRUE;
> + *end = start;
> + attrib = a;
> + continue;
> + } else if (!found)
> + break;
> +
> + if (sdp_uuid_cmp(&a->uuid, &prim_uuid) == 0 ||
> + sdp_uuid_cmp(&a->uuid, &snd_uuid) == 0)
> + break;
> + else
> + *end = a->handle;
> + }
> +
> + return attrib;
> +}
> +
> static uint16_t read_by_group(struct gatt_channel *channel, uint16_t start,
> uint16_t end, uuid_t *uuid,
> uint8_t *pdu, int len)
> @@ -611,7 +639,7 @@ static uint16_t write_value(struct gatt_channel *channel, uint16_t handle,
> static uint16_t mtu_exchange(struct gatt_channel *channel, uint16_t mtu,
> uint8_t *pdu, int len)
> {
> - channel->mtu = MIN(mtu, ATT_MAX_MTU);
> + channel->mtu = MIN(mtu, channel->mtu);
>
> return enc_mtu_resp(channel->mtu, pdu, len);
> }
I still think this change should go in a separate patch, as it fixes
another bug.
> @@ -798,7 +826,7 @@ static void confirm_event(GIOChannel *io, void *user_data)
> return;
> }
>
> -static void register_core_services(void)
> +static gboolean register_core_services(void)
> {
> uint8_t atval[256];
> uuid_t uuid;
> @@ -835,17 +863,37 @@ static void register_core_services(void)
> att_put_u16(appearance, &atval[0]);
> attrib_db_add(appearance_handle, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
> atval, 2);
> + gap_sdp_handle = attrib_create_sdp(0x0001, "Generic Access Profile");
> +
> + if (gap_sdp_handle == 0) {
> + error("Failed to register GAP service record");
> + goto failed;
> + }
>
> /* GATT service: primary service definition */
> sdp_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
> att_put_u16(GENERIC_ATTRIB_PROFILE_ID, &atval[0]);
> attrib_db_add(0x0010, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 2);
> +
> + gatt_sdp_handle = attrib_create_sdp(0x0010,
> + "Generic Attribute Profile");
> + if (gatt_sdp_handle == 0) {
> + error("Failed to register GATT service record");
> + goto failed;
> + }
> +
> + return TRUE;
> +
> +failed:
> + if (gap_sdp_handle)
> + remove_record_from_server(gap_sdp_handle);
> +
> + return FALSE;
> }
>
> int attrib_server_init(void)
> {
> GError *gerr = NULL;
> - sdp_record_t *record;
>
> /* BR/EDR socket */
> l2cap_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event,
> @@ -861,21 +909,8 @@ int attrib_server_init(void)
> return -1;
> }
>
> - record = server_record_new();
> - if (record == NULL) {
> - error("Unable to create GATT service record");
> + if (!register_core_services())
> goto failed;
> - }
> -
> - if (add_record_to_server(BDADDR_ANY, record) < 0) {
> - error("Failed to register GATT service record");
> - sdp_record_free(record);
> - goto failed;
> - }
> -
> - sdp_handle = record->handle;
> -
> - register_core_services();
>
> if (!main_opts.le)
> return 0;
> @@ -934,8 +969,61 @@ void attrib_server_exit(void)
>
> g_slist_free(clients);
>
> - if (sdp_handle)
> - remove_record_from_server(sdp_handle);
> + if (gatt_sdp_handle)
> + remove_record_from_server(gatt_sdp_handle);
> +
> + if (gap_sdp_handle)
> + remove_record_from_server(gap_sdp_handle);
> +}
> +
> +uint32_t attrib_create_sdp(uint16_t handle, const char *name)
> +{
> + sdp_record_t *record;
> + struct attribute *a;
> + uint16_t end = 0;
> + uuid_t svc;
> +
> + a = find_primary_range(handle, &end);
> +
> + if (a == NULL)
> + goto failed;
> +
> + if (a->len == 2) {
> + svc.type = SDP_UUID16;
> + svc.value.uuid16 = att_get_u16(a->data);
You should use "sdp_uuid16_create(&svc, att_get_u16(a->data))" here
> + } else if (a->len == 16) {
> + svc.type = SDP_UUID128;
> + memcpy(&svc.value.uuid128, a->data, sizeof(uint128_t));
And sdp_uuid128_create() here.
> + } else
> + goto failed;
> +
> + record = server_record_new(&svc, handle, end);
> +
> + if (record == NULL)
> + goto failed;
> +
> + if (name)
> + sdp_set_info_attr(record, name, "BlueZ", NULL);
> +
> + if (svc.type == SDP_UUID16 &&
> + svc.value.uuid16 == GENERIC_ACCESS_PROFILE_ID) {
Usually you would create a temporary uuid16 containing
GENERIC_ACCESS_PROFILE_ID and then compare with sdp_uuid_cmp().
> + sdp_set_url_attr(record, "http://www.bluez.org/",
> + "http://www.bluez.org/",
> + "http://www.bluez.org/");
> + }
> +
> + if (add_record_to_server(BDADDR_ANY, record) < 0)
> + sdp_record_free(record);
> + else
> + return record->handle;
> +failed:
This label (and the goto's) look unnecessary.
> + return 0;
> +}
> +
> +void attrib_free_sdp(uint32_t sdp_handle)
> +{
> + remove_record_from_server(sdp_handle);
> }
>
> int attrib_db_add(uint16_t handle, uuid_t *uuid, int read_reqs, int write_reqs,
> diff --git a/src/attrib-server.h b/src/attrib-server.h
> index 252700f..ecd695c 100644
> --- a/src/attrib-server.h
> +++ b/src/attrib-server.h
> @@ -30,5 +30,6 @@ int attrib_db_add(uint16_t handle, uuid_t *uuid, int read_reqs, int write_reqs,
> int attrib_db_update(uint16_t handle, uuid_t *uuid, const uint8_t *value,
> int len);
> int attrib_db_del(uint16_t handle);
> -
> int attrib_gap_set(uint16_t uuid, const uint8_t *value, int len);
> +uint32_t attrib_create_sdp(uint16_t handle, const char *name);
> +void attrib_free_sdp(uint32_t sdp_handle);
> --
> 1.7.1
> --
> Brian Gix
> bgix@codeaurora.org
> Employee of Qualcomm Innovation Center, Inc.
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
>
Regards,
--
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil
^ permalink raw reply
* [PATCH 1/1 rev2] Add SDP registration of Primary GATT services
From: Brian Gix @ 2011-02-18 20:36 UTC (permalink / raw)
To: linux-bluetooth; +Cc: johan.hedberg, padovan, anderson.lizardo, Brian Gix
In-Reply-To: <1298061379-4816-1-git-send-email-bgix@codeaurora.org>
Add capability to register SDP record for Primary Services.
---
attrib/example.c | 29 +++++++++-
src/attrib-server.c | 162 +++++++++++++++++++++++++++++++++++++++------------
src/attrib-server.h | 3 +-
3 files changed, 155 insertions(+), 39 deletions(-)
diff --git a/attrib/example.c b/attrib/example.c
index 1911912..f0648e4 100644
--- a/attrib/example.c
+++ b/attrib/example.c
@@ -59,6 +59,9 @@
#define FMT_KILOGRAM_UUID 0xA010
#define FMT_HANGING_UUID 0xA011
+#define SDP_RECORD_COUNT 10
+uint32_t sdp_handles[SDP_RECORD_COUNT];
+
static int register_attributes(void)
{
const char *desc_out_temp = "Outside Temperature";
@@ -77,6 +80,7 @@ static int register_attributes(void)
uint8_t atval[256];
uuid_t uuid;
int len;
+ int i = 0;
/* Battery state service: primary service definition */
sdp_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
@@ -101,6 +105,11 @@ static int register_attributes(void)
atval[1] = 0x00;
attrib_db_add(0x0111, &uuid, ATT_NONE, ATT_AUTHENTICATION, atval, 2);
+ /* Add an SDP record for the above service */
+ sdp_handles[i] = attrib_create_sdp(0x0100, "Battery State Service");
+ if (sdp_handles[i])
+ i++;
+
/* Thermometer: primary service definition */
sdp_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
att_put_u16(THERM_HUMIDITY_SVC_UUID, &atval[0]);
@@ -116,7 +125,8 @@ static int register_attributes(void)
/* Thermometer: Include */
att_put_u16(0x0550, &atval[0]);
att_put_u16(0x0568, &atval[2]);
- attrib_db_add(0x0202, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 4);
+ att_put_u16(VENDOR_SPECIFIC_SVC_UUID, &atval[4]);
+ attrib_db_add(0x0202, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 6);
/* Thermometer: temperature characteristic */
sdp_uuid16_create(&uuid, GATT_CHARAC_UUID);
@@ -173,6 +183,11 @@ static int register_attributes(void)
strncpy((char *) atval, desc_out_hum, len);
attrib_db_add(0x0214, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, len);
+ /* Add an SDP record for the above service */
+ sdp_handles[i] = attrib_create_sdp(0x0200, "Thermometer");
+ if (sdp_handles[i])
+ i++;
+
/* Secondary Service: Manufacturer Service */
sdp_uuid16_create(&uuid, GATT_SND_SVC_UUID);
att_put_u16(MANUFACTURER_SVC_UUID, &atval[0]);
@@ -299,6 +314,11 @@ static int register_attributes(void)
strncpy((char *) atval, desc_weight, len);
attrib_db_add(0x0685, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, len);
+ /* Add an SDP record for the above service */
+ sdp_handles[i] = attrib_create_sdp(0x0680, "Weight Service");
+ if (sdp_handles[i])
+ i++;
+
return 0;
}
@@ -309,4 +329,11 @@ int server_example_init(void)
void server_example_exit(void)
{
+ int i;
+
+ for (i = 0; i < SDP_RECORD_COUNT; i++)
+ if (sdp_handles[i]) {
+ attrib_free_sdp(sdp_handles[i]);
+ sdp_handles[i] = 0;
+ }
}
diff --git a/src/attrib-server.c b/src/attrib-server.c
index 5e00601..78e347c 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -70,7 +70,8 @@ struct group_elem {
static GIOChannel *l2cap_io = NULL;
static GIOChannel *le_io = NULL;
static GSList *clients = NULL;
-static uint32_t sdp_handle = 0;
+static uint32_t gatt_sdp_handle = 0;
+static uint32_t gap_sdp_handle = 0;
/* GAP attribute handles */
static uint16_t name_handle = 0x0000;
@@ -85,14 +86,19 @@ static uuid_t snd_uuid = {
.value.uuid16 = GATT_SND_SVC_UUID
};
-static sdp_record_t *server_record_new(void)
+static sdp_record_t *server_record_new(uuid_t *uuid, uint16_t start, uint16_t end)
{
- sdp_list_t *svclass_id, *apseq, *proto[2], *profiles, *root, *aproto;
+ sdp_list_t *svclass_id, *apseq, *proto[2], *root, *aproto;
uuid_t root_uuid, proto_uuid, gatt_uuid, l2cap;
- sdp_profile_desc_t profile;
sdp_record_t *record;
sdp_data_t *psm, *sh, *eh;
- uint16_t lp = GATT_PSM, start = 0x0001, end = 0xffff;
+ uint16_t lp = GATT_PSM;
+
+ if (uuid == NULL)
+ return NULL;
+
+ if (start > end)
+ return NULL;
record = sdp_record_alloc();
if (record == NULL)
@@ -103,17 +109,10 @@ static sdp_record_t *server_record_new(void)
sdp_set_browse_groups(record, root);
sdp_list_free(root, NULL);
- sdp_uuid16_create(&gatt_uuid, GENERIC_ATTRIB_SVCLASS_ID);
- svclass_id = sdp_list_append(NULL, &gatt_uuid);
+ svclass_id = sdp_list_append(NULL, uuid);
sdp_set_service_classes(record, svclass_id);
sdp_list_free(svclass_id, NULL);
- sdp_uuid16_create(&profile.uuid, GENERIC_ATTRIB_PROFILE_ID);
- profile.version = 0x0100;
- profiles = sdp_list_append(NULL, &profile);
- sdp_set_profile_descs(record, profiles);
- sdp_list_free(profiles, NULL);
-
sdp_uuid16_create(&l2cap, L2CAP_UUID);
proto[0] = sdp_list_append(NULL, &l2cap);
psm = sdp_data_alloc(SDP_UINT16, &lp);
@@ -131,11 +130,6 @@ static sdp_record_t *server_record_new(void)
aproto = sdp_list_append(NULL, apseq);
sdp_set_access_protos(record, aproto);
- sdp_set_info_attr(record, "Generic Attribute Profile", "BlueZ", NULL);
-
- sdp_set_url_attr(record, "http://www.bluez.org/",
- "http://www.bluez.org/", "http://www.bluez.org/");
-
sdp_set_service_id(record, gatt_uuid);
sdp_data_free(psm);
@@ -180,6 +174,40 @@ static uint8_t att_check_reqs(struct gatt_channel *channel, uint8_t opcode,
return 0;
}
+static struct attribute *find_primary_range(uint16_t start, uint16_t *end)
+{
+ struct attribute *a, *attrib = NULL;
+ GSList *l;
+ gboolean found = FALSE;
+
+ if (end == NULL)
+ return NULL;
+
+ for (l = database; l; l = l->next) {
+ a = l->data;
+
+ if (a->handle < start)
+ continue;
+
+ if ((a->handle == start) &&
+ sdp_uuid_cmp(&a->uuid, &prim_uuid) == 0) {
+ found = TRUE;
+ *end = start;
+ attrib = a;
+ continue;
+ } else if (!found)
+ break;
+
+ if (sdp_uuid_cmp(&a->uuid, &prim_uuid) == 0 ||
+ sdp_uuid_cmp(&a->uuid, &snd_uuid) == 0)
+ break;
+ else
+ *end = a->handle;
+ }
+
+ return attrib;
+}
+
static uint16_t read_by_group(struct gatt_channel *channel, uint16_t start,
uint16_t end, uuid_t *uuid,
uint8_t *pdu, int len)
@@ -611,7 +639,7 @@ static uint16_t write_value(struct gatt_channel *channel, uint16_t handle,
static uint16_t mtu_exchange(struct gatt_channel *channel, uint16_t mtu,
uint8_t *pdu, int len)
{
- channel->mtu = MIN(mtu, ATT_MAX_MTU);
+ channel->mtu = MIN(mtu, channel->mtu);
return enc_mtu_resp(channel->mtu, pdu, len);
}
@@ -798,7 +826,7 @@ static void confirm_event(GIOChannel *io, void *user_data)
return;
}
-static void register_core_services(void)
+static gboolean register_core_services(void)
{
uint8_t atval[256];
uuid_t uuid;
@@ -835,17 +863,37 @@ static void register_core_services(void)
att_put_u16(appearance, &atval[0]);
attrib_db_add(appearance_handle, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
atval, 2);
+ gap_sdp_handle = attrib_create_sdp(0x0001, "Generic Access Profile");
+
+ if (gap_sdp_handle == 0) {
+ error("Failed to register GAP service record");
+ goto failed;
+ }
/* GATT service: primary service definition */
sdp_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
att_put_u16(GENERIC_ATTRIB_PROFILE_ID, &atval[0]);
attrib_db_add(0x0010, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 2);
+
+ gatt_sdp_handle = attrib_create_sdp(0x0010,
+ "Generic Attribute Profile");
+ if (gatt_sdp_handle == 0) {
+ error("Failed to register GATT service record");
+ goto failed;
+ }
+
+ return TRUE;
+
+failed:
+ if (gap_sdp_handle)
+ remove_record_from_server(gap_sdp_handle);
+
+ return FALSE;
}
int attrib_server_init(void)
{
GError *gerr = NULL;
- sdp_record_t *record;
/* BR/EDR socket */
l2cap_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event,
@@ -861,21 +909,8 @@ int attrib_server_init(void)
return -1;
}
- record = server_record_new();
- if (record == NULL) {
- error("Unable to create GATT service record");
+ if (!register_core_services())
goto failed;
- }
-
- if (add_record_to_server(BDADDR_ANY, record) < 0) {
- error("Failed to register GATT service record");
- sdp_record_free(record);
- goto failed;
- }
-
- sdp_handle = record->handle;
-
- register_core_services();
if (!main_opts.le)
return 0;
@@ -934,8 +969,61 @@ void attrib_server_exit(void)
g_slist_free(clients);
- if (sdp_handle)
- remove_record_from_server(sdp_handle);
+ if (gatt_sdp_handle)
+ remove_record_from_server(gatt_sdp_handle);
+
+ if (gap_sdp_handle)
+ remove_record_from_server(gap_sdp_handle);
+}
+
+uint32_t attrib_create_sdp(uint16_t handle, const char *name)
+{
+ sdp_record_t *record;
+ struct attribute *a;
+ uint16_t end = 0;
+ uuid_t svc;
+
+ a = find_primary_range(handle, &end);
+
+ if (a == NULL)
+ goto failed;
+
+ if (a->len == 2) {
+ svc.type = SDP_UUID16;
+ svc.value.uuid16 = att_get_u16(a->data);
+ } else if (a->len == 16) {
+ svc.type = SDP_UUID128;
+ memcpy(&svc.value.uuid128, a->data, sizeof(uint128_t));
+ } else
+ goto failed;
+
+ record = server_record_new(&svc, handle, end);
+
+ if (record == NULL)
+ goto failed;
+
+ if (name)
+ sdp_set_info_attr(record, name, "BlueZ", NULL);
+
+ if (svc.type == SDP_UUID16 &&
+ svc.value.uuid16 == GENERIC_ACCESS_PROFILE_ID) {
+ sdp_set_url_attr(record, "http://www.bluez.org/",
+ "http://www.bluez.org/",
+ "http://www.bluez.org/");
+ }
+
+ if (add_record_to_server(BDADDR_ANY, record) < 0)
+ sdp_record_free(record);
+ else
+ return record->handle;
+
+failed:
+ return 0;
+}
+
+void attrib_free_sdp(uint32_t sdp_handle)
+{
+ remove_record_from_server(sdp_handle);
}
int attrib_db_add(uint16_t handle, uuid_t *uuid, int read_reqs, int write_reqs,
diff --git a/src/attrib-server.h b/src/attrib-server.h
index 252700f..ecd695c 100644
--- a/src/attrib-server.h
+++ b/src/attrib-server.h
@@ -30,5 +30,6 @@ int attrib_db_add(uint16_t handle, uuid_t *uuid, int read_reqs, int write_reqs,
int attrib_db_update(uint16_t handle, uuid_t *uuid, const uint8_t *value,
int len);
int attrib_db_del(uint16_t handle);
-
int attrib_gap_set(uint16_t uuid, const uint8_t *value, int len);
+uint32_t attrib_create_sdp(uint16_t handle, const char *name);
+void attrib_free_sdp(uint32_t sdp_handle);
--
1.7.1
--
Brian Gix
bgix@codeaurora.org
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
^ permalink raw reply related
* [PATCH 0/1 rev2] Add SDP registration of Primary Services
From: Brian Gix @ 2011-02-18 20:36 UTC (permalink / raw)
To: linux-bluetooth; +Cc: johan.hedberg, padovan, anderson.lizardo
This is a fully merged patch to take into account Claudio's changes
to Device Name Characteristic etcetra.
Otherwise:
This addresses Anderson's issue with the SDP registration. It maintains
the prior APIs and adds a couple which can be called any time after
a complete Primary Service has been inserted into the attribute database.
This allows the attrib-server user to pick and choose the services he
wants to expose to BR/EDR devices, as opposed to LE only devices. It also
gives a mechanism to remove the SDP record from the SDP db.
It also has improved naming (attrib_*) to tie all the parts together.
--
Brian Gix
bgix@codeaurora.org
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
^ permalink raw reply
* Re: HCI core error recovery.
From: Andrei Warkentin @ 2011-02-18 20:21 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <AANLkTi=Z0jaFfeLsNzx9SDJvz-2XCzzTJ++L56rLGZt3@mail.gmail.com>
On Mon, Feb 14, 2011 at 4:23 PM, Andrei Warkentin <andreiw@motorola.com> wrote:
> On Sat, Feb 12, 2011 at 12:47 AM, Andrei Warkentin <andreiw@motorola.com> wrote:
>> On Fri, Feb 11, 2011 at 5:07 PM, Andrei Warkentin <andreiw@motorola.com> wrote:
>>> Dear List,
>>>
>>> I've run into an interesting problem. Excuse me in advance if this was
>>> already covered here, or for my explanations, since I'm not too
>>> familiar with overall flow within BlueZ or Bluetooth specifics...
>>> We've had some hardware config issues that resulted in garbage/malformed
>>> messages arriving via H4 into the HCI layer. We've since resolved
>>> these, but it got me thinking. The issues would result in certain HCI
>>> messages being missed, including occasionally disconnect events being
>>> missed, and a subsequent connect event would result in a double add.
>>>
>>> I was thinking about how to fix at the very least the crash. The sysfs
>>> object is created as a last step after getting a "connection
>>> completed" HCI message, I think. What I am unsure about is if it's
>>> safe to just ignore the add if there is already a sysfs entry...
>>>
>>> So I would think the HCI core needs some resiliency against
>>> bad/malignant bluetooth controllers, and perform error
>>> recovery/resynchronization. Perhaps maybe there is room for a virtual
>>> hci controller that just injects various message types to see how well
>>> the core can cope?
>>>
>>> Thanks in advance,
>>> A
>>
>> To further explain the issue, here is what was happening -
>>
>> 0) A BT device is paired.
>> 1) Host goes into sleep mode.
>> 2) BT device turns off.
>> 3) Host wakes up due to BT waking the host. Due to UART resume issues,
>> HCI message corrupted. hci_disconn_complete_evt never gets called.
>> 4) BT device turns on.
>> 5) devref gets incremented in hci_conn_complete_evt, and is now 2.
>> 6) BT device turns off. hci_disconn_complete_evt is called, conn hash
>> is deleted, but sysfs entry not cleaned up since
>> atomic_dec_and_test(&conn->devref) != 0.
>> 7) BT device turns on. sysfs add fails since it never was cleaned up.
>>
>> The attached patch takes care of that. I'm not too familiar with BlueZ
>> (or bluetooth :-(), so I would like your feedback. In particular, I am
>> unsure about sync connections.
>> The primary issue overall is that HCI core doesn't handle HCI issues
>> (whether caused by transport issues, or bad/malicious BT controller).
>> I am curious if there are other ways to break the core.
>>
>> Thanks,
>> A
>>
>
> Anyone?
>
Anyone? Who should I talk to about HCI?
^ permalink raw reply
* Re: [PATCH 1/1] Add SDP registration of Primary GATT services
From: Brian Gix @ 2011-02-18 20:20 UTC (permalink / raw)
To: Brian Gix; +Cc: linux-bluetooth, johan.hedberg, padovan, anderson.lizardo
In-Reply-To: <1298059898-27366-2-git-send-email-bgix@codeaurora.org>
Please ignore --> I have some merging to do.
On 2/18/2011 12:11 PM, Brian Gix wrote:
> Add capability to register SDP record for Primary Services.
> ---
> attrib/example.c | 29 +++++++++-
> src/attrib-server.c | 162 +++++++++++++++++++++++++++++++++++++++------------
> src/attrib-server.h | 2 +
> 3 files changed, 155 insertions(+), 38 deletions(-)
>
> diff --git a/attrib/example.c b/attrib/example.c
> index 1911912..f0648e4 100644
> --- a/attrib/example.c
> +++ b/attrib/example.c
> @@ -59,6 +59,9 @@
> #define FMT_KILOGRAM_UUID 0xA010
> #define FMT_HANGING_UUID 0xA011
>
> +#define SDP_RECORD_COUNT 10
> +uint32_t sdp_handles[SDP_RECORD_COUNT];
> +
> static int register_attributes(void)
> {
> const char *desc_out_temp = "Outside Temperature";
> @@ -77,6 +80,7 @@ static int register_attributes(void)
> uint8_t atval[256];
> uuid_t uuid;
> int len;
> + int i = 0;
>
> /* Battery state service: primary service definition */
> sdp_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
> @@ -101,6 +105,11 @@ static int register_attributes(void)
> atval[1] = 0x00;
> attrib_db_add(0x0111,&uuid, ATT_NONE, ATT_AUTHENTICATION, atval, 2);
>
> + /* Add an SDP record for the above service */
> + sdp_handles[i] = attrib_create_sdp(0x0100, "Battery State Service");
> + if (sdp_handles[i])
> + i++;
> +
> /* Thermometer: primary service definition */
> sdp_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
> att_put_u16(THERM_HUMIDITY_SVC_UUID,&atval[0]);
> @@ -116,7 +125,8 @@ static int register_attributes(void)
> /* Thermometer: Include */
> att_put_u16(0x0550,&atval[0]);
> att_put_u16(0x0568,&atval[2]);
> - attrib_db_add(0x0202,&uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 4);
> + att_put_u16(VENDOR_SPECIFIC_SVC_UUID,&atval[4]);
> + attrib_db_add(0x0202,&uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 6);
>
> /* Thermometer: temperature characteristic */
> sdp_uuid16_create(&uuid, GATT_CHARAC_UUID);
> @@ -173,6 +183,11 @@ static int register_attributes(void)
> strncpy((char *) atval, desc_out_hum, len);
> attrib_db_add(0x0214,&uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, len);
>
> + /* Add an SDP record for the above service */
> + sdp_handles[i] = attrib_create_sdp(0x0200, "Thermometer");
> + if (sdp_handles[i])
> + i++;
> +
> /* Secondary Service: Manufacturer Service */
> sdp_uuid16_create(&uuid, GATT_SND_SVC_UUID);
> att_put_u16(MANUFACTURER_SVC_UUID,&atval[0]);
> @@ -299,6 +314,11 @@ static int register_attributes(void)
> strncpy((char *) atval, desc_weight, len);
> attrib_db_add(0x0685,&uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, len);
>
> + /* Add an SDP record for the above service */
> + sdp_handles[i] = attrib_create_sdp(0x0680, "Weight Service");
> + if (sdp_handles[i])
> + i++;
> +
> return 0;
> }
>
> @@ -309,4 +329,11 @@ int server_example_init(void)
>
> void server_example_exit(void)
> {
> + int i;
> +
> + for (i = 0; i< SDP_RECORD_COUNT; i++)
> + if (sdp_handles[i]) {
> + attrib_free_sdp(sdp_handles[i]);
> + sdp_handles[i] = 0;
> + }
> }
> diff --git a/src/attrib-server.c b/src/attrib-server.c
> index 85b39a8..c6438bd 100644
> --- a/src/attrib-server.c
> +++ b/src/attrib-server.c
> @@ -70,7 +70,8 @@ struct group_elem {
> static GIOChannel *l2cap_io = NULL;
> static GIOChannel *le_io = NULL;
> static GSList *clients = NULL;
> -static uint32_t sdp_handle = 0;
> +static uint32_t gatt_sdp_handle = 0;
> +static uint32_t gap_sdp_handle = 0;
>
> static uuid_t prim_uuid = {
> .type = SDP_UUID16,
> @@ -81,14 +82,19 @@ static uuid_t snd_uuid = {
> .value.uuid16 = GATT_SND_SVC_UUID
> };
>
> -static sdp_record_t *server_record_new(void)
> +static sdp_record_t *server_record_new(uuid_t *uuid, uint16_t start, uint16_t end)
> {
> - sdp_list_t *svclass_id, *apseq, *proto[2], *profiles, *root, *aproto;
> + sdp_list_t *svclass_id, *apseq, *proto[2], *root, *aproto;
> uuid_t root_uuid, proto_uuid, gatt_uuid, l2cap;
> - sdp_profile_desc_t profile;
> sdp_record_t *record;
> sdp_data_t *psm, *sh, *eh;
> - uint16_t lp = GATT_PSM, start = 0x0001, end = 0xffff;
> + uint16_t lp = GATT_PSM;
> +
> + if (uuid == NULL)
> + return NULL;
> +
> + if (start> end)
> + return NULL;
>
> record = sdp_record_alloc();
> if (record == NULL)
> @@ -99,17 +105,10 @@ static sdp_record_t *server_record_new(void)
> sdp_set_browse_groups(record, root);
> sdp_list_free(root, NULL);
>
> - sdp_uuid16_create(&gatt_uuid, GENERIC_ATTRIB_SVCLASS_ID);
> - svclass_id = sdp_list_append(NULL,&gatt_uuid);
> + svclass_id = sdp_list_append(NULL, uuid);
> sdp_set_service_classes(record, svclass_id);
> sdp_list_free(svclass_id, NULL);
>
> - sdp_uuid16_create(&profile.uuid, GENERIC_ATTRIB_PROFILE_ID);
> - profile.version = 0x0100;
> - profiles = sdp_list_append(NULL,&profile);
> - sdp_set_profile_descs(record, profiles);
> - sdp_list_free(profiles, NULL);
> -
> sdp_uuid16_create(&l2cap, L2CAP_UUID);
> proto[0] = sdp_list_append(NULL,&l2cap);
> psm = sdp_data_alloc(SDP_UINT16,&lp);
> @@ -127,11 +126,6 @@ static sdp_record_t *server_record_new(void)
> aproto = sdp_list_append(NULL, apseq);
> sdp_set_access_protos(record, aproto);
>
> - sdp_set_info_attr(record, "Generic Attribute Profile", "BlueZ", NULL);
> -
> - sdp_set_url_attr(record, "http://www.bluez.org/",
> - "http://www.bluez.org/", "http://www.bluez.org/");
> -
> sdp_set_service_id(record, gatt_uuid);
>
> sdp_data_free(psm);
> @@ -176,6 +170,40 @@ static uint8_t att_check_reqs(struct gatt_channel *channel, uint8_t opcode,
> return 0;
> }
>
> +static struct attribute *find_primary_range(uint16_t start, uint16_t *end)
> +{
> + struct attribute *a, *attrib = NULL;
> + GSList *l;
> + gboolean found = FALSE;
> +
> + if (end == NULL)
> + return NULL;
> +
> + for (l = database; l; l = l->next) {
> + a = l->data;
> +
> + if (a->handle< start)
> + continue;
> +
> + if ((a->handle == start)&&
> + sdp_uuid_cmp(&a->uuid,&prim_uuid) == 0) {
> + found = TRUE;
> + *end = start;
> + attrib = a;
> + continue;
> + } else if (!found)
> + break;
> +
> + if (sdp_uuid_cmp(&a->uuid,&prim_uuid) == 0 ||
> + sdp_uuid_cmp(&a->uuid,&snd_uuid) == 0)
> + break;
> + else
> + *end = a->handle;
> + }
> +
> + return attrib;
> +}
> +
> static uint16_t read_by_group(struct gatt_channel *channel, uint16_t start,
> uint16_t end, uuid_t *uuid,
> uint8_t *pdu, int len)
> @@ -607,7 +635,7 @@ static uint16_t write_value(struct gatt_channel *channel, uint16_t handle,
> static uint16_t mtu_exchange(struct gatt_channel *channel, uint16_t mtu,
> uint8_t *pdu, int len)
> {
> - channel->mtu = MIN(mtu, ATT_MAX_MTU);
> + channel->mtu = MIN(mtu, channel->mtu);
>
> return enc_mtu_resp(channel->mtu, pdu, len);
> }
> @@ -794,7 +822,7 @@ static void confirm_event(GIOChannel *io, void *user_data)
> return;
> }
>
> -static void register_core_services(void)
> +static gboolean register_core_services(void)
> {
> uint8_t atval[256];
> uuid_t uuid;
> @@ -820,17 +848,37 @@ static void register_core_services(void)
>
> /* TODO: Implement Appearance characteristic. It is mandatory for
> * Peripheral/Central GAP roles. */
> + gap_sdp_handle = attrib_create_sdp(0x0001, "Generic Access Profile");
> +
> + if (gap_sdp_handle == 0) {
> + error("Failed to register GAP service record");
> + goto failed;
> + }
>
> /* GATT service: primary service definition */
> sdp_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
> att_put_u16(GENERIC_ATTRIB_PROFILE_ID,&atval[0]);
> attrib_db_add(0x0010,&uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 2);
> +
> + gatt_sdp_handle = attrib_create_sdp(0x0010,
> + "Generic Attribute Profile");
> + if (gatt_sdp_handle == 0) {
> + error("Failed to register GATT service record");
> + goto failed;
> + }
> +
> + return TRUE;
> +
> +failed:
> + if (gap_sdp_handle)
> + remove_record_from_server(gap_sdp_handle);
> +
> + return FALSE;
> }
>
> int attrib_server_init(void)
> {
> GError *gerr = NULL;
> - sdp_record_t *record;
>
> /* BR/EDR socket */
> l2cap_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event,
> @@ -846,21 +894,8 @@ int attrib_server_init(void)
> return -1;
> }
>
> - record = server_record_new();
> - if (record == NULL) {
> - error("Unable to create GATT service record");
> + if (!register_core_services())
> goto failed;
> - }
> -
> - if (add_record_to_server(BDADDR_ANY, record)< 0) {
> - error("Failed to register GATT service record");
> - sdp_record_free(record);
> - goto failed;
> - }
> -
> - sdp_handle = record->handle;
> -
> - register_core_services();
>
> if (!main_opts.le)
> return 0;
> @@ -919,8 +954,61 @@ void attrib_server_exit(void)
>
> g_slist_free(clients);
>
> - if (sdp_handle)
> - remove_record_from_server(sdp_handle);
> + if (gatt_sdp_handle)
> + remove_record_from_server(gatt_sdp_handle);
> +
> + if (gap_sdp_handle)
> + remove_record_from_server(gap_sdp_handle);
> +}
> +
> +uint32_t attrib_create_sdp(uint16_t handle, const char *name)
> +{
> + sdp_record_t *record;
> + struct attribute *a;
> + uint16_t end = 0;
> + uuid_t svc;
> +
> + a = find_primary_range(handle,&end);
> +
> + if (a == NULL)
> + goto failed;
> +
> + if (a->len == 2) {
> + svc.type = SDP_UUID16;
> + svc.value.uuid16 = att_get_u16(a->data);
> + } else if (a->len == 16) {
> + svc.type = SDP_UUID128;
> + memcpy(&svc.value.uuid128, a->data, sizeof(uint128_t));
> + } else
> + goto failed;
> +
> + record = server_record_new(&svc, handle, end);
> +
> + if (record == NULL)
> + goto failed;
> +
> + if (name)
> + sdp_set_info_attr(record, name, "BlueZ", NULL);
> +
> + if (svc.type == SDP_UUID16&&
> + svc.value.uuid16 == GENERIC_ACCESS_PROFILE_ID) {
> + sdp_set_url_attr(record, "http://www.bluez.org/",
> + "http://www.bluez.org/",
> + "http://www.bluez.org/");
> + }
> +
> + if (add_record_to_server(BDADDR_ANY, record)< 0)
> + sdp_record_free(record);
> + else
> + return record->handle;
> +
> +failed:
> + return 0;
> +}
> +
> +void attrib_free_sdp(uint32_t sdp_handle)
> +{
> + remove_record_from_server(sdp_handle);
> }
>
> int attrib_db_add(uint16_t handle, uuid_t *uuid, int read_reqs, int write_reqs,
> diff --git a/src/attrib-server.h b/src/attrib-server.h
> index ba90ff4..34236e4 100644
> --- a/src/attrib-server.h
> +++ b/src/attrib-server.h
> @@ -30,3 +30,5 @@ int attrib_db_add(uint16_t handle, uuid_t *uuid, int read_reqs, int write_reqs,
> int attrib_db_update(uint16_t handle, uuid_t *uuid, const uint8_t *value,
> int len);
> int attrib_db_del(uint16_t handle);
> +uint32_t attrib_create_sdp(uint16_t handle, const char *name);
> +void attrib_free_sdp(uint32_t sdp_handle);
--
Brian Gix
bgix@codeaurora.org
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
^ permalink raw reply
* [PATCH 1/1] Add SDP registration of Primary GATT services
From: Brian Gix @ 2011-02-18 20:11 UTC (permalink / raw)
To: linux-bluetooth; +Cc: johan.hedberg, padovan, anderson.lizardo, Brian Gix
In-Reply-To: <1298059898-27366-1-git-send-email-bgix@codeaurora.org>
Add capability to register SDP record for Primary Services.
---
attrib/example.c | 29 +++++++++-
src/attrib-server.c | 162 +++++++++++++++++++++++++++++++++++++++------------
src/attrib-server.h | 2 +
3 files changed, 155 insertions(+), 38 deletions(-)
diff --git a/attrib/example.c b/attrib/example.c
index 1911912..f0648e4 100644
--- a/attrib/example.c
+++ b/attrib/example.c
@@ -59,6 +59,9 @@
#define FMT_KILOGRAM_UUID 0xA010
#define FMT_HANGING_UUID 0xA011
+#define SDP_RECORD_COUNT 10
+uint32_t sdp_handles[SDP_RECORD_COUNT];
+
static int register_attributes(void)
{
const char *desc_out_temp = "Outside Temperature";
@@ -77,6 +80,7 @@ static int register_attributes(void)
uint8_t atval[256];
uuid_t uuid;
int len;
+ int i = 0;
/* Battery state service: primary service definition */
sdp_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
@@ -101,6 +105,11 @@ static int register_attributes(void)
atval[1] = 0x00;
attrib_db_add(0x0111, &uuid, ATT_NONE, ATT_AUTHENTICATION, atval, 2);
+ /* Add an SDP record for the above service */
+ sdp_handles[i] = attrib_create_sdp(0x0100, "Battery State Service");
+ if (sdp_handles[i])
+ i++;
+
/* Thermometer: primary service definition */
sdp_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
att_put_u16(THERM_HUMIDITY_SVC_UUID, &atval[0]);
@@ -116,7 +125,8 @@ static int register_attributes(void)
/* Thermometer: Include */
att_put_u16(0x0550, &atval[0]);
att_put_u16(0x0568, &atval[2]);
- attrib_db_add(0x0202, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 4);
+ att_put_u16(VENDOR_SPECIFIC_SVC_UUID, &atval[4]);
+ attrib_db_add(0x0202, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 6);
/* Thermometer: temperature characteristic */
sdp_uuid16_create(&uuid, GATT_CHARAC_UUID);
@@ -173,6 +183,11 @@ static int register_attributes(void)
strncpy((char *) atval, desc_out_hum, len);
attrib_db_add(0x0214, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, len);
+ /* Add an SDP record for the above service */
+ sdp_handles[i] = attrib_create_sdp(0x0200, "Thermometer");
+ if (sdp_handles[i])
+ i++;
+
/* Secondary Service: Manufacturer Service */
sdp_uuid16_create(&uuid, GATT_SND_SVC_UUID);
att_put_u16(MANUFACTURER_SVC_UUID, &atval[0]);
@@ -299,6 +314,11 @@ static int register_attributes(void)
strncpy((char *) atval, desc_weight, len);
attrib_db_add(0x0685, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, len);
+ /* Add an SDP record for the above service */
+ sdp_handles[i] = attrib_create_sdp(0x0680, "Weight Service");
+ if (sdp_handles[i])
+ i++;
+
return 0;
}
@@ -309,4 +329,11 @@ int server_example_init(void)
void server_example_exit(void)
{
+ int i;
+
+ for (i = 0; i < SDP_RECORD_COUNT; i++)
+ if (sdp_handles[i]) {
+ attrib_free_sdp(sdp_handles[i]);
+ sdp_handles[i] = 0;
+ }
}
diff --git a/src/attrib-server.c b/src/attrib-server.c
index 85b39a8..c6438bd 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -70,7 +70,8 @@ struct group_elem {
static GIOChannel *l2cap_io = NULL;
static GIOChannel *le_io = NULL;
static GSList *clients = NULL;
-static uint32_t sdp_handle = 0;
+static uint32_t gatt_sdp_handle = 0;
+static uint32_t gap_sdp_handle = 0;
static uuid_t prim_uuid = {
.type = SDP_UUID16,
@@ -81,14 +82,19 @@ static uuid_t snd_uuid = {
.value.uuid16 = GATT_SND_SVC_UUID
};
-static sdp_record_t *server_record_new(void)
+static sdp_record_t *server_record_new(uuid_t *uuid, uint16_t start, uint16_t end)
{
- sdp_list_t *svclass_id, *apseq, *proto[2], *profiles, *root, *aproto;
+ sdp_list_t *svclass_id, *apseq, *proto[2], *root, *aproto;
uuid_t root_uuid, proto_uuid, gatt_uuid, l2cap;
- sdp_profile_desc_t profile;
sdp_record_t *record;
sdp_data_t *psm, *sh, *eh;
- uint16_t lp = GATT_PSM, start = 0x0001, end = 0xffff;
+ uint16_t lp = GATT_PSM;
+
+ if (uuid == NULL)
+ return NULL;
+
+ if (start > end)
+ return NULL;
record = sdp_record_alloc();
if (record == NULL)
@@ -99,17 +105,10 @@ static sdp_record_t *server_record_new(void)
sdp_set_browse_groups(record, root);
sdp_list_free(root, NULL);
- sdp_uuid16_create(&gatt_uuid, GENERIC_ATTRIB_SVCLASS_ID);
- svclass_id = sdp_list_append(NULL, &gatt_uuid);
+ svclass_id = sdp_list_append(NULL, uuid);
sdp_set_service_classes(record, svclass_id);
sdp_list_free(svclass_id, NULL);
- sdp_uuid16_create(&profile.uuid, GENERIC_ATTRIB_PROFILE_ID);
- profile.version = 0x0100;
- profiles = sdp_list_append(NULL, &profile);
- sdp_set_profile_descs(record, profiles);
- sdp_list_free(profiles, NULL);
-
sdp_uuid16_create(&l2cap, L2CAP_UUID);
proto[0] = sdp_list_append(NULL, &l2cap);
psm = sdp_data_alloc(SDP_UINT16, &lp);
@@ -127,11 +126,6 @@ static sdp_record_t *server_record_new(void)
aproto = sdp_list_append(NULL, apseq);
sdp_set_access_protos(record, aproto);
- sdp_set_info_attr(record, "Generic Attribute Profile", "BlueZ", NULL);
-
- sdp_set_url_attr(record, "http://www.bluez.org/",
- "http://www.bluez.org/", "http://www.bluez.org/");
-
sdp_set_service_id(record, gatt_uuid);
sdp_data_free(psm);
@@ -176,6 +170,40 @@ static uint8_t att_check_reqs(struct gatt_channel *channel, uint8_t opcode,
return 0;
}
+static struct attribute *find_primary_range(uint16_t start, uint16_t *end)
+{
+ struct attribute *a, *attrib = NULL;
+ GSList *l;
+ gboolean found = FALSE;
+
+ if (end == NULL)
+ return NULL;
+
+ for (l = database; l; l = l->next) {
+ a = l->data;
+
+ if (a->handle < start)
+ continue;
+
+ if ((a->handle == start) &&
+ sdp_uuid_cmp(&a->uuid, &prim_uuid) == 0) {
+ found = TRUE;
+ *end = start;
+ attrib = a;
+ continue;
+ } else if (!found)
+ break;
+
+ if (sdp_uuid_cmp(&a->uuid, &prim_uuid) == 0 ||
+ sdp_uuid_cmp(&a->uuid, &snd_uuid) == 0)
+ break;
+ else
+ *end = a->handle;
+ }
+
+ return attrib;
+}
+
static uint16_t read_by_group(struct gatt_channel *channel, uint16_t start,
uint16_t end, uuid_t *uuid,
uint8_t *pdu, int len)
@@ -607,7 +635,7 @@ static uint16_t write_value(struct gatt_channel *channel, uint16_t handle,
static uint16_t mtu_exchange(struct gatt_channel *channel, uint16_t mtu,
uint8_t *pdu, int len)
{
- channel->mtu = MIN(mtu, ATT_MAX_MTU);
+ channel->mtu = MIN(mtu, channel->mtu);
return enc_mtu_resp(channel->mtu, pdu, len);
}
@@ -794,7 +822,7 @@ static void confirm_event(GIOChannel *io, void *user_data)
return;
}
-static void register_core_services(void)
+static gboolean register_core_services(void)
{
uint8_t atval[256];
uuid_t uuid;
@@ -820,17 +848,37 @@ static void register_core_services(void)
/* TODO: Implement Appearance characteristic. It is mandatory for
* Peripheral/Central GAP roles. */
+ gap_sdp_handle = attrib_create_sdp(0x0001, "Generic Access Profile");
+
+ if (gap_sdp_handle == 0) {
+ error("Failed to register GAP service record");
+ goto failed;
+ }
/* GATT service: primary service definition */
sdp_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
att_put_u16(GENERIC_ATTRIB_PROFILE_ID, &atval[0]);
attrib_db_add(0x0010, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 2);
+
+ gatt_sdp_handle = attrib_create_sdp(0x0010,
+ "Generic Attribute Profile");
+ if (gatt_sdp_handle == 0) {
+ error("Failed to register GATT service record");
+ goto failed;
+ }
+
+ return TRUE;
+
+failed:
+ if (gap_sdp_handle)
+ remove_record_from_server(gap_sdp_handle);
+
+ return FALSE;
}
int attrib_server_init(void)
{
GError *gerr = NULL;
- sdp_record_t *record;
/* BR/EDR socket */
l2cap_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event,
@@ -846,21 +894,8 @@ int attrib_server_init(void)
return -1;
}
- record = server_record_new();
- if (record == NULL) {
- error("Unable to create GATT service record");
+ if (!register_core_services())
goto failed;
- }
-
- if (add_record_to_server(BDADDR_ANY, record) < 0) {
- error("Failed to register GATT service record");
- sdp_record_free(record);
- goto failed;
- }
-
- sdp_handle = record->handle;
-
- register_core_services();
if (!main_opts.le)
return 0;
@@ -919,8 +954,61 @@ void attrib_server_exit(void)
g_slist_free(clients);
- if (sdp_handle)
- remove_record_from_server(sdp_handle);
+ if (gatt_sdp_handle)
+ remove_record_from_server(gatt_sdp_handle);
+
+ if (gap_sdp_handle)
+ remove_record_from_server(gap_sdp_handle);
+}
+
+uint32_t attrib_create_sdp(uint16_t handle, const char *name)
+{
+ sdp_record_t *record;
+ struct attribute *a;
+ uint16_t end = 0;
+ uuid_t svc;
+
+ a = find_primary_range(handle, &end);
+
+ if (a == NULL)
+ goto failed;
+
+ if (a->len == 2) {
+ svc.type = SDP_UUID16;
+ svc.value.uuid16 = att_get_u16(a->data);
+ } else if (a->len == 16) {
+ svc.type = SDP_UUID128;
+ memcpy(&svc.value.uuid128, a->data, sizeof(uint128_t));
+ } else
+ goto failed;
+
+ record = server_record_new(&svc, handle, end);
+
+ if (record == NULL)
+ goto failed;
+
+ if (name)
+ sdp_set_info_attr(record, name, "BlueZ", NULL);
+
+ if (svc.type == SDP_UUID16 &&
+ svc.value.uuid16 == GENERIC_ACCESS_PROFILE_ID) {
+ sdp_set_url_attr(record, "http://www.bluez.org/",
+ "http://www.bluez.org/",
+ "http://www.bluez.org/");
+ }
+
+ if (add_record_to_server(BDADDR_ANY, record) < 0)
+ sdp_record_free(record);
+ else
+ return record->handle;
+
+failed:
+ return 0;
+}
+
+void attrib_free_sdp(uint32_t sdp_handle)
+{
+ remove_record_from_server(sdp_handle);
}
int attrib_db_add(uint16_t handle, uuid_t *uuid, int read_reqs, int write_reqs,
diff --git a/src/attrib-server.h b/src/attrib-server.h
index ba90ff4..34236e4 100644
--- a/src/attrib-server.h
+++ b/src/attrib-server.h
@@ -30,3 +30,5 @@ int attrib_db_add(uint16_t handle, uuid_t *uuid, int read_reqs, int write_reqs,
int attrib_db_update(uint16_t handle, uuid_t *uuid, const uint8_t *value,
int len);
int attrib_db_del(uint16_t handle);
+uint32_t attrib_create_sdp(uint16_t handle, const char *name);
+void attrib_free_sdp(uint32_t sdp_handle);
--
1.7.1
--
Brian Gix
bgix@codeaurora.org
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
^ permalink raw reply related
* [PATCH 0/1] SDP registration of Primary GATT Services
From: Brian Gix @ 2011-02-18 20:11 UTC (permalink / raw)
To: linux-bluetooth; +Cc: johan.hedberg, padovan, anderson.lizardo
This addresses Anderson's issue with the SDP registration. It maintains
the prior APIs and adds a couple which can be called any time after
a complete Primary Service has been inserted into the attribute database.
This allows the attrib-server user to pick and choose the services he
wants to expose to BR/EDR devices, as opposed to LE only devices. It also
gives a mechanism to remove the SDP record from the SDP db.
It also has improved naming (attrib_*) to tie all the parts together.
--
Brian Gix
bgix@codeaurora.org
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
^ permalink raw reply
* Re: bluetooth disabled with current 2.6.38-rc4
From: Justin Mattock @ 2011-02-18 19:09 UTC (permalink / raw)
To: Gustavo F. Padovan; +Cc: Johan Hedberg, linux-bluetooth
In-Reply-To: <9E5B44E9-A8D4-49AB-9D2E-0465BF74ACA1@gmail.com>
well.. I've looked at this issue a little bit more, and am noticing
that the hci0 device is not being brought up when the daemon is being
called.(udev seems to not being loading for me at boot) Im going to
look and check my configurations to make sure everything is correct.
Justin P. Mattock
^ permalink raw reply
* Re: [PATCH 1/2] telephony-ofono: reset indicators when a network is found
From: Johan Hedberg @ 2011-02-18 16:51 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <1298046241-8655-1-git-send-email-luiz.dentz@gmail.com>
Hi Luiz,
On Fri, Feb 18, 2011, Luiz Augusto von Dentz wrote:
> Indicators may have invalid values set from the last time they were used
> ---
> audio/telephony-ofono.c | 9 +++++++++
> 1 files changed, 9 insertions(+), 0 deletions(-)
Pushed upstream. Thanks.
Be careful with the commit message line lengths. The summary line of
your second patch was too long for git log on a 80-character wide
terminal (I fixed this manually).
Johan
^ permalink raw reply
* [PATCH 2/2] telephony-ofono: fix not resetting network status and signal on modem removed
From: Luiz Augusto von Dentz @ 2011-02-18 16:24 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1298046241-8655-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.dentz-von@nokia.com>
This prevent using status and signal from previous active modem
---
audio/telephony-ofono.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/audio/telephony-ofono.c b/audio/telephony-ofono.c
index bc8fea2..0a7f0bd 100644
--- a/audio/telephony-ofono.c
+++ b/audio/telephony-ofono.c
@@ -1042,6 +1042,8 @@ static void modem_removed(const char *path)
g_free(net.operator_name);
net.operator_name = NULL;
+ net.status = NETWORK_REG_STATUS_NOSERV;
+ net.signals_bar = 0;
g_free(modem_obj_path);
modem_obj_path = NULL;
--
1.7.1
^ permalink raw reply related
* [PATCH 1/2] telephony-ofono: reset indicators when a network is found
From: Luiz Augusto von Dentz @ 2011-02-18 16:24 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.dentz-von@nokia.com>
Indicators may have invalid values set from the last time they were used
---
audio/telephony-ofono.c | 9 +++++++++
1 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/audio/telephony-ofono.c b/audio/telephony-ofono.c
index 4e78801..bc8fea2 100644
--- a/audio/telephony-ofono.c
+++ b/audio/telephony-ofono.c
@@ -935,6 +935,15 @@ static int parse_network_properties(DBusMessageIter *properties)
AG_FEATURE_ENHANCED_CALL_CONTROL |
AG_FEATURE_EXTENDED_ERROR_RESULT_CODES |
AG_FEATURE_THREE_WAY_CALLING;
+ int i;
+
+ /* Reset indicators */
+ for (i = 0; ofono_indicators[i].desc != NULL; i++) {
+ if (g_str_equal(ofono_indicators[i].desc, "battchg"))
+ ofono_indicators[i].val = 5;
+ else
+ ofono_indicators[i].val = 0;
+ }
while (dbus_message_iter_get_arg_type(properties)
== DBUS_TYPE_DICT_ENTRY) {
--
1.7.1
^ permalink raw reply related
* Re: [PATCH 1/3] Add UUID property to GATT service object
From: Johan Hedberg @ 2011-02-18 15:10 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1297880021-31728-1-git-send-email-epx@signove.com>
Hi Elvis,
On Wed, Feb 16, 2011, Elvis Pf??tzenreuter wrote:
> ---
> attrib/client.c | 4 ++++
> 1 files changed, 4 insertions(+), 0 deletions(-)
This patch has been pushed upstream. For the others I'm still waiting
for some feedback from the other LE developers.
Johan
^ permalink raw reply
* Re: [PATCH] Replace batostr() with ba2str() to avoid memleaks
From: Johan Hedberg @ 2011-02-18 15:02 UTC (permalink / raw)
To: David Herrmann; +Cc: linux-bluetooth, David Herrmann
In-Reply-To: <1297983986-10131-1-git-send-email-dh.herrmann@gmail.com>
Hi David,
On Fri, Feb 18, 2011, David Herrmann wrote:
> batostr() returns dynamically allocated strings. Replace it with
> ba2str() wherever possible to avoid heap allocations and fix
> memleaks.
> ---
> compat/bnep.c | 5 +++--
> test/hciemu.c | 4 +++-
> 2 files changed, 6 insertions(+), 3 deletions(-)
Thanks. The patch has been pushed upstream with a couple of minor coding
style corrections.
Johan
^ permalink raw reply
* Re: [PATCH] Add Primary Discovery Services option to interactive gatttool
From: Johan Hedberg @ 2011-02-18 14:57 UTC (permalink / raw)
To: Sheldon Demario; +Cc: linux-bluetooth
In-Reply-To: <1297974030-20497-1-git-send-email-sheldon.demario@openbossa.org>
Hi Sheldon,
On Thu, Feb 17, 2011, Sheldon Demario wrote:
> ---
> attrib/interactive.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 files changed, 70 insertions(+), 0 deletions(-)
Pushed upstream. Thanks.
Johan
^ permalink raw reply
* pull request: bluetooth-next-2.6 2011-02-17
From: Gustavo F. Padovan @ 2011-02-18 13:59 UTC (permalink / raw)
To: linville; +Cc: linux-wireless, linux-bluetooth
Hi John,
Busy times at the Bluetooth subsystem. Here is another big set of patches
intended to 2.6.39. ;)
One of the changes is the end of the L2CAP and SCO kernel modules. We just
merged them into the main bluetooth.ko module. It really never made sense to
have them separated.
Then we have firmware support to a new Atheros device by Bala Shanmugam.
The First set of patches for Bluetooth Low Energy(LE) support, by Ville Tervo.
Low Energy is a new Bluetooth radio that will bring many new use cases to the
Bluetooth technology. Finally, LE connection update command support by Claudio
Takahasi. The rest is just bugs fixes and cleanups.
Please pull, or let me know any doubts you have. Thanks.
The following changes since commit a3dc5e881a8a5199bf371fdd4530cfa18280ca83:
rtlwifi: rtl8192ce: Rework rtl8192ce/phy.c (2011-02-11 16:16:38 -0500)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/padovan/bluetooth-next-2.6.git master
Andrei Warkentin (1):
Bluetooth: Make hci a child of the corresponding tty device.
Bala Shanmugam (1):
Bluetooth: Add firmware support for Atheros 3012
Claudio Takahasi (3):
Bluetooth: Add LE signaling commands handling
Bluetooth: Add connection parameter update response
Bluetooth: Send LE Connection Update Command
Gustavo F. Padovan (8):
Bluetooth: Merge L2CAP and SCO modules into bluetooth.ko
Bluetooth: remove l2cap_load() hack
Bluetooth: Add L2CAP mode to debugfs output
Bluetooth: Use usb_fill_int_urb()
Bluetooth: Fix crash when ioctl(HCIUARTSETPROTO) fails
Bluetooth: fix errors reported by checkpatch.pl
Bluetooth: Fix errors reported by checkpatch.pl
Bluetooth: fix checkpatch errors in af_bluetooth.c
Szymon Janc (5):
Bluetooth: Use #include <linux/uaccess.h> instead of <asm/uaccess.h>
Bluetooth: Clean up hci_sniff_subrate_evt function
Bluetooth: Fix some code style issues in hci_core.h
Bluetooth: Fix some code style issues in hci_core.c
Bluetooth: Fix some code style issues in hci_event.c
Vasiliy Kulikov (3):
Bluetooth: l2cap: fix 1 byte infoleak to userspace
Bluetooth: bnep: fix buffer overflow
Bluetooth: sco: fix information leak to userspace
Ville Tervo (9):
Bluetooth: Add low energy commands and events
Bluetooth: Add LE connect support
Bluetooth: Use LE buffers for LE traffic
Bluetooth: Add LE connection support to L2CAP
Bluetooth: Add server socket support for LE connection
Bluetooth: Do not send disconn comand over LE links
Bluetooth: Treat LE and ACL links separately on timeout
Bluetooth: Add SMP command structures
Bluetooth: Use proper timer for hci command timout
Vinicius Costa Gomes (1):
Bluetooth: Fix initiated LE connections
drivers/bluetooth/ath3k.c | 279 +++++++++++++++++++++++++++++
drivers/bluetooth/btusb.c | 13 +-
drivers/bluetooth/hci_ldisc.c | 1 +
include/net/bluetooth/bluetooth.h | 28 +++
include/net/bluetooth/hci.h | 65 +++++++
include/net/bluetooth/hci_core.h | 92 ++++++----
include/net/bluetooth/l2cap.h | 23 +++-
include/net/bluetooth/smp.h | 76 ++++++++
net/bluetooth/Kconfig | 10 +-
net/bluetooth/Makefile | 5 +-
net/bluetooth/af_bluetooth.c | 34 ++++-
net/bluetooth/bnep/core.c | 2 -
net/bluetooth/bnep/sock.c | 1 +
net/bluetooth/cmtp/core.c | 2 -
net/bluetooth/hci_conn.c | 77 ++++++++-
net/bluetooth/hci_core.c | 115 ++++++++++--
net/bluetooth/hci_event.c | 165 +++++++++++++++--
net/bluetooth/hci_sysfs.c | 6 +-
net/bluetooth/hidp/core.c | 2 -
net/bluetooth/l2cap_core.c | 355 ++++++++++++++++++++++++++++---------
net/bluetooth/l2cap_sock.c | 60 ++++---
net/bluetooth/mgmt.c | 2 +-
net/bluetooth/rfcomm/core.c | 2 -
net/bluetooth/sco.c | 17 +--
24 files changed, 1196 insertions(+), 236 deletions(-)
create mode 100644 include/net/bluetooth/smp.h
--
Gustavo F. Padovan
http://profusion.mobi
^ permalink raw reply
* RE: BUG in Mobile initiated pairing
From: sachin.athanikar @ 2011-02-18 11:21 UTC (permalink / raw)
To: padovan; +Cc: linux-bluetooth
In-Reply-To: <20110217162719.GF10543@joana>
[-- Attachment #1: Type: text/plain, Size: 1837 bytes --]
Hi Gustavo,
Thanks for your precious time and response.
I had modified the agent.c provided in the test folder of BlueZ to support mobile initiated pairing.
I have attached the
1. modified code (agent.c)
2. DBUS monitor logs
3. BlueZ Logs (property changed event "Paired" is not generated)
The pairing is successful, but the property changed event "Paired" is not seen in DBUS monitor.
Please let me know your comments on this program.
Yes, in Ubuntu 10.10 with the support of Bluetooth-Gnome remote device initiated pairing works with all the events.
Thanks
Sachin
-----Original Message-----
From: linux-bluetooth-owner@vger.kernel.org [mailto:linux-bluetooth-owner@vger.kernel.org] On Behalf Of Gustavo F. Padovan
Sent: Thursday, February 17, 2011 9:57 PM
To: Athanikar, Sachin
Cc: linux-bluetooth@vger.kernel.org
Subject: Re: BUG in Mobile initiated pairing
Hi Sachin,
* sachin.athanikar@accenture.com <sachin.athanikar@accenture.com> [2011-02-17 20:10:38 +0530]:
> Hi Gustavo,
> Many thanks for the response.
>
> The property changed event "Paired" is not generated when the mobile initiated pairing is successful. So I am not able get an acknowledgement for successful completion of pairing process.
Yes, it is. I just tested it before reply to you.
--
Gustavo F. Padovan
http://profusion.mobi
--
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
This message is for the designated recipient only and may contain privileged, proprietary, or otherwise private information. If you have received it in error, please notify the sender immediately and delete the original. Any other use of the email by you is prohibited.
[-- Attachment #2: dbus-monitor-log.txt --]
[-- Type: text/plain, Size: 1037 bytes --]
signal sender=org.freedesktop.DBus -> dest=(null destination) serial=50 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=NameOwnerChanged
string ":1.82"
string ""
string ":1.82"
signal sender=:1.63 -> dest=(null destination) serial=286 path=/org/bluez/3346/hci0/dev_A0_4E_04_BC_A3_79; interface=org.bluez.Device; member=PropertyChanged
string "Connected"
variant boolean true
signal sender=org.freedesktop.DBus -> dest=(null destination) serial=51 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=NameOwnerChanged
string ":1.83"
string ""
string ":1.83"
signal sender=org.freedesktop.DBus -> dest=(null destination) serial=52 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=NameOwnerChanged
string ":1.83"
string ":1.83"
string ""
signal sender=:1.63 -> dest=(null destination) serial=288 path=/org/bluez/3346/hci0/dev_A0_4E_04_BC_A3_79; interface=org.bluez.Device; member=PropertyChanged
string "Connected"
variant boolean false
[-- Attachment #3: agent.c --]
[-- Type: text/plain, Size: 15368 bytes --]
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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 <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <getopt.h>
#include <string.h>
#include <dbus/dbus.h>
static char *passkey_value = NULL;
static int passkey_delay = 0;
static int do_reject = 0;
static volatile sig_atomic_t __io_canceled = 0;
static volatile sig_atomic_t __io_terminated = 0;
static void sig_term(int sig)
{
__io_canceled = 1;
}
static DBusHandlerResult agent_filter(DBusConnection *conn,
DBusMessage *msg, void *data)
{
const char *name, *old, *new;
if (!dbus_message_is_signal(msg, DBUS_INTERFACE_DBUS,
"NameOwnerChanged"))
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
if (!dbus_message_get_args(msg, NULL,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_STRING, &old,
DBUS_TYPE_STRING, &new,
DBUS_TYPE_INVALID)) {
fprintf(stderr, "Invalid arguments for NameOwnerChanged signal");
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
if (!strcmp(name, "org.bluez") && *new == '\0') {
fprintf(stderr, "Agent has been terminated\n");
__io_terminated = 1;
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
static DBusHandlerResult request_pincode_message(DBusConnection *conn,
DBusMessage *msg, void *data)
{
DBusMessage *reply;
const char *path;
if (!passkey_value)
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID)) {
fprintf(stderr, "Invalid arguments for RequestPinCode method");
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
if (do_reject) {
reply = dbus_message_new_error(msg, "org.bluez.Error.Rejected", "");
goto send;
}
reply = dbus_message_new_method_return(msg);
if (!reply) {
fprintf(stderr, "Can't create reply message\n");
return DBUS_HANDLER_RESULT_NEED_MEMORY;
}
printf("Pincode request for device %s\n", path);
if (passkey_delay) {
printf("Waiting for %d seconds\n", passkey_delay);
sleep(passkey_delay);
}
dbus_message_append_args(reply, DBUS_TYPE_STRING, &passkey_value,
DBUS_TYPE_INVALID);
send:
dbus_connection_send(conn, reply, NULL);
dbus_connection_flush(conn);
dbus_message_unref(reply);
return DBUS_HANDLER_RESULT_HANDLED;
}
static DBusHandlerResult request_passkey_message(DBusConnection *conn,
DBusMessage *msg, void *data)
{
DBusMessage *reply;
const char *path;
unsigned int passkey;
if (!passkey_value)
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID)) {
fprintf(stderr, "Invalid arguments for RequestPasskey method");
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
if (do_reject) {
reply = dbus_message_new_error(msg, "org.bluez.Error.Rejected", "");
goto send;
}
reply = dbus_message_new_method_return(msg);
if (!reply) {
fprintf(stderr, "Can't create reply message\n");
return DBUS_HANDLER_RESULT_NEED_MEMORY;
}
printf("Passkey request for device %s\n", path);
if (passkey_delay) {
printf("Waiting for %d seconds\n", passkey_delay);
sleep(passkey_delay);
}
passkey = strtoul(passkey_value, NULL, 10);
dbus_message_append_args(reply, DBUS_TYPE_UINT32, &passkey,
DBUS_TYPE_INVALID);
send:
dbus_connection_send(conn, reply, NULL);
dbus_connection_flush(conn);
dbus_message_unref(reply);
return DBUS_HANDLER_RESULT_HANDLED;
}
static DBusHandlerResult request_confirmation_message(DBusConnection *conn,
DBusMessage *msg, void *data)
{
DBusMessage *reply;
const char *path;
unsigned int passkey;
if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_UINT32, &passkey,
DBUS_TYPE_INVALID)) {
fprintf(stderr, "Invalid arguments for RequestPasskey method");
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
if (do_reject) {
reply = dbus_message_new_error(msg, "org.bluez.Error.Rejected", "");
goto send;
}
reply = dbus_message_new_method_return(msg);
if (!reply) {
fprintf(stderr, "Can't create reply message\n");
return DBUS_HANDLER_RESULT_NEED_MEMORY;
}
printf("Confirmation request of %u for device %s\n", passkey, path);
if (passkey_delay) {
printf("Waiting for %d seconds\n", passkey_delay);
sleep(passkey_delay);
}
send:
dbus_connection_send(conn, reply, NULL);
dbus_connection_flush(conn);
dbus_message_unref(reply);
return DBUS_HANDLER_RESULT_HANDLED;
}
static DBusHandlerResult authorize_message(DBusConnection *conn,
DBusMessage *msg, void *data)
{
DBusMessage *reply;
const char *path, *uuid;
if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_STRING, &uuid,
DBUS_TYPE_INVALID)) {
fprintf(stderr, "Invalid arguments for Authorize method");
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
if (do_reject) {
reply = dbus_message_new_error(msg, "org.bluez.Error.Rejected", "");
goto send;
}
reply = dbus_message_new_method_return(msg);
if (!reply) {
fprintf(stderr, "Can't create reply message\n");
return DBUS_HANDLER_RESULT_NEED_MEMORY;
}
printf("Authorizing request for %s\n", path);
send:
dbus_connection_send(conn, reply, NULL);
dbus_connection_flush(conn);
dbus_message_unref(reply);
return DBUS_HANDLER_RESULT_HANDLED;
}
static DBusHandlerResult cancel_message(DBusConnection *conn,
DBusMessage *msg, void *data)
{
DBusMessage *reply;
if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_INVALID)) {
fprintf(stderr, "Invalid arguments for passkey Confirm method");
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
printf("Request canceled\n");
reply = dbus_message_new_method_return(msg);
if (!reply) {
fprintf(stderr, "Can't create reply message\n");
return DBUS_HANDLER_RESULT_NEED_MEMORY;
}
dbus_connection_send(conn, reply, NULL);
dbus_connection_flush(conn);
dbus_message_unref(reply);
return DBUS_HANDLER_RESULT_HANDLED;
}
static DBusHandlerResult release_message(DBusConnection *conn,
DBusMessage *msg, void *data)
{
DBusMessage *reply;
if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_INVALID)) {
fprintf(stderr, "Invalid arguments for Release method");
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
if (!__io_canceled)
fprintf(stderr, "Agent has been released\n");
__io_terminated = 1;
reply = dbus_message_new_method_return(msg);
if (!reply) {
fprintf(stderr, "Can't create reply message\n");
return DBUS_HANDLER_RESULT_NEED_MEMORY;
}
dbus_connection_send(conn, reply, NULL);
dbus_connection_flush(conn);
dbus_message_unref(reply);
return DBUS_HANDLER_RESULT_HANDLED;
}
static DBusHandlerResult agent_message(DBusConnection *conn,
DBusMessage *msg, void *data)
{
if (dbus_message_is_method_call(msg, "org.bluez.Agent",
"RequestPinCode"))
return request_pincode_message(conn, msg, data);
if (dbus_message_is_method_call(msg, "org.bluez.Agent",
"RequestPasskey"))
return request_passkey_message(conn, msg, data);
if (dbus_message_is_method_call(msg, "org.bluez.Agent",
"RequestConfirmation"))
return request_confirmation_message(conn, msg, data);
if (dbus_message_is_method_call(msg, "org.bluez.Agent", "Authorize"))
return authorize_message(conn, msg, data);
if (dbus_message_is_method_call(msg, "org.bluez.Agent", "Cancel"))
return cancel_message(conn, msg, data);
if (dbus_message_is_method_call(msg, "org.bluez.Agent", "Release"))
return release_message(conn, msg, data);
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
static const DBusObjectPathVTable agent_table = {
.message_function = agent_message,
};
static int register_agent(DBusConnection *conn, const char *adapter_path,
const char *agent_path,
const char *capabilities)
{
DBusMessage *msg, *reply;
DBusError err;
msg = dbus_message_new_method_call("org.bluez", adapter_path,
"org.bluez.Adapter", "RegisterAgent");
if (!msg) {
fprintf(stderr, "Can't allocate new method call\n");
return -1;
}
dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &agent_path,
DBUS_TYPE_STRING, &capabilities,
DBUS_TYPE_INVALID);
dbus_error_init(&err);
reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
dbus_message_unref(msg);
if (!reply) {
fprintf(stderr, "Can't register agent\n");
if (dbus_error_is_set(&err)) {
fprintf(stderr, "%s\n", err.message);
dbus_error_free(&err);
}
return -1;
}
dbus_message_unref(reply);
dbus_connection_flush(conn);
return 0;
}
static int unregister_agent(DBusConnection *conn, const char *adapter_path,
const char *agent_path)
{
DBusMessage *msg, *reply;
DBusError err;
msg = dbus_message_new_method_call("org.bluez", adapter_path,
"org.bluez.Adapter", "UnregisterAgent");
if (!msg) {
fprintf(stderr, "Can't allocate new method call\n");
return -1;
}
dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &agent_path,
DBUS_TYPE_INVALID);
dbus_error_init(&err);
reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
dbus_message_unref(msg);
if (!reply) {
fprintf(stderr, "Can't unregister agent\n");
if (dbus_error_is_set(&err)) {
fprintf(stderr, "%s\n", err.message);
dbus_error_free(&err);
}
return -1;
}
dbus_message_unref(reply);
dbus_connection_flush(conn);
dbus_connection_unregister_object_path(conn, agent_path);
return 0;
}
static int create_paired_device(DBusConnection *conn, const char *adapter_path,
const char *agent_path,
const char *capabilities,
const char *device)
{
dbus_bool_t success;
DBusMessage *msg;
msg = dbus_message_new_method_call("org.bluez", adapter_path,
"org.bluez.Adapter",
"CreatePairedDevice");
if (!msg) {
fprintf(stderr, "Can't allocate new method call\n");
return -1;
}
dbus_message_append_args(msg, DBUS_TYPE_STRING, &device,
DBUS_TYPE_OBJECT_PATH, &agent_path,
DBUS_TYPE_STRING, &capabilities,
DBUS_TYPE_INVALID);
success = dbus_connection_send(conn, msg, NULL);
dbus_message_unref(msg);
if (!success) {
fprintf(stderr, "Not enough memory for message send\n");
return -1;
}
dbus_connection_flush(conn);
return 0;
}
static char *get_default_adapter_path(DBusConnection *conn)
{
DBusMessage *msg, *reply;
DBusError err;
const char *reply_path;
char *path;
msg = dbus_message_new_method_call("org.bluez", "/",
"org.bluez.Manager", "DefaultAdapter");
if (!msg) {
fprintf(stderr, "Can't allocate new method call\n");
return NULL;
}
dbus_error_init(&err);
reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
dbus_message_unref(msg);
if (!reply) {
fprintf(stderr,
"Can't get default adapter\n");
if (dbus_error_is_set(&err)) {
fprintf(stderr, "%s\n", err.message);
dbus_error_free(&err);
}
return NULL;
}
if (!dbus_message_get_args(reply, &err,
DBUS_TYPE_OBJECT_PATH, &reply_path,
DBUS_TYPE_INVALID)) {
fprintf(stderr,
"Can't get reply arguments\n");
if (dbus_error_is_set(&err)) {
fprintf(stderr, "%s\n", err.message);
dbus_error_free(&err);
}
return NULL;
}
path = strdup(reply_path);
dbus_message_unref(reply);
dbus_connection_flush(conn);
return path;
}
static char *get_adapter_path(DBusConnection *conn, const char *adapter)
{
DBusMessage *msg, *reply;
DBusError err;
const char *reply_path;
char *path;
if (!adapter)
return get_default_adapter_path(conn);
msg = dbus_message_new_method_call("org.bluez", "/",
"org.bluez.Manager", "FindAdapter");
if (!msg) {
fprintf(stderr, "Can't allocate new method call\n");
return NULL;
}
dbus_message_append_args(msg, DBUS_TYPE_STRING, &adapter,
DBUS_TYPE_INVALID);
dbus_error_init(&err);
reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
dbus_message_unref(msg);
if (!reply) {
fprintf(stderr,
"Can't find adapter %s\n", adapter);
if (dbus_error_is_set(&err)) {
fprintf(stderr, "%s\n", err.message);
dbus_error_free(&err);
}
return NULL;
}
if (!dbus_message_get_args(reply, &err,
DBUS_TYPE_OBJECT_PATH, &reply_path,
DBUS_TYPE_INVALID)) {
fprintf(stderr,
"Can't get reply arguments\n");
if (dbus_error_is_set(&err)) {
fprintf(stderr, "%s\n", err.message);
dbus_error_free(&err);
}
return NULL;
}
path = strdup(reply_path);
dbus_message_unref(reply);
dbus_connection_flush(conn);
return path;
}
static void usage(void)
{
// printf("Bluetooth agent ver %s\n\n", VERSION);
printf("Usage:\n"
"\tagent [--adapter adapter-path] [--path agent-path] <passkey> [<device>]\n"
"\n");
}
static struct option main_options[] = {
{ "adapter", 1, 0, 'a' },
{ "path", 1, 0, 'p' },
{ "capabilites",1, 0, 'c' },
{ "delay", 1, 0, 'd' },
{ "reject", 0, 0, 'r' },
{ "help", 0, 0, 'h' },
{ 0, 0, 0, 0 }
};
int main(int argc, char *argv[])
{
const char *capabilities = "DisplayYesNo";
struct sigaction sa;
DBusConnection *conn;
char match_string[128], default_path[128], *adapter_id = NULL;
char *adapter_path = NULL, *agent_path = NULL, *device = NULL;
snprintf(default_path, sizeof(default_path),
"/org/bluez/agent_%d", getpid());
adapter_id = "hci0";
passkey_value = "123";
if (!agent_path)
agent_path = strdup(default_path);
conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
if (!conn) {
fprintf(stderr, "Can't get on system bus");
exit(1);
}
adapter_path = get_adapter_path(conn, adapter_id);
if (!adapter_path)
exit(1);
if (!dbus_connection_register_object_path(conn, agent_path,
&agent_table, NULL)) {
fprintf(stderr, "Can't register object path for agent\n");
exit(1);
}
if (register_agent(conn, adapter_path, agent_path,
capabilities) < 0) {
dbus_connection_unref(conn);
exit(1);
}
if (!dbus_connection_add_filter(conn, agent_filter, NULL, NULL))
fprintf(stderr, "Can't add signal filter");
snprintf(match_string, sizeof(match_string),
"interface=%s,member=NameOwnerChanged,arg0=%s",
DBUS_INTERFACE_DBUS, "org.bluez");
dbus_bus_add_match(conn, match_string, NULL);
memset(&sa, 0, sizeof(sa));
sa.sa_flags = SA_NOCLDSTOP;
sa.sa_handler = sig_term;
sigaction(SIGTERM, &sa, NULL);
sigaction(SIGINT, &sa, NULL);
while (!__io_canceled && !__io_terminated) {
if (dbus_connection_read_write_dispatch(conn, 500) != TRUE)
break;
}
if (!__io_terminated && !device)
unregister_agent(conn, adapter_path, agent_path);
free(adapter_path);
free(agent_path);
free(passkey_value);
dbus_connection_unref(conn);
return 0;
}
^ permalink raw reply
* [PATCH v2 2/2] Bluetooth: Enable support for Out of Band authentication
From: Szymon Janc @ 2011-02-18 11:12 UTC (permalink / raw)
To: linux-bluetooth; +Cc: par-gunnar.p.hjalmdahl, henrik.possung, Szymon Janc
In-Reply-To: <1297948601-12723-7-git-send-email-szymon.janc@tieto.com>
Signed-off-by: Szymon Janc <szymon.janc@tieto.com>
---
net/bluetooth/hci_event.c | 7 ++++++-
1 files changed, 6 insertions(+), 1 deletions(-)
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index abaa905..a7c7349 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2335,9 +2335,14 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff
bacpy(&cp.bdaddr, &ev->bdaddr);
cp.capability = conn->io_capability;
- cp.oob_data = 0;
cp.authentication = hci_get_auth_req(conn);
+ if ((conn->out == 1 || conn->remote_oob == 0x01) &&
+ hci_find_remote_oob_data(hdev, &conn->dst))
+ cp.oob_data = 0x01;
+ else
+ cp.oob_data = 0x00;
+
hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_REPLY,
sizeof(cp), &cp);
} else {
--
1.7.0.4
^ permalink raw reply related
* [PATCH v2 1/2] Bluetooth: Add add/remove_remote_oob_data management commands
From: Szymon Janc @ 2011-02-18 11:12 UTC (permalink / raw)
To: linux-bluetooth; +Cc: par-gunnar.p.hjalmdahl, henrik.possung, Szymon Janc
In-Reply-To: <1297948601-12723-7-git-send-email-szymon.janc@tieto.com>
This patch adds commands to add and remove remote OOB data to the managment
interface. Remote data is stored in kernel and used by corresponding HCI
commands and events (also implemented in this patch) when needed.
This patch does not enable OOB support.
Signed-off-by: Szymon Janc <szymon.janc@tieto.com>
---
include/net/bluetooth/hci.h | 17 ++++++++
include/net/bluetooth/hci_core.h | 16 ++++++++
include/net/bluetooth/mgmt.h | 14 +++++++
net/bluetooth/hci_core.c | 76 ++++++++++++++++++++++++++++++++++++++
net/bluetooth/hci_event.c | 34 +++++++++++++++++
net/bluetooth/mgmt.c | 73 ++++++++++++++++++++++++++++++++++++
6 files changed, 230 insertions(+), 0 deletions(-)
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 7d1aef9..d1dd7dc 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -415,6 +415,18 @@ struct hci_cp_io_capability_reply {
__u8 authentication;
} __packed;
+#define HCI_OP_REMOTE_OOB_DATA_REPLY 0x0430
+struct hci_cp_remote_oob_data_reply {
+ bdaddr_t bdaddr;
+ __u8 hash[16];
+ __u8 randomizer[16];
+} __packed;
+
+#define HCI_OP_REMOTE_OOB_DATA_NEG_REPLY 0x0433
+struct hci_cp_remote_oob_data_neg_reply {
+ bdaddr_t bdaddr;
+} __packed;
+
#define HCI_OP_IO_CAPABILITY_NEG_REPLY 0x0434
struct hci_cp_io_capability_neg_reply {
bdaddr_t bdaddr;
@@ -943,6 +955,11 @@ struct hci_ev_io_capa_reply {
__u8 authentication;
} __packed;
+#define HCI_EV_REMOTE_OOB_DATA_REQUEST 0x35
+struct hci_ev_remote_oob_data_request {
+ bdaddr_t bdaddr;
+} __packed;
+
#define HCI_EV_SIMPLE_PAIR_COMPLETE 0x36
struct hci_ev_simple_pair_complete {
__u8 status;
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 6be278b..2893288 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -82,6 +82,13 @@ struct link_key {
u8 pin_len;
};
+struct oob_data {
+ struct list_head list;
+ bdaddr_t bdaddr;
+ u8 hash[16];
+ u8 randomizer[16];
+};
+
#define NUM_REASSEMBLY 4
struct hci_dev {
struct list_head list;
@@ -169,6 +176,8 @@ struct hci_dev {
struct list_head link_keys;
+ struct list_head remote_oob_data;
+
struct hci_dev_stats stat;
struct sk_buff_head driver_init;
@@ -501,6 +510,13 @@ int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
u8 *key, u8 type, u8 pin_len);
int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
+int hci_remote_oob_data_clear(struct hci_dev *hdev);
+struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev,
+ bdaddr_t *bdaddr);
+int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
+ u8 *randomizer);
+int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr);
+
void hci_del_off_timer(struct hci_dev *hdev);
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 18e2fb6..9bfd30f 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -174,6 +174,20 @@ struct mgmt_rp_read_local_oob_data_failed {
__le16 index;
} __packed;
+#define MGMT_OP_ADD_REMOTE_OOB_DATA 0x0018
+struct mgmt_cp_add_remote_oob_data {
+ __le16 index;
+ bdaddr_t bdaddr;
+ __u8 hash[16];
+ __u8 randomizer[16];
+} __packed;
+
+#define MGMT_OP_REMOVE_REMOTE_OOB_DATA 0x0019
+struct mgmt_cp_remove_remote_oob_data {
+ __le16 index;
+ bdaddr_t bdaddr;
+} __packed;
+
#define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete {
__le16 opcode;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index b372fb8..a1d2263 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1077,6 +1077,79 @@ static void hci_cmd_timer(unsigned long arg)
tasklet_schedule(&hdev->cmd_task);
}
+struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev,
+ bdaddr_t *bdaddr)
+{
+ struct list_head *p;
+
+ list_for_each(p, &hdev->remote_oob_data) {
+ struct oob_data *data;
+
+ data = list_entry(p, struct oob_data, list);
+
+ if (bacmp(bdaddr, &data->bdaddr) == 0)
+ return data;
+ }
+
+ return NULL;
+}
+
+int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr)
+{
+ struct oob_data *data;
+
+ data = hci_find_remote_oob_data(hdev, bdaddr);
+ if (!data)
+ return -ENOENT;
+
+ BT_DBG("%s removing %s", hdev->name, batostr(bdaddr));
+
+ list_del(&data->list);
+ kfree(data);
+
+ return 0;
+}
+
+int hci_remote_oob_data_clear(struct hci_dev *hdev)
+{
+ struct list_head *p, *n;
+
+ list_for_each_safe(p, n, &hdev->remote_oob_data) {
+ struct oob_data *data;
+
+ data = list_entry(p, struct oob_data, list);
+
+ list_del(p);
+ kfree(data);
+ }
+
+ return 0;
+}
+
+int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
+ u8 *randomizer)
+{
+ struct oob_data *data;
+
+ data = hci_find_remote_oob_data(hdev, bdaddr);
+
+ if (!data) {
+ data = kmalloc(sizeof(*data), GFP_ATOMIC);
+ if (!data)
+ return -ENOMEM;
+
+ bacpy(&data->bdaddr, bdaddr);
+ list_add(&data->list, &hdev->remote_oob_data);
+ }
+
+ memcpy(data->hash, hash, 16);
+ memcpy(data->randomizer, randomizer, 16);
+
+ BT_DBG("%s for %s", hdev->name, batostr(bdaddr));
+
+ return 0;
+}
+
/* Register HCI device */
int hci_register_dev(struct hci_dev *hdev)
{
@@ -1141,6 +1214,8 @@ int hci_register_dev(struct hci_dev *hdev)
INIT_LIST_HEAD(&hdev->link_keys);
+ INIT_LIST_HEAD(&hdev->remote_oob_data);
+
INIT_WORK(&hdev->power_on, hci_power_on);
INIT_WORK(&hdev->power_off, hci_power_off);
setup_timer(&hdev->off_timer, hci_auto_off, (unsigned long) hdev);
@@ -1220,6 +1295,7 @@ int hci_unregister_dev(struct hci_dev *hdev)
hci_blacklist_clear(hdev);
hci_uuids_clear(hdev);
hci_link_keys_clear(hdev);
+ hci_remote_oob_data_clear(hdev);
hci_dev_unlock_bh(hdev);
__hci_dev_put(hdev);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 0c351d9..abaa905 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2409,6 +2409,37 @@ static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_
hci_dev_unlock(hdev);
}
+static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
+{
+ struct hci_ev_remote_oob_data_request *ev = (void *) skb->data;
+ struct oob_data *data;
+
+ BT_DBG("%s", hdev->name);
+
+ hci_dev_lock(hdev);
+
+ data = hci_find_remote_oob_data(hdev, &ev->bdaddr);
+ if (data) {
+ struct hci_cp_remote_oob_data_reply cp;
+
+ bacpy(&cp.bdaddr, &ev->bdaddr);
+ memcpy(cp.hash, data->hash, 16);
+ memcpy(cp.randomizer, data->randomizer, 16);
+
+ hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_REPLY, sizeof(cp),
+ &cp);
+ } else {
+ struct hci_cp_remote_oob_data_neg_reply cp;
+
+ bacpy(&cp.bdaddr, &ev->bdaddr);
+ hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_NEG_REPLY, sizeof(cp),
+ &cp);
+ }
+
+ hci_dev_unlock(hdev);
+}
+
static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_le_conn_complete *ev = (void *) skb->data;
@@ -2605,6 +2636,9 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
case HCI_EV_LE_META:
hci_le_meta_evt(hdev, skb);
+
+ case HCI_EV_REMOTE_OOB_DATA_REQUEST:
+ hci_remote_oob_data_request_evt(hdev, skb);
break;
default:
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 2847934..571cbcf 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1112,6 +1112,73 @@ unlock:
return err;
}
+static int add_remote_oob_data(struct sock *sk, unsigned char *data, u16 len)
+{
+ struct hci_dev *hdev;
+ struct mgmt_cp_add_remote_oob_data *cp;
+ u16 dev_id;
+ int err;
+
+ cp = (void *) data;
+ dev_id = get_unaligned_le16(&cp->index);
+
+ BT_DBG("hci%u ", dev_id);
+
+ hdev = hci_dev_get(dev_id);
+ if (!hdev)
+ return cmd_status(sk, MGMT_OP_ADD_REMOTE_OOB_DATA, ENODEV, NULL,
+ 0);
+
+ hci_dev_lock_bh(hdev);
+
+ err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
+ cp->randomizer);
+ if (err < 0)
+ err = cmd_status(sk, MGMT_OP_ADD_REMOTE_OOB_DATA, -err, NULL,
+ 0);
+ else
+ err = cmd_complete(sk, MGMT_OP_ADD_REMOTE_OOB_DATA, &dev_id,
+ sizeof(dev_id));
+
+ hci_dev_unlock_bh(hdev);
+ hci_dev_put(hdev);
+
+ return err;
+}
+
+static int remove_remote_oob_data(struct sock *sk, unsigned char *data, u16 len)
+{
+ struct hci_dev *hdev;
+ struct mgmt_cp_remove_remote_oob_data *cp;
+ u16 dev_id;
+ int err;
+
+ cp = (void *) data;
+ dev_id = get_unaligned_le16(&cp->index);
+
+ BT_DBG("hci%u ", dev_id);
+
+ hdev = hci_dev_get(dev_id);
+ if (!hdev)
+ return cmd_status(sk, MGMT_OP_REMOVE_REMOTE_OOB_DATA, ENODEV,
+ NULL, 0);
+
+ hci_dev_lock_bh(hdev);
+
+ err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
+ if (err < 0)
+ err = cmd_status(sk, MGMT_OP_REMOVE_REMOTE_OOB_DATA, -err, NULL,
+ 0);
+ else
+ err = cmd_complete(sk, MGMT_OP_REMOVE_REMOTE_OOB_DATA, &dev_id,
+ sizeof(dev_id));
+
+ hci_dev_unlock_bh(hdev);
+ hci_dev_put(hdev);
+
+ return err;
+}
+
int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
{
unsigned char *buf;
@@ -1200,6 +1267,12 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
case MGMT_OP_READ_LOCAL_OOB_DATA:
err = read_local_oob_data(sk, buf + sizeof(*hdr), len);
break;
+ case MGMT_OP_ADD_REMOTE_OOB_DATA:
+ err = add_remote_oob_data(sk, buf + sizeof(*hdr), len);
+ break;
+ case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
+ err = remove_remote_oob_data(sk, buf + sizeof(*hdr), len);
+ break;
default:
BT_DBG("Unknown op %u", opcode);
err = cmd_status(sk, opcode, 0x01, NULL, 0);
--
1.7.0.4
^ permalink raw reply related
* [PATCH v2] Bluetooth: Use EIO code to report HCI error to userpace
From: Szymon Janc @ 2011-02-18 9:15 UTC (permalink / raw)
To: linux-bluetooth; +Cc: par-gunnar.p.hjalmdahl, henrik.possung, Szymon Janc
In-Reply-To: <20110218073400.GA874@null>
It is not possible to distinguish in cmd_status if error was from kernel or
from HCI (because HCI status codes and kernel error codes overlaps). Since
in mgmt only kernel sends HCI commands HCI errors shouldn't be needed for
userspace at all so report EIO to userspace on HCI error.
Signed-off-by: Szymon Janc <szymon.janc@tieto.com>
---
net/bluetooth/mgmt.c | 7 +++----
1 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index aee1da6..dee82fe 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1372,8 +1372,7 @@ int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
return -ENOENT;
if (status != 0)
- err = cmd_status(cmd->sk, MGMT_OP_PIN_CODE_REPLY, status, NULL,
- 0);
+ err = cmd_status(cmd->sk, MGMT_OP_PIN_CODE_REPLY, EIO, NULL, 0);
else
err = cmd_complete(cmd->sk, MGMT_OP_PIN_CODE_REPLY,
bdaddr, sizeof(*bdaddr));
@@ -1394,8 +1393,8 @@ int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
return -ENOENT;
if (status != 0)
- err = cmd_status(cmd->sk, MGMT_OP_PIN_CODE_NEG_REPLY, status,
- NULL, 0);
+ err = cmd_status(cmd->sk, MGMT_OP_PIN_CODE_NEG_REPLY, EIO, NULL,
+ 0);
else
err = cmd_complete(cmd->sk, MGMT_OP_PIN_CODE_NEG_REPLY,
bdaddr, sizeof(*bdaddr));
--
1.7.0.4
^ permalink raw reply related
* Re: hidp_output_raw_report, HID_OUTPUT_REPORT and Sixaxis
From: Jiri Kosina @ 2011-02-18 8:45 UTC (permalink / raw)
To: Antonio Ospite
Cc: pascal@pabr.org, linux-input, linux-bluetooth, Bastien Nocera,
Marcel Holtmann, Alan Ott
In-Reply-To: <20110217151931.d7ee7e29.ospite@studenti.unina.it>
On Thu, 17 Feb 2011, Antonio Ospite wrote:
> However, even if my patch gets is, Output reports on the Sixaxis will
> stop working again as soon as someone implements the behavior you are
> suggesting, that is:
> Feature Report -> SET_REPORT on the Control channel
> Output Report -> DATA on the Interrupt channel
>
> So I am going to submit the hidp_output_raw_report() override in
> hid-sony.c as well, does this sound OK?
That makes sense to me.
Could you please repost all the patches that are currently being discussed
are flying around in the air?
I feel I haven't been CCed on all of them, so I don't have the complete
picture.
Thanks,
--
Jiri Kosina
SUSE Labs, Novell Inc.
^ permalink raw reply
* Re: [PATCH 04/10] Bluetooth: Use EIO code to report HCI error to userpace
From: Ville Tervo @ 2011-02-18 7:34 UTC (permalink / raw)
To: ext Szymon Janc
Cc: linux-bluetooth@vger.kernel.org,
par-gunnar.p.hjalmdahl@stericsson.com,
henrik.possung@stericsson.com
In-Reply-To: <201102171523.10461.szymon.janc@tieto.com>
Hi,
On Thu, Feb 17, 2011 at 03:23:10PM +0100, ext Szymon Janc wrote:
> Hi,
>
> > On Thu, Feb 17, 2011 at 02:16:35PM +0100, ext Szymon Janc wrote:
> > > Signed-off-by: Szymon Janc <szymon.janc@tieto.com>
> > > ---
> > > net/bluetooth/mgmt.c | 7 +++----
> > > 1 files changed, 3 insertions(+), 4 deletions(-)
> >
> > Some kind of explanation why EIO is better than status would be nice.
>
> As I've mentioned in cover letter:
Cover letters does not end up to git log. Proper description helps debugging
later a much if we can easily determine why this was needed and what was the
motivation for this patch.
> It is not possible to distinguish in cmd status if error was from kernel
> or from HCI. Since in mgmt only kernel sends HCI commands their errors
> shouldn't be needed for userspace so report EIO to userspace on HCI error
> (if HCI error is needed for debugging, logs can be added on kernel side)
>
> HCI status codes and kernel error codes overlaps i.e. one can't distinguish
> if error was ENOMEM or HCI Command Disallowed as both have value 12.
>
> For userspace is should be enough to just know that HCI failed, not why.
> (in fact, currently userspace is not able to determine error too...)
This sounds reasonable to me.
--
Ville
^ permalink raw reply
* Re: PATCH [1/2] batostr(): Switch byte order before converting
From: David Herrmann @ 2011-02-17 23:10 UTC (permalink / raw)
To: David Herrmann, linux-bluetooth
In-Reply-To: <20110217190401.GA22042@jh-x301>
Hi Johan,
On Thu, Feb 17, 2011 at 8:04 PM, Johan Hedberg <johan.hedberg@gmail.com> wrote:
> We can't go ahead and change the behavior of existing libbluetooth
> functions like that since it would break any applications relying on the
> old behavior (without baswap). So this patch isn't acceptable upstream.
I thought of this more like a bug because it doesn't make sense to me
why there should be a function returning the string without swapping
the bytes first. So I didn't think of this as breaking the API, but
more like fixing a function that is not used because it produces
incorrect results.
Anyway, your explanation makes sense and I don't use this function so
I am totally ok with that.
David
^ permalink raw reply
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