[PATCH 0/1 rev2] Add SDP registration of Primary Services

STALE5651d

3 messages, 2 authors, 2011-02-18 · open the first message on its own page

[PATCH 0/1 rev2] Add SDP registration of Primary Services

From: Brian Gix <hidden>
Date: 2011-02-18 20:36:18

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

[PATCH 1/1 rev2] Add SDP registration of Primary GATT services

From: Brian Gix <hidden>
Date: 2011-02-18 20:36:19

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

Re: [PATCH 1/1 rev2] Add SDP registration of Primary GATT services

From: Anderson Lizardo <hidden>
Date: 2011-02-18 22:03:45

Hi Brian,

On Fri, Feb 18, 2011 at 5:36 PM, Brian Gix [off-list ref] wrote:
quoted hunk
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?
quoted hunk
 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.
quoted hunk
       /* 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.
quoted hunk
 }
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:
quoted hunk
+
+               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.
quoted hunk
@@ -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.
quoted hunk
+       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
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help