Register features in SDP record

This commit is contained in:
Santiago Carot-Nemesio 2010-09-15 14:00:03 +02:00
parent bb0b2e841e
commit ced4231b06
4 changed files with 443 additions and 4 deletions

View File

@ -272,13 +272,9 @@ static gboolean update_adapter(struct hdp_adapter *hdp_adapter)
}
update:
/*
if (hdp_update_sdp_record(hdp_adapter, applications))
return TRUE;
error("Error updating the SDP record");
*/
DBG("TODO: Register in sdp");
return TRUE;
fail:
if (hdp_adapter->mi)

View File

@ -35,6 +35,12 @@
#define HEALTH_MANAGER "org.bluez.HealthManager"
#define HDP_VERSION 0x0100
#define HDP_SERVICE_NAME "Bluez HDP"
#define HDP_SERVICE_DSC "A Bluez health device profile implementation"
#define HDP_SERVICE_PROVIDER "Bluez"
#define HDP_MDEP_ECHO 0x00
#define HDP_MDEP_INITIAL 0x01
#define HDP_MDEP_FINAL 0x7F
@ -60,6 +66,10 @@ typedef enum {
HDP_UNKNOWN_ERROR
} HdpError;
enum data_specs {
DATA_EXCHANGE_SPEC_11073 = 0x01
};
struct hdp_application {
char *path; /* The path of the application */
uint16_t data_type; /* Data type handled for this application */

View File

@ -25,9 +25,14 @@
#include <gdbus.h>
#include <adapter.h>
#include <stdint.h>
#include <hdp_types.h>
#include <hdp_util.h>
#include <mcap.h>
#include <sdpd.h>
#include <sdp_lib.h>
typedef gboolean (*parse_item_f)(DBusMessageIter *iter, gpointer user_data,
GError **err);
@ -258,3 +263,430 @@ fail:
g_free(app);
return NULL;
}
static gboolean is_app_role(GSList *app_list, HdpRole role)
{
struct hdp_application *app;
GSList *l;
for (l = app_list; l; l = l->next) {
app = l->data;
if (app->role == role)
return TRUE;
}
return FALSE;
}
static gboolean set_sdp_services_uuid(sdp_record_t *record, HdpRole role)
{
uuid_t svc_uuid_source, svc_uuid_sink;
sdp_list_t *svc_list = NULL;
sdp_uuid16_create(&svc_uuid_sink, HDP_SINK_SVCLASS_ID);
sdp_uuid16_create(&svc_uuid_source, HDP_SOURCE_SVCLASS_ID);
sdp_get_service_classes(record, &svc_list);
if (role == HDP_SOURCE) {
if (sdp_list_find(svc_list, &svc_uuid_source, sdp_uuid_cmp) ==
NULL)
svc_list = sdp_list_append(svc_list, &svc_uuid_source);
} else if (role == HDP_SINK) {
if (sdp_list_find(svc_list, &svc_uuid_sink, sdp_uuid_cmp) ==
NULL)
svc_list = sdp_list_append(svc_list, &svc_uuid_sink);
}
if (sdp_set_service_classes(record, svc_list) < 0) {
sdp_list_free(svc_list, NULL);
return FALSE;
}
sdp_list_free(svc_list, NULL);
return TRUE;
}
static gboolean register_service_protocols(struct hdp_adapter *adapter,
sdp_record_t *sdp_record)
{
gboolean ret;
uuid_t l2cap_uuid, mcap_c_uuid;
sdp_list_t *l2cap_list, *proto_list, *mcap_list, *access_proto_list;
sdp_data_t *psm, *mcap_ver;
uint16_t version = MCAP_VERSION;
/* set l2cap information */
sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
l2cap_list = sdp_list_append(NULL, &l2cap_uuid);
if (!l2cap_list) {
ret = FALSE;
goto end;
}
psm = sdp_data_alloc(SDP_UINT16, &adapter->ccpsm);
if (!psm) {
ret = FALSE;
goto end;
}
if (!sdp_list_append(l2cap_list, psm)) {
ret = FALSE;
goto end;
}
proto_list = sdp_list_append(NULL, l2cap_list);
if (!proto_list) {
ret = FALSE;
goto end;
}
/* set mcap information */
sdp_uuid16_create(&mcap_c_uuid, MCAP_CTRL_UUID);
mcap_list = sdp_list_append(NULL, &mcap_c_uuid);
if (!mcap_list) {
ret = FALSE;
goto end;
}
mcap_ver = sdp_data_alloc(SDP_UINT16, &version);
if (!mcap_ver) {
ret = FALSE;
goto end;
}
if (!sdp_list_append( mcap_list, mcap_ver)) {
ret = FALSE;
goto end;
}
if (!sdp_list_append( proto_list, mcap_list)) {
ret = FALSE;
goto end;
}
/* attach protocol information to service record */
access_proto_list = sdp_list_append(NULL, proto_list);
if (!access_proto_list) {
ret = FALSE;
goto end;
}
if (sdp_set_access_protos(sdp_record, access_proto_list) < 0) {
ret = FALSE;
goto end;
}
ret = TRUE;
end:
if (l2cap_list)
sdp_list_free(l2cap_list, NULL);
if (mcap_list)
sdp_list_free(mcap_list, NULL);
if (proto_list)
sdp_list_free(proto_list, NULL);
if (access_proto_list)
sdp_list_free(access_proto_list, NULL);
if (psm)
sdp_data_free(psm);
if (mcap_ver)
sdp_data_free(mcap_ver);
return ret;
}
static gboolean register_service_profiles(sdp_record_t *sdp_record)
{
gboolean ret;
sdp_list_t *profile_list;
sdp_profile_desc_t hdp_profile;
/* set hdp information */
sdp_uuid16_create( &hdp_profile.uuid, HDP_SVCLASS_ID);
hdp_profile.version = HDP_VERSION;
profile_list = sdp_list_append(NULL, &hdp_profile);
if (!profile_list)
return FALSE;
/* set profile descriptor list */
if (sdp_set_profile_descs(sdp_record, profile_list) < 0)
ret = FALSE;
else
ret = TRUE;
sdp_list_free(profile_list, NULL);
return ret;
}
static gboolean register_service_aditional_protocols(
struct hdp_adapter *adapter,
sdp_record_t *sdp_record)
{
gboolean ret;
uuid_t l2cap_uuid, mcap_d_uuid;
sdp_list_t *l2cap_list, *proto_list, *mcap_list, *access_proto_list;
sdp_data_t *psm = NULL;
/* set l2cap information */
sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
l2cap_list = sdp_list_append(NULL, &l2cap_uuid);
if (!l2cap_list) {
ret = FALSE;
goto end;
}
psm = sdp_data_alloc(SDP_UINT16, &adapter->dcpsm);
if (!psm) {
ret = FALSE;
goto end;
}
if (!sdp_list_append(l2cap_list, psm)) {
ret = FALSE;
goto end;
}
proto_list = sdp_list_append(NULL, l2cap_list);
if (!proto_list) {
ret = FALSE;
goto end;
}
/* set mcap information */
sdp_uuid16_create(&mcap_d_uuid, MCAP_DATA_UUID);
mcap_list = sdp_list_append(NULL, &mcap_d_uuid);
if (!mcap_list) {
ret = FALSE;
goto end;
}
if (!sdp_list_append( proto_list, mcap_list)) {
ret = FALSE;
goto end;
}
/* attach protocol information to service record */
access_proto_list = sdp_list_append(NULL, proto_list);
if (!access_proto_list) {
ret = FALSE;
goto end;
}
if (sdp_set_add_access_protos(sdp_record, access_proto_list) < 0)
ret = FALSE;
else
ret = TRUE;
end:
if (l2cap_list)
sdp_list_free(l2cap_list, NULL);
if (mcap_list)
sdp_list_free(mcap_list, NULL);
if (proto_list)
sdp_list_free(proto_list, NULL);
if (access_proto_list)
sdp_list_free(access_proto_list, NULL);
if (psm)
sdp_data_free(psm);
return ret;
}
static sdp_list_t *app_to_sdplist(struct hdp_application *app)
{
sdp_data_t *mdepid, *dtype, *role, *desc;
sdp_list_t *f_list;
mdepid = sdp_data_alloc(SDP_UINT8, &app->id);
if (!mdepid)
return NULL;
dtype = sdp_data_alloc(SDP_UINT16, &app->data_type);
if (!dtype)
goto fail;
role = sdp_data_alloc(SDP_UINT8, &app->role);
if (!role)
goto fail;
if (app->description) {
desc = sdp_data_alloc(SDP_TEXT_STR8, app->description);
if (!desc)
goto fail;
}
f_list = sdp_list_append(NULL, mdepid);
if (!f_list)
goto fail;
if (!sdp_list_append(f_list, dtype))
goto fail;
if (!sdp_list_append(f_list, role))
goto fail;
if (desc)
if (!sdp_list_append(f_list, desc))
goto fail;
return f_list;
fail:
if (f_list)
sdp_list_free(f_list, NULL);
if (mdepid)
sdp_data_free(mdepid);
if (dtype)
sdp_data_free(dtype);
if (role)
sdp_data_free(role);
if (desc)
sdp_data_free(desc);
return NULL;
}
static gboolean register_features(struct hdp_application *app,
sdp_list_t **sup_features)
{
sdp_list_t *hdp_feature;
hdp_feature = app_to_sdplist(app);
if (!hdp_feature)
goto fail;
if (!*sup_features) {
*sup_features = sdp_list_append(NULL, hdp_feature);
if (!*sup_features)
goto fail;
} else if (!sdp_list_append(*sup_features, hdp_feature)) {
goto fail;
}
return TRUE;
fail:
if (hdp_feature)
sdp_list_free(hdp_feature, (sdp_free_func_t)sdp_data_free);
return FALSE;
}
static void free_hdp_list(void *list)
{
sdp_list_t *hdp_list = list;
sdp_list_free(hdp_list, (sdp_free_func_t)sdp_data_free);
}
static gboolean register_service_sup_features(GSList *app_list,
sdp_record_t *sdp_record)
{
GSList *l;
sdp_list_t *sup_features = NULL;
for (l = app_list; l; l = l->next) {
if (!register_features(l->data, &sup_features))
return FALSE;
}
if (sdp_set_supp_feat(sdp_record, sup_features) < 0) {
sdp_list_free(sup_features, free_hdp_list);
return FALSE;
}
return TRUE;
}
static gboolean register_data_exchange_spec(sdp_record_t *record)
{
sdp_data_t *spec;
uint8_t data_spec = DATA_EXCHANGE_SPEC_11073;
/* As by now 11073 is the only supported we set it by default */
spec = sdp_data_alloc(SDP_UINT8, &data_spec);
if (!spec)
return FALSE;
if (sdp_attr_add(record, SDP_ATTR_DATA_EXCHANGE_SPEC, spec) < 0) {
sdp_data_free(spec);
return FALSE;
}
return TRUE;
}
static gboolean register_mcap_features(sdp_record_t *sdp_record)
{
sdp_data_t *mcap_proc;
uint8_t mcap_sup_proc = MCAP_SUP_PROC;
mcap_proc = sdp_data_alloc(SDP_UINT8, &mcap_sup_proc);
if (!mcap_proc)
return FALSE;
if (sdp_attr_add(sdp_record, SDP_ATTR_MCAP_SUPPORTED_PROCEDURES,
mcap_proc) < 0) {
sdp_data_free(mcap_proc);
return FALSE;
}
return TRUE;
}
gboolean hdp_update_sdp_record(struct hdp_adapter *adapter, GSList *app_list)
{
sdp_record_t *sdp_record;
bdaddr_t addr;
if (adapter->sdp_handler)
remove_record_from_server(adapter->sdp_handler);
if (!app_list) {
adapter->sdp_handler = 0;
return TRUE;
}
sdp_record = sdp_record_alloc();
if (!sdp_record)
return FALSE;
if (adapter->sdp_handler)
sdp_record->handle = adapter->sdp_handler;
else
sdp_record->handle = 0xffffffff; /* Set automatically */
if (is_app_role(app_list, HDP_SINK))
set_sdp_services_uuid(sdp_record, HDP_SINK);
if (is_app_role(app_list, HDP_SOURCE))
set_sdp_services_uuid(sdp_record, HDP_SOURCE);
if (!register_service_protocols(adapter, sdp_record))
goto fail;
if (!register_service_profiles(sdp_record))
goto fail;
if (!register_service_aditional_protocols(adapter, sdp_record))
goto fail;
sdp_set_info_attr(sdp_record, HDP_SERVICE_NAME, HDP_SERVICE_PROVIDER,
HDP_SERVICE_DSC);
if (!register_service_sup_features(app_list, sdp_record))
goto fail;
if (!register_data_exchange_spec(sdp_record))
goto fail;
register_mcap_features(sdp_record);
if (sdp_set_record_state(sdp_record, adapter->record_state++))
goto fail;
adapter_get_address(adapter->btd_adapter, &addr);
if (add_record_to_server(&addr, sdp_record) < 0)
goto fail;
adapter->sdp_handler = sdp_record->handle;
return TRUE;
fail:
if (sdp_record)
sdp_record_free(sdp_record);
return FALSE;
}

View File

@ -28,5 +28,6 @@
#define __HDP_UTIL_H__
struct hdp_application *hdp_get_app_config(DBusMessageIter *iter, GError **err);
gboolean hdp_update_sdp_record(struct hdp_adapter *adapter, GSList *app_list);
#endif /* __HDP_UTIL_H__ */