From 612d0207646064f309edd564a69d30b42de9e26f Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Mon, 11 Apr 2011 15:24:03 -0300 Subject: [PATCH] Register primary services exported over basic rate This patch registers the object paths for primary services exported through SDP. PSM, start and end handle information are available in the Protocol Descriptor List. --- attrib/gatt.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++ attrib/gatt.h | 5 ++++ src/device.c | 56 +++++++++++++++++++++++++++++++++++- 3 files changed, 138 insertions(+), 1 deletion(-) diff --git a/attrib/gatt.c b/attrib/gatt.c index 0b69daf60..360218b05 100644 --- a/attrib/gatt.c +++ b/attrib/gatt.c @@ -23,8 +23,11 @@ */ #include +#include #include #include +#include +#include #include "att.h" #include "gattrib.h" @@ -575,3 +578,78 @@ guint gatt_write_cmd(GAttrib *attrib, uint16_t handle, uint8_t *value, int vlen, return g_attrib_send(attrib, 0, ATT_OP_WRITE_CMD, buf, plen, NULL, user_data, notify); } + +static sdp_data_t *proto_seq_find(sdp_list_t *proto_list) +{ + sdp_list_t *list; + uuid_t proto; + + sdp_uuid16_create(&proto, ATT_UUID); + + for (list = proto_list; list; list = list->next) { + sdp_list_t *p; + for (p = list->data; p; p = p->next) { + sdp_data_t *seq = p->data; + if (seq && seq->dtd == SDP_UUID16 && + sdp_uuid16_cmp(&proto, &seq->val.uuid) == 0) + return seq->next; + } + } + + return NULL; +} + +static gboolean parse_proto_params(sdp_list_t *proto_list, uint16_t *psm, + uint16_t *start, uint16_t *end) +{ + sdp_data_t *seq1, *seq2; + + if (psm) + *psm = sdp_get_proto_port(proto_list, L2CAP_UUID); + + /* Getting start and end handle */ + seq1 = proto_seq_find(proto_list); + if (!seq1 || seq1->dtd != SDP_UINT16) + return FALSE; + + seq2 = seq1->next; + if (!seq2 || seq2->dtd != SDP_UINT16) + return FALSE; + + if (start) + *start = seq1->val.uint16; + + if (end) + *end = seq2->val.uint16; + + return TRUE; +} + +gboolean gatt_parse_record(const sdp_record_t *rec, + uuid_t *prim_uuid, uint16_t *psm, + uint16_t *start, uint16_t *end) +{ + sdp_list_t *list; + uuid_t uuid; + gboolean ret; + + if (sdp_get_service_classes(rec, &list) < 0) + return FALSE; + + memcpy(&uuid, list->data, sizeof(uuid)); + sdp_list_free(list, free); + + if (sdp_get_access_protos(rec, &list) < 0) + return FALSE; + + ret = parse_proto_params(list, psm, start, end); + + sdp_list_foreach(list, (sdp_list_func_t) sdp_list_free, NULL); + sdp_list_free(list, NULL); + + /* FIXME: replace by bt_uuid_t after uuid_t/sdp code cleanup */ + if (ret && prim_uuid) + memcpy(prim_uuid, &uuid, sizeof(uuid_t)); + + return ret; +} diff --git a/attrib/gatt.h b/attrib/gatt.h index 221d94d06..01c651e8c 100644 --- a/attrib/gatt.h +++ b/attrib/gatt.h @@ -21,6 +21,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ +#include #define GATT_CID 4 @@ -51,3 +52,7 @@ guint gatt_read_char_by_uuid(GAttrib *attrib, uint16_t start, uint16_t end, guint gatt_exchange_mtu(GAttrib *attrib, uint16_t mtu, GAttribResultFunc func, gpointer user_data); + +gboolean gatt_parse_record(const sdp_record_t *rec, + uuid_t *prim_uuid, uint16_t *psm, + uint16_t *start, uint16_t *end); diff --git a/src/device.c b/src/device.c index d56795253..ecd1861df 100644 --- a/src/device.c +++ b/src/device.c @@ -1367,6 +1367,53 @@ static void create_device_reply(struct btd_device *device, struct browse_req *re g_dbus_send_message(req->conn, reply); } +static GSList *primary_from_record(struct btd_device *device, GSList *profiles) +{ + GSList *l, *prim_list = NULL; + char *att_uuid; + uuid_t proto_uuid; + + sdp_uuid16_create(&proto_uuid, ATT_UUID); + att_uuid = bt_uuid2string(&proto_uuid); + + for (l = profiles; l; l = l->next) { + const char *profile_uuid = l->data; + const sdp_record_t *rec; + struct att_primary *prim; + uint16_t start = 0, end = 0, psm = 0; + uuid_t prim_uuid; + + rec = btd_device_get_record(device, profile_uuid); + if (!rec) + continue; + + if (!record_has_uuid(rec, att_uuid)) + continue; + + if (!gatt_parse_record(rec, &prim_uuid, &psm, &start, &end)) + continue; + + prim = g_new0(struct att_primary, 1); + prim->start = start; + prim->end = end; + sdp_uuid2strn(&prim_uuid, prim->uuid, sizeof(prim->uuid)); + + prim_list = g_slist_append(prim_list, prim); + } + + g_free(att_uuid); + + return prim_list; +} + +static void register_primary_services(DBusConnection *conn, + struct btd_device *device, GSList *prim_list) +{ + /* TODO: PSM is hardcoded */ + attrib_client_register(conn, device, 31, NULL, prim_list); + device->primaries = g_slist_concat(device->primaries, prim_list); +} + static void search_cb(sdp_list_t *recs, int err, gpointer user_data) { struct browse_req *req = user_data; @@ -1396,9 +1443,16 @@ static void search_cb(sdp_list_t *recs, int err, gpointer user_data) } /* Probe matching drivers for services added */ - if (req->profiles_added) + if (req->profiles_added) { + GSList *list; + device_probe_drivers(device, req->profiles_added); + list = primary_from_record(device, req->profiles_added); + if (list) + register_primary_services(req->conn, device, list); + } + /* Remove drivers for services removed */ if (req->profiles_removed) device_remove_drivers(device, req->profiles_removed); -- 2.47.3