2014-06-16 17:51:10

by Ravi kumar Veeramally

[permalink] [raw]
Subject: [PATCH 0/4] Intiates L2CAP Control Channel

Patchset is initial implementaion for MCL connection. It can
be tested with PTS, register application in source or sink role
and run source or sink L2CAP control channel tests. Initiate
channel connection from haltest, only MCAP MCL gets connected.

SINK
-----------
hl register_application bluez-android Bluez bluez-hdp health-device-profile 1 BTHL_MDEP_ROLE_SINK 4100 BTHL_CHANNEL_TYPE_RELIABLE pulse-oximeter

hl connect_channel 1 00:1b:dc:05:b5:54 0

SOURCE
-----------
hl register_application bluez-android Bluez bluez-hdp health-device-profile 1 BTHL_MDEP_ROLE_SOURCE 4100 BTHL_CHANNEL_TYPE_RELIABLE pulse-oximeter

hl connect_channel 1 00:1b:dc:05:b5:54 0

Ravi kumar Veeramally (4):
profiles/health/hdp: Fix memory leak in SDP record preparati Sdp
record preparation part is copied to android/health.c from
profiles/health/hdp_utils.c. Memory leak is noticed while
testing. Memory summay is from android daemon, but code snippet
is same. It is already fixed in android/health.c while submitting
android related patches.
anrdoid/hal-health: Fix wrong channel type defines
android/health: Initial connect channel implementation
android/health: Notify channel connection status

android/hal-health.c | 13 +-
android/hal-msg.h | 6 +-
android/health.c | 434 ++++++++++++++++++++++++++++++++++++++++++++-
profiles/health/hdp_util.c | 2 +
4 files changed, 449 insertions(+), 6 deletions(-)

--
1.9.1



2014-06-16 20:57:08

by Ravi kumar Veeramally

[permalink] [raw]
Subject: Re: [PATCH 3/4] android/health: Initial connect channel implementation

Hi Szymon,

On 06/16/2014 11:21 PM, Szymon Janc wrote:
> Hi Ravi,
>
> On Monday 16 June 2014 20:51:13 Ravi kumar Veeramally wrote:
>> Fetches remote sdp record and initiates MCL connection.
>> ---
>> android/health.c | 416
>> ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 414
>> insertions(+), 2 deletions(-)
>>
>> diff --git a/android/health.c b/android/health.c
>> index 7e2c5d6..07df2c4 100644
>> --- a/android/health.c
>> +++ b/android/health.c
>> @@ -36,9 +36,13 @@
>> #include "lib/bluetooth.h"
>> #include "lib/sdp.h"
>> #include "lib/sdp_lib.h"
>> +#include "lib/uuid.h"
>> +#include "lib/l2cap.h"
>> #include "src/log.h"
>> #include "src/shared/util.h"
>> #include "src/shared/queue.h"
>> +#include "src/uuid-helper.h"
>> +#include "src/sdp-client.h"
>>
>> #include "hal-msg.h"
>> #include "ipc-common.h"
>> @@ -59,6 +63,17 @@ static struct mcap_instance *mcap = NULL;
>> static uint32_t record_id = 0;
>> static uint32_t record_state = 0;
>>
>> +struct health_device;
>> +
> Reorder structures definitions to avoid this.
Ok.
>
>> +struct health_channel {
>> + uint8_t mdep_id;
>> + uint8_t type;
>> +
>> + struct health_device *dev;
>> +
>> + uint16_t id; /* channel id */
>> +};
>> +
>> struct mdep_cfg {
>> uint8_t role;
>> uint16_t data_type;
>> @@ -68,6 +83,19 @@ struct mdep_cfg {
>> uint8_t id; /* mdep id */
>> };
>>
>> +struct health_device {
>> + bdaddr_t dst;
>> + uint16_t app_id;
>> +
>> + struct mcap_mcl *mcl;
>> + bool mcl_conn;
>> +
>> + struct queue *channels; /* data channels */
>> +
>> + uint16_t ccpsm;
>> + uint16_t dcpsm;
>> +};
>> +
>> struct health_app {
>> char *app_name;
>> char *provider_name;
>> @@ -77,8 +105,54 @@ struct health_app {
>> struct queue *mdeps;
>>
>> uint16_t id; /* app id */
>> + struct queue *devices;
>> };
>>
>> +static void free_health_channel(void *data)
>> +{
>> + struct health_channel *channel = data;
>> +
>> + if (!channel)
>> + return;
>> +
>> + free(channel);
>> +}
>> +
>> +static void destroy_channel(void *data)
>> +{
>> + struct health_channel *channel = data;
>> +
>> + if (!channel)
>> + return;
>> +
>> + /* TODO: Notify channel connection status DESTROYED */
>> + queue_remove(channel->dev->channels, channel);
>> + free_health_channel(channel);
>> +}
>> +
>> +static void unref_mcl(struct health_device *dev)
>> +{
>> + if (!dev && !dev->mcl)
>> + return;
>> +
>> + mcap_close_mcl(dev->mcl, FALSE);
>> + mcap_mcl_unref(dev->mcl);
>> + dev->mcl = NULL;
>> + dev->mcl_conn = FALSE;
>> +}
>> +
>> +static void free_health_device(void *data)
>> +{
>> + struct health_device *dev = data;
>> +
>> + if (!dev)
>> + return;
>> +
>> + unref_mcl(dev);
>> + queue_destroy(dev->channels, free_health_channel);
>> + free(dev);
>> +}
>> +
>> static void free_mdep_cfg(void *data)
>> {
>> struct mdep_cfg *cfg = data;
>> @@ -102,6 +176,7 @@ static void free_health_app(void *data)
>> free(app->service_name);
>> free(app->service_descr);
>> queue_destroy(app->mdeps, free_mdep_cfg);
>> + queue_destroy(app->devices, free_health_device);
>> free(app);
>> }
>>
>> @@ -126,6 +201,14 @@ static bool mdep_by_mdep_role(const void *data, const
>> void *user_data) return mdep->role == role;
>> }
>>
>> +static bool mdep_by_mdep_id(const void *data, const void *user_data)
>> +{
>> + const struct mdep_cfg *mdep = data;
>> + uint16_t mdep_id = PTR_TO_INT(user_data);
>> +
>> + return mdep->id == mdep_id;
>> +}
>> +
>> static bool app_by_app_id(const void *data, const void *user_data)
>> {
>> const struct health_app *app = data;
>> @@ -744,12 +827,341 @@ static void bt_health_unregister_app(const void *buf,
>> uint16_t len) HAL_OP_HEALTH_UNREG_APP, HAL_STATUS_SUCCESS);
>> }
>>
>> +static int get_prot_desc_entry(sdp_data_t *entry, int type, guint16 *val)
>> +{
>> + sdp_data_t *iter;
>> + int proto;
>> +
>> + if (!entry || !SDP_IS_SEQ(entry->dtd))
>> + return -1;
>> +
>> + iter = entry->val.dataseq;
>> + if (!(iter->dtd & SDP_UUID_UNSPEC))
>> + return -1;
>> + proto = sdp_uuid_to_proto(&iter->val.uuid);
>> + if (proto != type)
>> + return -1;
>> +
>> + if (!val)
>> + return 0;
>> +
>> + iter = iter->next;
>> + if (iter->dtd != SDP_UINT16)
>> + return -1;
>> +
>> + *val = iter->val.uint16;
>> +
>> + return 0;
>> +}
>> +
>> +static int get_prot_desc_list(const sdp_record_t *rec, uint16_t *psm,
>> + uint16_t *version)
>> +{
>> + sdp_data_t *pdl, *p0, *p1;
>> +
>> + if (!psm && !version)
>> + return -1;
>> +
>> + pdl = sdp_data_get(rec, SDP_ATTR_PROTO_DESC_LIST);
>> + if (!pdl || !SDP_IS_SEQ(pdl->dtd))
>> + return -1;
>> +
>> + p0 = pdl->val.dataseq;
>> + if (get_prot_desc_entry(p0, L2CAP_UUID, psm) < 0)
>> + return -1;
>> +
>> + p1 = p0->next;
>> + if (get_prot_desc_entry(p1, MCAP_CTRL_UUID, version) < 0)
>> + return -1;
>> +
>> + return 0;
>> +}
>> +
>> +static int get_ccpsm(sdp_list_t *recs, uint16_t *ccpsm)
>> +{
>> + sdp_list_t *l;
>> +
>> + for (l = recs; l; l = l->next) {
>> + sdp_record_t *rec = l->data;
>> +
>> + if (!get_prot_desc_list(rec, ccpsm, NULL))
>> + return 0;
>> + }
>> +
>> + return -1;
>> +}
>> +
>> +static int get_add_prot_desc_list(const sdp_record_t *rec, uint16_t *psm)
>> +{
>> + sdp_data_t *pdl, *p0, *p1;
>> +
>> + if (!psm)
>> + return -1;
>> +
>> + pdl = sdp_data_get(rec, SDP_ATTR_ADD_PROTO_DESC_LIST);
>> + if (!pdl || pdl->dtd != SDP_SEQ8)
>> + return -1;
>> +
>> + pdl = pdl->val.dataseq;
>> + if (pdl->dtd != SDP_SEQ8)
>> + return -1;
>> +
>> + p0 = pdl->val.dataseq;
>> +
>> + if (get_prot_desc_entry(p0, L2CAP_UUID, psm) < 0)
>> + return -1;
>> +
>> + p1 = p0->next;
>> + if (get_prot_desc_entry(p1, MCAP_DATA_UUID, NULL) < 0)
>> + return -1;
>> +
>> + return 0;
>> +}
>> +
>> +static int get_dcpsm(sdp_list_t *recs, uint16_t *dcpsm)
>> +{
>> + sdp_list_t *l;
>> +
>> + for (l = recs; l; l = l->next) {
>> + sdp_record_t *rec = l->data;
>> +
>> + if (!get_add_prot_desc_list(rec, dcpsm))
>> + return 0;
>> + }
>> +
>> + return -1;
>> +}
>> +
>> +static void mcap_mdl_connected_cb(struct mcap_mdl *mdl, void *data)
>> +{
>> + DBG("Not Implemeneted");
>> +}
>> +
>> +static void mcap_mdl_closed_cb(struct mcap_mdl *mdl, void *data)
>> +{
>> + DBG("Not Implemeneted");
>> +}
>> +
>> +static void mcap_mdl_deleted_cb(struct mcap_mdl *mdl, void *data)
>> +{
>> + DBG("Not Implemeneted");
>> +}
>> +
>> +static void mcap_mdl_aborted_cb(struct mcap_mdl *mdl, void *data)
>> +{
>> + DBG("Not Implemeneted");
>> +}
>> +
>> +static void mcap_mdl_conn_req_cb(struct mcap_mcl *mcl, uint8_t mdepid,
>> + uint16_t mdlid, uint8_t *conf, void *data)
>> +{
>> + DBG("Not Implemeneted");
>> +}
>> +
>> +static void mcap_mdl_reconn_req_cb(struct mcap_mdl *mdl, void *data)
>> +{
>> + DBG("Not Implemeneted");
>> +}
>> +
>> +static void create_mcl_cb(struct mcap_mcl *mcl, GError *err, gpointer data)
>> +{
>> + struct health_channel *channel = data;
>> + gboolean ret;
>> + GError *gerr = NULL;
>> +
>> + DBG("");
>> +
>> + if (err) {
>> + error("error creating MCL : %s", err->message);
>> + goto fail;
>> + }
>> +
>> + if (!channel->dev->mcl)
>> + channel->dev->mcl = mcap_mcl_ref(mcl);
>> +
>> + channel->dev->mcl_conn = TRUE;
>> + DBG("MCL connected");
>> +
>> + ret = mcap_mcl_set_cb(channel->dev->mcl, channel, &gerr,
>> + MCAP_MDL_CB_CONNECTED, mcap_mdl_connected_cb,
>> + MCAP_MDL_CB_CLOSED, mcap_mdl_closed_cb,
>> + MCAP_MDL_CB_DELETED, mcap_mdl_deleted_cb,
>> + MCAP_MDL_CB_ABORTED, mcap_mdl_aborted_cb,
>> + MCAP_MDL_CB_REMOTE_CONN_REQ, mcap_mdl_conn_req_cb,
>> + MCAP_MDL_CB_REMOTE_RECONN_REQ, mcap_mdl_reconn_req_cb,
>> + MCAP_MDL_CB_INVALID);
>> + if (!ret) {
>> + error("error setting mdl callbacks on mcl");
>> + goto fail;
>> + }
>> +
>> + /* TODO : create mdl */
>> + return;
>> +
>> +fail:
>> + destroy_channel(channel);
>> +
>> + if (err)
>> + g_error_free(err);
>> +}
>> +
>> +static void search_cb(sdp_list_t *recs, int err, gpointer data)
>> +{
>> + struct health_channel *channel = data;
>> + GError *gerr = NULL;
>> +
>> + DBG("");
>> +
>> + if (err < 0 || !recs) {
>> + error("Error getting remote SDP records");
>> + goto fail;
>> + }
>> +
>> + if (get_ccpsm(recs, &channel->dev->ccpsm) < 0) {
>> + error("Can't get remote PSM for control channel");
>> + goto fail;
>> + }
>> +
>> + if (get_dcpsm(recs, &channel->dev->dcpsm) < 0) {
>> + error("Can't get remote PSM for data channel");
>> + goto fail;
>> + }
>> +
>> + if (!mcap_create_mcl(mcap, &channel->dev->dst, channel->dev->ccpsm,
>> + create_mcl_cb, channel, NULL, &gerr)) {
>> + error("error creating mcl %s", gerr->message);
>> + goto fail;
>> + }
>> +
>> + /* TODO: send channel state CONNECTING */
>> + return;
>> +
>> +fail:
>> + /* TODO: send channel state DESTROYED*/
>> +
>> + queue_remove(channel->dev->channels, channel);
>> + free_health_channel(channel);
>> +
>> + if (gerr)
>> + g_error_free(gerr);
>> +}
>> +
>> +static int connect_mcl(struct health_channel *channel)
>> +{
>> + uuid_t uuid;
>> +
>> + DBG("");
>> +
>> + bt_string2uuid(&uuid, HDP_UUID);
>> +
>> + return bt_search_service(&adapter_addr, &channel->dev->dst, &uuid,
>> + search_cb, channel, NULL, 0);
>> +}
>> +
>> +static struct health_device *create_device(
>> + const struct hal_cmd_health_connect_channel *cmd)
> I'd avoid passing hal structs to helpers and just pass bdaddr and app_id to
> this helper.
Ok.
>> +{
>> + struct health_device *dev;
>> +
>> + dev = new0(struct health_device, 1);
>> + if (!dev)
>> + return NULL;
>> +
>> + android2bdaddr(&cmd->bdaddr, &dev->dst);
>> + dev->app_id = cmd->app_id;
>> +
>> + return dev;
>> +}
>> +
>> +static struct health_channel *create_channel(uint8_t app_id, uint8_t
>> mdep_index) +{
>> + struct health_app *app;
>> + struct mdep_cfg *mdep;
>> + struct health_channel *channel;
>> + uint8_t index;
>> + static unsigned int channel_id = 1;
>> +
>> + app = queue_find(apps, app_by_app_id, INT_TO_PTR(app_id));
>> + if (!app)
>> + return NULL;
>> +
>> + index = mdep_index + 1;
>> + mdep = queue_find(app->mdeps, mdep_by_mdep_id, INT_TO_PTR(index));
>> + if (!mdep)
>> + return NULL;
>> +
>> + channel = new0(struct health_channel, 1);
>> + if (!channel)
>> + return NULL;
>> +
>> + channel->mdep_id = mdep_index;
>> + channel->type = mdep->channel_type;
>> + channel->id = channel_id++;
>> +
>> + return channel;
>> +}
>> +
>> static void bt_health_connect_channel(const void *buf, uint16_t len)
>> {
>> - DBG("Not implemented");
>> + const struct hal_cmd_health_connect_channel *cmd = buf;
>> + struct hal_rsp_health_connect_channel rsp;
>> + struct health_app *app;
>> + struct health_device *dev = NULL;
>> + struct health_channel *channel = NULL;
>> +
>> + DBG("");
>>
>> + app = queue_find(apps, app_by_app_id, INT_TO_PTR(cmd->app_id));
>> + if (!app)
>> + goto fail;
>> +
>> + dev = create_device(cmd);
>> + if (!dev)
>> + goto fail;
>> +
>> + channel = create_channel(cmd->app_id, cmd->mdep_index);
>> + if (!channel)
>> + goto fail;
>> +
>> + channel->dev = dev;
>> +
>> + if (!app->devices) {
>> + app->devices = queue_new();
>> + if (!app->devices)
>> + goto fail;
>> + }
>> +
>> + if (!queue_push_tail(app->devices, dev))
>> + goto fail;
>> +
>> + if (!dev->channels) {
>> + dev->channels = queue_new();
>> + if (!dev->channels)
>> + goto fail;
>> + }
>> +
>> + if (!queue_push_tail(dev->channels, channel)) {
>> + queue_remove(app->devices, dev);
>> + goto fail;
>> + }
>> +
>> + if (connect_mcl(channel) < 0) {
>> + error("error retrieving HDP SDP record");
>> + queue_remove(app->devices, dev);
>> + goto fail;
>> + }
>> +
>> + rsp.channel_id = channel->id;
>> + ipc_send_rsp_full(hal_ipc, HAL_SERVICE_ID_HEALTH,
>> + HAL_OP_HEALTH_CONNECT_CHANNEL,
>> + sizeof(rsp), &rsp, -1);
>> + return;
>> +
>> +fail:
>> + free_health_channel(channel);
>> + free_health_device(dev);
>> ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_HEALTH,
>> - HAL_OP_HEALTH_CONNECT_CHANNEL, HAL_STATUS_UNSUPPORTED);
>> + HAL_OP_HEALTH_CONNECT_CHANNEL, HAL_STATUS_FAILED);
>> }
>>
>> static void bt_health_destroy_channel(const void *buf, uint16_t len)
Thanks,
Ravi.

