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
[email protected]
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
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
[email protected]
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
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
[email protected]
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum