mirror of
https://git.kernel.org/pub/scm/bluetooth/bluez.git
synced 2024-11-16 16:54:38 +08:00
Register features in SDP record
This commit is contained in:
parent
bb0b2e841e
commit
ced4231b06
@ -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)
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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__ */
|
||||
|
Loading…
Reference in New Issue
Block a user