2014-06-16 20:56:09

by Ravi kumar Veeramally

[permalink] [raw]
Subject: Re: [PATCH 2/4] anrdoid/hal-health: Fix wrong channel type defines

Hi Szymon,

On 06/16/2014 11:16 PM, Szymon Janc wrote:
> Hi Ravi,
>
> On Monday 16 June 2014 20:51:12 Ravi kumar Veeramally wrote:
>> Enums in bt_hl.h are defined in this order BTHL_CHANNEL_TYPE_RELIABLE,
>> BTHL_CHANNEL_TYPE_STREAMING, BTHL_CHANNEL_TYPE_ANY. But HDP_SPEC_V11(3.4)
>> has no-preference(any)-0, reliable-1, stream-2, reserved(0x03-0xff).
>> ---
>> android/hal-health.c | 13 ++++++++++++-
>> android/hal-msg.h | 6 +++---
>> 2 files changed, 15 insertions(+), 4 deletions(-)
>>
>> diff --git a/android/hal-health.c b/android/hal-health.c
>> index ab06658..32c1b39 100644
>> --- a/android/hal-health.c
>> +++ b/android/hal-health.c
>> @@ -127,7 +127,18 @@ static bt_status_t
>> register_application(bthl_reg_param_t *reg, int *app_id) mdep->app_id =
>> rsp.app_id;
>> mdep->role = reg->mdep_cfg[i].mdep_role;
>> mdep->data_type = reg->mdep_cfg[i].data_type;
>> - mdep->channel_type = reg->mdep_cfg[i].channel_type;
>> +
>> + switch (reg->mdep_cfg[i].channel_type) {
>> + case BTHL_CHANNEL_TYPE_ANY:
>> + mdep->channel_type = HAL_HEALTH_CHANNEL_TYPE_ANY;
>> + break;
>> + case BTHL_CHANNEL_TYPE_RELIABLE:
>> + mdep->channel_type = HAL_HEALTH_CHANNEL_TYPE_RELIABLE;
>> + break;
>> + case BTHL_CHANNEL_TYPE_STREAMING:
>> + mdep->channel_type = HAL_HEALTH_CHANNEL_TYPE_STREAMING;
>> + break;
>> + }
>>
>> if (reg->mdep_cfg[i].mdep_description) {
>> mdep->descr_len =
>> diff --git a/android/hal-msg.h b/android/hal-msg.h
>> index 2c21a85..c95ac0f 100644
>> --- a/android/hal-msg.h
>> +++ b/android/hal-msg.h
>> @@ -388,9 +388,9 @@ struct hal_cmd_pan_disconnect {
>> #define HAL_HEALTH_MDEP_ROLE_SOURCE 0x00
>> #define HAL_HEALTH_MDEP_ROLE_SINK 0x01
>>
>> -#define HAL_HEALTH_CHANNEL_TYPE_RELIABLE 0x00
>> -#define HAL_HEALTH_CHANNEL_TYPE_STREAMING 0x01
>> -#define HAL_HEALTH_CHANNEL_TYPE_ANY 0x02
>> +#define HAL_HEALTH_CHANNEL_TYPE_ANY 0x00
>> +#define HAL_HEALTH_CHANNEL_TYPE_RELIABLE 0x01
>> +#define HAL_HEALTH_CHANNEL_TYPE_STREAMING 0x02
>>
>> #define HAL_OP_HEALTH_REG_APP 0x01
>> struct hal_cmd_health_reg_app {
>
> HAL library is suppose to be simple pipe as close to HAL API as possible. If
> such mapping is needed it should be done on daemon side in health.c.
> Possibly with helpers eg. android2channel_type().
>
Ok.

Regards,
Ravi.

2014-06-16 20:21:08

by Szymon Janc

[permalink] [raw]
Subject: Re: [PATCH 3/4] android/health: Initial connect channel implementation

Hi Ravi,

On Monday 16 June 2014 20:51:13 Ravi kumar Veeramally wrote:
> Fetches remote sdp record and initiates MCL connection.
> ---
> android/health.c | 416
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 414
> insertions(+), 2 deletions(-)
>
> diff --git a/android/health.c b/android/health.c
> index 7e2c5d6..07df2c4 100644
> --- a/android/health.c
> +++ b/android/health.c
> @@ -36,9 +36,13 @@
> #include "lib/bluetooth.h"
> #include "lib/sdp.h"
> #include "lib/sdp_lib.h"
> +#include "lib/uuid.h"
> +#include "lib/l2cap.h"
> #include "src/log.h"
> #include "src/shared/util.h"
> #include "src/shared/queue.h"
> +#include "src/uuid-helper.h"
> +#include "src/sdp-client.h"
>
> #include "hal-msg.h"
> #include "ipc-common.h"
> @@ -59,6 +63,17 @@ static struct mcap_instance *mcap = NULL;
> static uint32_t record_id = 0;
> static uint32_t record_state = 0;
>
> +struct health_device;
> +

Reorder structures definitions to avoid this.

> +struct health_channel {
> + uint8_t mdep_id;
> + uint8_t type;
> +
> + struct health_device *dev;
> +
> + uint16_t id; /* channel id */
> +};
> +
> struct mdep_cfg {
> uint8_t role;
> uint16_t data_type;
> @@ -68,6 +83,19 @@ struct mdep_cfg {
> uint8_t id; /* mdep id */
> };
>
> +struct health_device {
> + bdaddr_t dst;
> + uint16_t app_id;
> +
> + struct mcap_mcl *mcl;
> + bool mcl_conn;
> +
> + struct queue *channels; /* data channels */
> +
> + uint16_t ccpsm;
> + uint16_t dcpsm;
> +};
> +
> struct health_app {
> char *app_name;
> char *provider_name;
> @@ -77,8 +105,54 @@ struct health_app {
> struct queue *mdeps;
>
> uint16_t id; /* app id */
> + struct queue *devices;
> };
>
> +static void free_health_channel(void *data)
> +{
> + struct health_channel *channel = data;
> +
> + if (!channel)
> + return;
> +
> + free(channel);
> +}
> +
> +static void destroy_channel(void *data)
> +{
> + struct health_channel *channel = data;
> +
> + if (!channel)
> + return;
> +
> + /* TODO: Notify channel connection status DESTROYED */
> + queue_remove(channel->dev->channels, channel);
> + free_health_channel(channel);
> +}
> +
> +static void unref_mcl(struct health_device *dev)
> +{
> + if (!dev && !dev->mcl)
> + return;
> +
> + mcap_close_mcl(dev->mcl, FALSE);
> + mcap_mcl_unref(dev->mcl);
> + dev->mcl = NULL;
> + dev->mcl_conn = FALSE;
> +}
> +
> +static void free_health_device(void *data)
> +{
> + struct health_device *dev = data;
> +
> + if (!dev)
> + return;
> +
> + unref_mcl(dev);
> + queue_destroy(dev->channels, free_health_channel);
> + free(dev);
> +}
> +
> static void free_mdep_cfg(void *data)
> {
> struct mdep_cfg *cfg = data;
> @@ -102,6 +176,7 @@ static void free_health_app(void *data)
> free(app->service_name);
> free(app->service_descr);
> queue_destroy(app->mdeps, free_mdep_cfg);
> + queue_destroy(app->devices, free_health_device);
> free(app);
> }
>
> @@ -126,6 +201,14 @@ static bool mdep_by_mdep_role(const void *data, const
> void *user_data) return mdep->role == role;
> }
>
> +static bool mdep_by_mdep_id(const void *data, const void *user_data)
> +{
> + const struct mdep_cfg *mdep = data;
> + uint16_t mdep_id = PTR_TO_INT(user_data);
> +
> + return mdep->id == mdep_id;
> +}
> +
> static bool app_by_app_id(const void *data, const void *user_data)
> {
> const struct health_app *app = data;
> @@ -744,12 +827,341 @@ static void bt_health_unregister_app(const void *buf,
> uint16_t len) HAL_OP_HEALTH_UNREG_APP, HAL_STATUS_SUCCESS);
> }
>
> +static int get_prot_desc_entry(sdp_data_t *entry, int type, guint16 *val)
> +{
> + sdp_data_t *iter;
> + int proto;
> +
> + if (!entry || !SDP_IS_SEQ(entry->dtd))
> + return -1;
> +
> + iter = entry->val.dataseq;
> + if (!(iter->dtd & SDP_UUID_UNSPEC))
> + return -1;
> + proto = sdp_uuid_to_proto(&iter->val.uuid);
> + if (proto != type)
> + return -1;
> +
> + if (!val)
> + return 0;
> +
> + iter = iter->next;
> + if (iter->dtd != SDP_UINT16)
> + return -1;
> +
> + *val = iter->val.uint16;
> +
> + return 0;
> +}
> +
> +static int get_prot_desc_list(const sdp_record_t *rec, uint16_t *psm,
> + uint16_t *version)
> +{
> + sdp_data_t *pdl, *p0, *p1;
> +
> + if (!psm && !version)
> + return -1;
> +
> + pdl = sdp_data_get(rec, SDP_ATTR_PROTO_DESC_LIST);
> + if (!pdl || !SDP_IS_SEQ(pdl->dtd))
> + return -1;
> +
> + p0 = pdl->val.dataseq;
> + if (get_prot_desc_entry(p0, L2CAP_UUID, psm) < 0)
> + return -1;
> +
> + p1 = p0->next;
> + if (get_prot_desc_entry(p1, MCAP_CTRL_UUID, version) < 0)
> + return -1;
> +
> + return 0;
> +}
> +
> +static int get_ccpsm(sdp_list_t *recs, uint16_t *ccpsm)
> +{
> + sdp_list_t *l;
> +
> + for (l = recs; l; l = l->next) {
> + sdp_record_t *rec = l->data;
> +
> + if (!get_prot_desc_list(rec, ccpsm, NULL))
> + return 0;
> + }
> +
> + return -1;
> +}
> +
> +static int get_add_prot_desc_list(const sdp_record_t *rec, uint16_t *psm)
> +{
> + sdp_data_t *pdl, *p0, *p1;
> +
> + if (!psm)
> + return -1;
> +
> + pdl = sdp_data_get(rec, SDP_ATTR_ADD_PROTO_DESC_LIST);
> + if (!pdl || pdl->dtd != SDP_SEQ8)
> + return -1;
> +
> + pdl = pdl->val.dataseq;
> + if (pdl->dtd != SDP_SEQ8)
> + return -1;
> +
> + p0 = pdl->val.dataseq;
> +
> + if (get_prot_desc_entry(p0, L2CAP_UUID, psm) < 0)
> + return -1;
> +
> + p1 = p0->next;
> + if (get_prot_desc_entry(p1, MCAP_DATA_UUID, NULL) < 0)
> + return -1;
> +
> + return 0;
> +}
> +
> +static int get_dcpsm(sdp_list_t *recs, uint16_t *dcpsm)
> +{
> + sdp_list_t *l;
> +
> + for (l = recs; l; l = l->next) {
> + sdp_record_t *rec = l->data;
> +
> + if (!get_add_prot_desc_list(rec, dcpsm))
> + return 0;
> + }
> +
> + return -1;
> +}
> +
> +static void mcap_mdl_connected_cb(struct mcap_mdl *mdl, void *data)
> +{
> + DBG("Not Implemeneted");
> +}
> +
> +static void mcap_mdl_closed_cb(struct mcap_mdl *mdl, void *data)
> +{
> + DBG("Not Implemeneted");
> +}
> +
> +static void mcap_mdl_deleted_cb(struct mcap_mdl *mdl, void *data)
> +{
> + DBG("Not Implemeneted");
> +}
> +
> +static void mcap_mdl_aborted_cb(struct mcap_mdl *mdl, void *data)
> +{
> + DBG("Not Implemeneted");
> +}
> +
> +static void mcap_mdl_conn_req_cb(struct mcap_mcl *mcl, uint8_t mdepid,
> + uint16_t mdlid, uint8_t *conf, void *data)
> +{
> + DBG("Not Implemeneted");
> +}
> +
> +static void mcap_mdl_reconn_req_cb(struct mcap_mdl *mdl, void *data)
> +{
> + DBG("Not Implemeneted");
> +}
> +
> +static void create_mcl_cb(struct mcap_mcl *mcl, GError *err, gpointer data)
> +{
> + struct health_channel *channel = data;
> + gboolean ret;
> + GError *gerr = NULL;
> +
> + DBG("");
> +
> + if (err) {
> + error("error creating MCL : %s", err->message);
> + goto fail;
> + }
> +
> + if (!channel->dev->mcl)
> + channel->dev->mcl = mcap_mcl_ref(mcl);
> +
> + channel->dev->mcl_conn = TRUE;
> + DBG("MCL connected");
> +
> + ret = mcap_mcl_set_cb(channel->dev->mcl, channel, &gerr,
> + MCAP_MDL_CB_CONNECTED, mcap_mdl_connected_cb,
> + MCAP_MDL_CB_CLOSED, mcap_mdl_closed_cb,
> + MCAP_MDL_CB_DELETED, mcap_mdl_deleted_cb,
> + MCAP_MDL_CB_ABORTED, mcap_mdl_aborted_cb,
> + MCAP_MDL_CB_REMOTE_CONN_REQ, mcap_mdl_conn_req_cb,
> + MCAP_MDL_CB_REMOTE_RECONN_REQ, mcap_mdl_reconn_req_cb,
> + MCAP_MDL_CB_INVALID);
> + if (!ret) {
> + error("error setting mdl callbacks on mcl");
> + goto fail;
> + }
> +
> + /* TODO : create mdl */
> + return;
> +
> +fail:
> + destroy_channel(channel);
> +
> + if (err)
> + g_error_free(err);
> +}
> +
> +static void search_cb(sdp_list_t *recs, int err, gpointer data)
> +{
> + struct health_channel *channel = data;
> + GError *gerr = NULL;
> +
> + DBG("");
> +
> + if (err < 0 || !recs) {
> + error("Error getting remote SDP records");
> + goto fail;
> + }
> +
> + if (get_ccpsm(recs, &channel->dev->ccpsm) < 0) {
> + error("Can't get remote PSM for control channel");
> + goto fail;
> + }
> +
> + if (get_dcpsm(recs, &channel->dev->dcpsm) < 0) {
> + error("Can't get remote PSM for data channel");
> + goto fail;
> + }
> +
> + if (!mcap_create_mcl(mcap, &channel->dev->dst, channel->dev->ccpsm,
> + create_mcl_cb, channel, NULL, &gerr)) {
> + error("error creating mcl %s", gerr->message);
> + goto fail;
> + }
> +
> + /* TODO: send channel state CONNECTING */
> + return;
> +
> +fail:
> + /* TODO: send channel state DESTROYED*/
> +
> + queue_remove(channel->dev->channels, channel);
> + free_health_channel(channel);
> +
> + if (gerr)
> + g_error_free(gerr);
> +}
> +
> +static int connect_mcl(struct health_channel *channel)
> +{
> + uuid_t uuid;
> +
> + DBG("");
> +
> + bt_string2uuid(&uuid, HDP_UUID);
> +
> + return bt_search_service(&adapter_addr, &channel->dev->dst, &uuid,
> + search_cb, channel, NULL, 0);
> +}
> +
> +static struct health_device *create_device(
> + const struct hal_cmd_health_connect_channel *cmd)

I'd avoid passing hal structs to helpers and just pass bdaddr and app_id to
this helper.

> +{
> + struct health_device *dev;
> +
> + dev = new0(struct health_device, 1);
> + if (!dev)
> + return NULL;
> +
> + android2bdaddr(&cmd->bdaddr, &dev->dst);
> + dev->app_id = cmd->app_id;
> +
> + return dev;
> +}
> +
> +static struct health_channel *create_channel(uint8_t app_id, uint8_t
> mdep_index) +{
> + struct health_app *app;
> + struct mdep_cfg *mdep;
> + struct health_channel *channel;
> + uint8_t index;
> + static unsigned int channel_id = 1;
> +
> + app = queue_find(apps, app_by_app_id, INT_TO_PTR(app_id));
> + if (!app)
> + return NULL;
> +
> + index = mdep_index + 1;
> + mdep = queue_find(app->mdeps, mdep_by_mdep_id, INT_TO_PTR(index));
> + if (!mdep)
> + return NULL;
> +
> + channel = new0(struct health_channel, 1);
> + if (!channel)
> + return NULL;
> +
> + channel->mdep_id = mdep_index;
> + channel->type = mdep->channel_type;
> + channel->id = channel_id++;
> +
> + return channel;
> +}
> +
> static void bt_health_connect_channel(const void *buf, uint16_t len)
> {
> - DBG("Not implemented");
> + const struct hal_cmd_health_connect_channel *cmd = buf;
> + struct hal_rsp_health_connect_channel rsp;
> + struct health_app *app;
> + struct health_device *dev = NULL;
> + struct health_channel *channel = NULL;
> +
> + DBG("");
>
> + app = queue_find(apps, app_by_app_id, INT_TO_PTR(cmd->app_id));
> + if (!app)
> + goto fail;
> +
> + dev = create_device(cmd);
> + if (!dev)
> + goto fail;
> +
> + channel = create_channel(cmd->app_id, cmd->mdep_index);
> + if (!channel)
> + goto fail;
> +
> + channel->dev = dev;
> +
> + if (!app->devices) {
> + app->devices = queue_new();
> + if (!app->devices)
> + goto fail;
> + }
> +
> + if (!queue_push_tail(app->devices, dev))
> + goto fail;
> +
> + if (!dev->channels) {
> + dev->channels = queue_new();
> + if (!dev->channels)
> + goto fail;
> + }
> +
> + if (!queue_push_tail(dev->channels, channel)) {
> + queue_remove(app->devices, dev);
> + goto fail;
> + }
> +
> + if (connect_mcl(channel) < 0) {
> + error("error retrieving HDP SDP record");
> + queue_remove(app->devices, dev);
> + goto fail;
> + }
> +
> + rsp.channel_id = channel->id;
> + ipc_send_rsp_full(hal_ipc, HAL_SERVICE_ID_HEALTH,
> + HAL_OP_HEALTH_CONNECT_CHANNEL,
> + sizeof(rsp), &rsp, -1);
> + return;
> +
> +fail:
> + free_health_channel(channel);
> + free_health_device(dev);
> ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_HEALTH,
> - HAL_OP_HEALTH_CONNECT_CHANNEL, HAL_STATUS_UNSUPPORTED);
> + HAL_OP_HEALTH_CONNECT_CHANNEL, HAL_STATUS_FAILED);
> }
>
> static void bt_health_destroy_channel(const void *buf, uint16_t len)

--
Szymon K. Janc
[email protected]

2014-06-16 20:16:14

by Szymon Janc

[permalink] [raw]
Subject: Re: [PATCH 2/4] anrdoid/hal-health: Fix wrong channel type defines

Hi Ravi,

On Monday 16 June 2014 20:51:12 Ravi kumar Veeramally wrote:
> Enums in bt_hl.h are defined in this order BTHL_CHANNEL_TYPE_RELIABLE,
> BTHL_CHANNEL_TYPE_STREAMING, BTHL_CHANNEL_TYPE_ANY. But HDP_SPEC_V11(3.4)
> has no-preference(any)-0, reliable-1, stream-2, reserved(0x03-0xff).
> ---
> android/hal-health.c | 13 ++++++++++++-
> android/hal-msg.h | 6 +++---
> 2 files changed, 15 insertions(+), 4 deletions(-)
>
> diff --git a/android/hal-health.c b/android/hal-health.c
> index ab06658..32c1b39 100644
> --- a/android/hal-health.c
> +++ b/android/hal-health.c
> @@ -127,7 +127,18 @@ static bt_status_t
> register_application(bthl_reg_param_t *reg, int *app_id) mdep->app_id =
> rsp.app_id;
> mdep->role = reg->mdep_cfg[i].mdep_role;
> mdep->data_type = reg->mdep_cfg[i].data_type;
> - mdep->channel_type = reg->mdep_cfg[i].channel_type;
> +
> + switch (reg->mdep_cfg[i].channel_type) {
> + case BTHL_CHANNEL_TYPE_ANY:
> + mdep->channel_type = HAL_HEALTH_CHANNEL_TYPE_ANY;
> + break;
> + case BTHL_CHANNEL_TYPE_RELIABLE:
> + mdep->channel_type = HAL_HEALTH_CHANNEL_TYPE_RELIABLE;
> + break;
> + case BTHL_CHANNEL_TYPE_STREAMING:
> + mdep->channel_type = HAL_HEALTH_CHANNEL_TYPE_STREAMING;
> + break;
> + }
>
> if (reg->mdep_cfg[i].mdep_description) {
> mdep->descr_len =
> diff --git a/android/hal-msg.h b/android/hal-msg.h
> index 2c21a85..c95ac0f 100644
> --- a/android/hal-msg.h
> +++ b/android/hal-msg.h
> @@ -388,9 +388,9 @@ struct hal_cmd_pan_disconnect {
> #define HAL_HEALTH_MDEP_ROLE_SOURCE 0x00
> #define HAL_HEALTH_MDEP_ROLE_SINK 0x01
>
> -#define HAL_HEALTH_CHANNEL_TYPE_RELIABLE 0x00
> -#define HAL_HEALTH_CHANNEL_TYPE_STREAMING 0x01
> -#define HAL_HEALTH_CHANNEL_TYPE_ANY 0x02
> +#define HAL_HEALTH_CHANNEL_TYPE_ANY 0x00
> +#define HAL_HEALTH_CHANNEL_TYPE_RELIABLE 0x01
> +#define HAL_HEALTH_CHANNEL_TYPE_STREAMING 0x02
>
> #define HAL_OP_HEALTH_REG_APP 0x01
> struct hal_cmd_health_reg_app {


HAL library is suppose to be simple pipe as close to HAL API as possible. If
such mapping is needed it should be done on daemon side in health.c.
Possibly with helpers eg. android2channel_type().

--
Szymon K. Janc
[email protected]

2014-06-16 17:51:13

by Ravi kumar Veeramally

[permalink] [raw]
Subject: [PATCH 3/4] android/health: Initial connect channel implementation

Fetches remote sdp record and initiates MCL connection.
---
android/health.c | 416 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 414 insertions(+), 2 deletions(-)

diff --git a/android/health.c b/android/health.c
index 7e2c5d6..07df2c4 100644
--- a/android/health.c
+++ b/android/health.c
@@ -36,9 +36,13 @@
#include "lib/bluetooth.h"
#include "lib/sdp.h"
#include "lib/sdp_lib.h"
+#include "lib/uuid.h"
+#include "lib/l2cap.h"
#include "src/log.h"
#include "src/shared/util.h"
#include "src/shared/queue.h"
+#include "src/uuid-helper.h"
+#include "src/sdp-client.h"

#include "hal-msg.h"
#include "ipc-common.h"
@@ -59,6 +63,17 @@ static struct mcap_instance *mcap = NULL;
static uint32_t record_id = 0;
static uint32_t record_state = 0;

+struct health_device;
+
+struct health_channel {
+ uint8_t mdep_id;
+ uint8_t type;
+
+ struct health_device *dev;
+
+ uint16_t id; /* channel id */
+};
+
struct mdep_cfg {
uint8_t role;
uint16_t data_type;
@@ -68,6 +83,19 @@ struct mdep_cfg {
uint8_t id; /* mdep id */
};

+struct health_device {
+ bdaddr_t dst;
+ uint16_t app_id;
+
+ struct mcap_mcl *mcl;
+ bool mcl_conn;
+
+ struct queue *channels; /* data channels */
+
+ uint16_t ccpsm;
+ uint16_t dcpsm;
+};
+
struct health_app {
char *app_name;
char *provider_name;
@@ -77,8 +105,54 @@ struct health_app {
struct queue *mdeps;

uint16_t id; /* app id */
+ struct queue *devices;
};

+static void free_health_channel(void *data)
+{
+ struct health_channel *channel = data;
+
+ if (!channel)
+ return;
+
+ free(channel);
+}
+
+static void destroy_channel(void *data)
+{
+ struct health_channel *channel = data;
+
+ if (!channel)
+ return;
+
+ /* TODO: Notify channel connection status DESTROYED */
+ queue_remove(channel->dev->channels, channel);
+ free_health_channel(channel);
+}
+
+static void unref_mcl(struct health_device *dev)
+{
+ if (!dev && !dev->mcl)
+ return;
+
+ mcap_close_mcl(dev->mcl, FALSE);
+ mcap_mcl_unref(dev->mcl);
+ dev->mcl = NULL;
+ dev->mcl_conn = FALSE;
+}
+
+static void free_health_device(void *data)
+{
+ struct health_device *dev = data;
+
+ if (!dev)
+ return;
+
+ unref_mcl(dev);
+ queue_destroy(dev->channels, free_health_channel);
+ free(dev);
+}
+
static void free_mdep_cfg(void *data)
{
struct mdep_cfg *cfg = data;
@@ -102,6 +176,7 @@ static void free_health_app(void *data)
free(app->service_name);
free(app->service_descr);
queue_destroy(app->mdeps, free_mdep_cfg);
+ queue_destroy(app->devices, free_health_device);
free(app);
}

@@ -126,6 +201,14 @@ static bool mdep_by_mdep_role(const void *data, const void *user_data)
return mdep->role == role;
}

+static bool mdep_by_mdep_id(const void *data, const void *user_data)
+{
+ const struct mdep_cfg *mdep = data;
+ uint16_t mdep_id = PTR_TO_INT(user_data);
+
+ return mdep->id == mdep_id;
+}
+
static bool app_by_app_id(const void *data, const void *user_data)
{
const struct health_app *app = data;
@@ -744,12 +827,341 @@ static void bt_health_unregister_app(const void *buf, uint16_t len)
HAL_OP_HEALTH_UNREG_APP, HAL_STATUS_SUCCESS);
}

+static int get_prot_desc_entry(sdp_data_t *entry, int type, guint16 *val)
+{
+ sdp_data_t *iter;
+ int proto;
+
+ if (!entry || !SDP_IS_SEQ(entry->dtd))
+ return -1;
+
+ iter = entry->val.dataseq;
+ if (!(iter->dtd & SDP_UUID_UNSPEC))
+ return -1;
+ proto = sdp_uuid_to_proto(&iter->val.uuid);
+ if (proto != type)
+ return -1;
+
+ if (!val)
+ return 0;
+
+ iter = iter->next;
+ if (iter->dtd != SDP_UINT16)
+ return -1;
+
+ *val = iter->val.uint16;
+
+ return 0;
+}
+
+static int get_prot_desc_list(const sdp_record_t *rec, uint16_t *psm,
+ uint16_t *version)
+{
+ sdp_data_t *pdl, *p0, *p1;
+
+ if (!psm && !version)
+ return -1;
+
+ pdl = sdp_data_get(rec, SDP_ATTR_PROTO_DESC_LIST);
+ if (!pdl || !SDP_IS_SEQ(pdl->dtd))
+ return -1;
+
+ p0 = pdl->val.dataseq;
+ if (get_prot_desc_entry(p0, L2CAP_UUID, psm) < 0)
+ return -1;
+
+ p1 = p0->next;
+ if (get_prot_desc_entry(p1, MCAP_CTRL_UUID, version) < 0)
+ return -1;
+
+ return 0;
+}
+
+static int get_ccpsm(sdp_list_t *recs, uint16_t *ccpsm)
+{
+ sdp_list_t *l;
+
+ for (l = recs; l; l = l->next) {
+ sdp_record_t *rec = l->data;
+
+ if (!get_prot_desc_list(rec, ccpsm, NULL))
+ return 0;
+ }
+
+ return -1;
+}
+
+static int get_add_prot_desc_list(const sdp_record_t *rec, uint16_t *psm)
+{
+ sdp_data_t *pdl, *p0, *p1;
+
+ if (!psm)
+ return -1;
+
+ pdl = sdp_data_get(rec, SDP_ATTR_ADD_PROTO_DESC_LIST);
+ if (!pdl || pdl->dtd != SDP_SEQ8)
+ return -1;
+
+ pdl = pdl->val.dataseq;
+ if (pdl->dtd != SDP_SEQ8)
+ return -1;
+
+ p0 = pdl->val.dataseq;
+
+ if (get_prot_desc_entry(p0, L2CAP_UUID, psm) < 0)
+ return -1;
+
+ p1 = p0->next;
+ if (get_prot_desc_entry(p1, MCAP_DATA_UUID, NULL) < 0)
+ return -1;
+
+ return 0;
+}
+
+static int get_dcpsm(sdp_list_t *recs, uint16_t *dcpsm)
+{
+ sdp_list_t *l;
+
+ for (l = recs; l; l = l->next) {
+ sdp_record_t *rec = l->data;
+
+ if (!get_add_prot_desc_list(rec, dcpsm))
+ return 0;
+ }
+
+ return -1;
+}
+
+static void mcap_mdl_connected_cb(struct mcap_mdl *mdl, void *data)
+{
+ DBG("Not Implemeneted");
+}
+
+static void mcap_mdl_closed_cb(struct mcap_mdl *mdl, void *data)
+{
+ DBG("Not Implemeneted");
+}
+
+static void mcap_mdl_deleted_cb(struct mcap_mdl *mdl, void *data)
+{
+ DBG("Not Implemeneted");
+}
+
+static void mcap_mdl_aborted_cb(struct mcap_mdl *mdl, void *data)
+{
+ DBG("Not Implemeneted");
+}
+
+static void mcap_mdl_conn_req_cb(struct mcap_mcl *mcl, uint8_t mdepid,
+ uint16_t mdlid, uint8_t *conf, void *data)
+{
+ DBG("Not Implemeneted");
+}
+
+static void mcap_mdl_reconn_req_cb(struct mcap_mdl *mdl, void *data)
+{
+ DBG("Not Implemeneted");
+}
+
+static void create_mcl_cb(struct mcap_mcl *mcl, GError *err, gpointer data)
+{
+ struct health_channel *channel = data;
+ gboolean ret;
+ GError *gerr = NULL;
+
+ DBG("");
+
+ if (err) {
+ error("error creating MCL : %s", err->message);
+ goto fail;
+ }
+
+ if (!channel->dev->mcl)
+ channel->dev->mcl = mcap_mcl_ref(mcl);
+
+ channel->dev->mcl_conn = TRUE;
+ DBG("MCL connected");
+
+ ret = mcap_mcl_set_cb(channel->dev->mcl, channel, &gerr,
+ MCAP_MDL_CB_CONNECTED, mcap_mdl_connected_cb,
+ MCAP_MDL_CB_CLOSED, mcap_mdl_closed_cb,
+ MCAP_MDL_CB_DELETED, mcap_mdl_deleted_cb,
+ MCAP_MDL_CB_ABORTED, mcap_mdl_aborted_cb,
+ MCAP_MDL_CB_REMOTE_CONN_REQ, mcap_mdl_conn_req_cb,
+ MCAP_MDL_CB_REMOTE_RECONN_REQ, mcap_mdl_reconn_req_cb,
+ MCAP_MDL_CB_INVALID);
+ if (!ret) {
+ error("error setting mdl callbacks on mcl");
+ goto fail;
+ }
+
+ /* TODO : create mdl */
+ return;
+
+fail:
+ destroy_channel(channel);
+
+ if (err)
+ g_error_free(err);
+}
+
+static void search_cb(sdp_list_t *recs, int err, gpointer data)
+{
+ struct health_channel *channel = data;
+ GError *gerr = NULL;
+
+ DBG("");
+
+ if (err < 0 || !recs) {
+ error("Error getting remote SDP records");
+ goto fail;
+ }
+
+ if (get_ccpsm(recs, &channel->dev->ccpsm) < 0) {
+ error("Can't get remote PSM for control channel");
+ goto fail;
+ }
+
+ if (get_dcpsm(recs, &channel->dev->dcpsm) < 0) {
+ error("Can't get remote PSM for data channel");
+ goto fail;
+ }
+
+ if (!mcap_create_mcl(mcap, &channel->dev->dst, channel->dev->ccpsm,
+ create_mcl_cb, channel, NULL, &gerr)) {
+ error("error creating mcl %s", gerr->message);
+ goto fail;
+ }
+
+ /* TODO: send channel state CONNECTING */
+ return;
+
+fail:
+ /* TODO: send channel state DESTROYED*/
+
+ queue_remove(channel->dev->channels, channel);
+ free_health_channel(channel);
+
+ if (gerr)
+ g_error_free(gerr);
+}
+
+static int connect_mcl(struct health_channel *channel)
+{
+ uuid_t uuid;
+
+ DBG("");
+
+ bt_string2uuid(&uuid, HDP_UUID);
+
+ return bt_search_service(&adapter_addr, &channel->dev->dst, &uuid,
+ search_cb, channel, NULL, 0);
+}
+
+static struct health_device *create_device(
+ const struct hal_cmd_health_connect_channel *cmd)
+{
+ struct health_device *dev;
+
+ dev = new0(struct health_device, 1);
+ if (!dev)
+ return NULL;
+
+ android2bdaddr(&cmd->bdaddr, &dev->dst);
+ dev->app_id = cmd->app_id;
+
+ return dev;
+}
+
+static struct health_channel *create_channel(uint8_t app_id, uint8_t mdep_index)
+{
+ struct health_app *app;
+ struct mdep_cfg *mdep;
+ struct health_channel *channel;
+ uint8_t index;
+ static unsigned int channel_id = 1;
+
+ app = queue_find(apps, app_by_app_id, INT_TO_PTR(app_id));
+ if (!app)
+ return NULL;
+
+ index = mdep_index + 1;
+ mdep = queue_find(app->mdeps, mdep_by_mdep_id, INT_TO_PTR(index));
+ if (!mdep)
+ return NULL;
+
+ channel = new0(struct health_channel, 1);
+ if (!channel)
+ return NULL;
+
+ channel->mdep_id = mdep_index;
+ channel->type = mdep->channel_type;
+ channel->id = channel_id++;
+
+ return channel;
+}
+
static void bt_health_connect_channel(const void *buf, uint16_t len)
{
- DBG("Not implemented");
+ const struct hal_cmd_health_connect_channel *cmd = buf;
+ struct hal_rsp_health_connect_channel rsp;
+ struct health_app *app;
+ struct health_device *dev = NULL;
+ struct health_channel *channel = NULL;
+
+ DBG("");

+ app = queue_find(apps, app_by_app_id, INT_TO_PTR(cmd->app_id));
+ if (!app)
+ goto fail;
+
+ dev = create_device(cmd);
+ if (!dev)
+ goto fail;
+
+ channel = create_channel(cmd->app_id, cmd->mdep_index);
+ if (!channel)
+ goto fail;
+
+ channel->dev = dev;
+
+ if (!app->devices) {
+ app->devices = queue_new();
+ if (!app->devices)
+ goto fail;
+ }
+
+ if (!queue_push_tail(app->devices, dev))
+ goto fail;
+
+ if (!dev->channels) {
+ dev->channels = queue_new();
+ if (!dev->channels)
+ goto fail;
+ }
+
+ if (!queue_push_tail(dev->channels, channel)) {
+ queue_remove(app->devices, dev);
+ goto fail;
+ }
+
+ if (connect_mcl(channel) < 0) {
+ error("error retrieving HDP SDP record");
+ queue_remove(app->devices, dev);
+ goto fail;
+ }
+
+ rsp.channel_id = channel->id;
+ ipc_send_rsp_full(hal_ipc, HAL_SERVICE_ID_HEALTH,
+ HAL_OP_HEALTH_CONNECT_CHANNEL,
+ sizeof(rsp), &rsp, -1);
+ return;
+
+fail:
+ free_health_channel(channel);
+ free_health_device(dev);
ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_HEALTH,
- HAL_OP_HEALTH_CONNECT_CHANNEL, HAL_STATUS_UNSUPPORTED);
+ HAL_OP_HEALTH_CONNECT_CHANNEL, HAL_STATUS_FAILED);
}

static void bt_health_destroy_channel(const void *buf, uint16_t len)
--
1.9.1


2014-06-16 17:51:14

by Ravi kumar Veeramally

[permalink] [raw]
Subject: [PATCH 4/4] android/health: Notify channel connection status

---
android/health.c | 22 ++++++++++++++++++++--
1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/android/health.c b/android/health.c
index 07df2c4..038f21c 100644
--- a/android/health.c
+++ b/android/health.c
@@ -193,6 +193,24 @@ static void send_app_reg_notify(struct health_app *app, uint8_t state)
HAL_EV_HEALTH_APP_REG_STATE, sizeof(ev), &ev);
}

