From: Brian Gix <bgix@codeaurora.org>
To: linux-bluetooth@vger.kernel.org
Cc: johan.hedberg@nokia.com, padovan@profusion.mobi,
anderson.lizardo@openbossa.org, Brian Gix <bgix@codeaurora.org>
Subject: [PATCH 1/1] Add SDP registration of Primary GATT services
Date: Fri, 18 Feb 2011 12:11:38 -0800 [thread overview]
Message-ID: <1298059898-27366-2-git-send-email-bgix@codeaurora.org> (raw)
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
next prev parent reply other threads:[~2011-02-18 20:11 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-02-18 20:11 [PATCH 0/1] SDP registration of Primary GATT Services Brian Gix
2011-02-18 20:11 ` Brian Gix [this message]
2011-02-18 20:20 ` [PATCH 1/1] Add SDP registration of Primary GATT services Brian Gix
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1298059898-27366-2-git-send-email-bgix@codeaurora.org \
--to=bgix@codeaurora.org \
--cc=anderson.lizardo@openbossa.org \
--cc=johan.hedberg@nokia.com \
--cc=linux-bluetooth@vger.kernel.org \
--cc=padovan@profusion.mobi \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.