+static void send_channel_state_notify(struct health_channel *channel,
+ uint8_t state, int fd)
+{
+ struct hal_ev_health_channel_state ev;
+
+ DBG("");
+
+ bdaddr2android(&channel->dev->dst, ev.bdaddr);
+ ev.app_id = channel->dev->app_id;
+ ev.mdep_index = channel->mdep_id;
+ ev.channel_id = channel->id;
+ ev.channel_state = state;
+
+ ipc_send_notif_with_fd(hal_ipc, HAL_SERVICE_ID_HEALTH,
+ HAL_EV_HEALTH_CHANNEL_STATE,
+ sizeof(ev), &ev, fd);
+}
+
static bool mdep_by_mdep_role(const void *data, const void *user_data)
{
const struct mdep_cfg *mdep = data;
@@ -1033,11 +1051,11 @@ static void search_cb(sdp_list_t *recs, int err, gpointer data)
goto fail;
}

- /* TODO: send channel state CONNECTING */
+ send_channel_state_notify(channel, HAL_HEALTH_CHANNEL_CONNECTING, -1);
return;

fail:
- /* TODO: send channel state DESTROYED*/
+ send_channel_state_notify(channel, HAL_HEALTH_CHANNEL_DESTROYED, -1);

queue_remove(channel->dev->channels, channel);
free_health_channel(channel);
--
1.9.1


2014-06-16 17:51:12

by Ravi kumar Veeramally

[permalink] [raw]
Subject: [PATCH 2/4] anrdoid/hal-health: Fix wrong channel type defines

Enums in bt_hl.h are defined in this order BTHL_CHANNEL_TYPE_RELIABLE,
BTHL_CHANNEL_TYPE_STREAMING, BTHL_CHANNEL_TYPE_ANY. But HDP_SPEC_V11(3.4)
has no-preference(any)-0, reliable-1, stream-2, reserved(0x03-0xff).
---
android/hal-health.c | 13 ++++++++++++-
android/hal-msg.h | 6 +++---
2 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/android/hal-health.c b/android/hal-health.c
index ab06658..32c1b39 100644
--- a/android/hal-health.c
+++ b/android/hal-health.c
@@ -127,7 +127,18 @@ static bt_status_t register_application(bthl_reg_param_t *reg, int *app_id)
mdep->app_id = rsp.app_id;
mdep->role = reg->mdep_cfg[i].mdep_role;
mdep->data_type = reg->mdep_cfg[i].data_type;
- mdep->channel_type = reg->mdep_cfg[i].channel_type;
+
+ switch (reg->mdep_cfg[i].channel_type) {
+ case BTHL_CHANNEL_TYPE_ANY:
+ mdep->channel_type = HAL_HEALTH_CHANNEL_TYPE_ANY;
+ break;
+ case BTHL_CHANNEL_TYPE_RELIABLE:
+ mdep->channel_type = HAL_HEALTH_CHANNEL_TYPE_RELIABLE;
+ break;
+ case BTHL_CHANNEL_TYPE_STREAMING:
+ mdep->channel_type = HAL_HEALTH_CHANNEL_TYPE_STREAMING;
+ break;
+ }

if (reg->mdep_cfg[i].mdep_description) {
mdep->descr_len =
diff --git a/android/hal-msg.h b/android/hal-msg.h
index 2c21a85..c95ac0f 100644
--- a/android/hal-msg.h
+++ b/android/hal-msg.h
@@ -388,9 +388,9 @@ struct hal_cmd_pan_disconnect {
#define HAL_HEALTH_MDEP_ROLE_SOURCE 0x00
#define HAL_HEALTH_MDEP_ROLE_SINK 0x01

-#define HAL_HEALTH_CHANNEL_TYPE_RELIABLE 0x00
-#define HAL_HEALTH_CHANNEL_TYPE_STREAMING 0x01
-#define HAL_HEALTH_CHANNEL_TYPE_ANY 0x02
+#define HAL_HEALTH_CHANNEL_TYPE_ANY 0x00
+#define HAL_HEALTH_CHANNEL_TYPE_RELIABLE 0x01
+#define HAL_HEALTH_CHANNEL_TYPE_STREAMING 0x02

#define HAL_OP_HEALTH_REG_APP 0x01
struct hal_cmd_health_reg_app {
--
1.9.1


2014-06-16 17:51:11

by Ravi kumar Veeramally

[permalink] [raw]
Subject: [PATCH 1/4] profiles/health/hdp: Fix memory leak in SDP record preparati Sdp record preparation part is copied to android/health.c from profiles/health/hdp_utils.c. Memory leak is noticed while testing. Memory summay is from android daemon, but code snippet is same. It is already fixed in android/health.c while submitting android related patches.

==12515== 286 (16 direct, 270 indirect) bytes in 1 blocks are definitely lost in loss record 158 of 165
==12515== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==12515== by 0x44AC45: sdp_list_append (sdp.c:1743)
==12515== by 0x4398F9: register_features (health.c:381)
==12515== by 0x4091CC: queue_foreach (queue.c:219)
==12515== by 0x43A31F: bt_health_mdep_cfg_data (health.c:398)
==12515== by 0x418B50: cmd_watch_cb (ipc.c:144)
==12515== by 0x4E7FCE4: g_main_context_dispatch (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4000.0)
==12515== by 0x4E80047: ??? (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4000.0)
==12515== by 0x4E80309: g_main_loop_run (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4000.0)
==12515== by 0x4044F2: main (main.c:538)
---
profiles/health/hdp_util.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/profiles/health/hdp_util.c b/profiles/health/hdp_util.c
index 58770b5..47c464e 100644
--- a/profiles/health/hdp_util.c
+++ b/profiles/health/hdp_util.c
@@ -652,6 +652,8 @@ static gboolean register_service_sup_features(GSList *app_list,
return FALSE;
}

+ sdp_list_free(sup_features, free_hdp_list);
+
return TRUE;
}

--
1.9.1