2010-07-22 08:51:55

by Santiago Carot

[permalink] [raw]
Subject: MCAP Patches

Hello,

Next you are MCAP patches that José Antonio Santos Cadenas and me have generated for BlueZ.
We still believe that MCAP should be an independent library from HDP because other profiles
non health related may want to use it in the future, if we set this health dependency we will
force to import health features in plugins that only require MCAP.
Nevertheless, as we accorded last week in Brazil we are sending a last patch to set MCAP
into health directory with HDP. We leave in your hands upload it as health plugin or not.

Regards




2010-07-23 18:07:30

by Gustavo Padovan

[permalink] [raw]
Subject: Re: [PATCH 18/60] Implement function to send md_abort_mdl_req

Hi Santiago,

* Santiago Carot-Nemesio <[email protected]> [2010-07-23 11:24:57 +0200]:

> Hi,
> On 07/23/10 02:07, Gustavo F. Padovan wrote:
> > Hi Santiago,
> >
> > * Santiago Carot-Nemesio<[email protected]> [2010-07-22 10:52:13 +0200]:
> >
> >
> >> ---
> >> mcap/mcap.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
> >> 1 files changed, 48 insertions(+), 0 deletions(-)
> >>
> >> diff --git a/mcap/mcap.c b/mcap/mcap.c
> >> index 5419d54..6f6e08a 100644
> >> --- a/mcap/mcap.c
> >> +++ b/mcap/mcap.c
> >> @@ -519,6 +519,38 @@ void mcap_req_mdl_deletion(struct mcap_mdl *mdl, GError **err,
> >> g_free(con);
> >> }
> >>
> >> +void mcap_mdl_abort(struct mcap_mdl *mdl, GError **err,
> >> + mcap_mdl_del_cb abort_cb, gpointer user_data)
> >> +{
> >> + struct mcap_mdl_op_cb *con;
> >> + struct mcap_mcl *mcl = mdl->mcl;
> >> + uint8_t *cmd;
> >> +
> >> + if (mdl->state != MDL_WAITING) {
> >> + g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
> >> + "Mdl in invalid state");
> >> + return;
> >> + }
> >> +
> >> + con = g_new0(struct mcap_mdl_op_cb, 1);
> >> + cmd = create_req(MCAP_MD_ABORT_MDL_REQ, mdl->mdlid);
> >> + mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_req), err);
> >> + if (*err) {
> >> + g_free(con);
> >> + g_free(cmd);
> >> + return;
> >> + }
> >> +
> >> + con->mdl = mdl;
> >> + con->cb.del = abort_cb;
> >> + con->user_data = user_data;
> >> +
> >> + mcl->priv_data = con;
> >> +
> >> + mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
> >> + mcl);
> >> +}
> >> +
> >> static void update_mcl_state(struct mcap_mcl *mcl)
> >> {
> >> GSList *l;
> >> @@ -554,6 +586,22 @@ static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr)
> >> return NULL;
> >> }
> >>
> >> +int mcap_mdl_get_fd(struct mcap_mdl *mdl)
> >> +{
> >> + if ((!mdl) || (mdl->state != MDL_CONNECTED))
> >> + return -1;
> >>
> > A proper Unix error is better than -1 here.
> >
> Patch 58 fix that.

So merge 58 into this one.. ;)

--
Gustavo F. Padovan
http://padovan.org

2010-07-23 18:05:05

by Gustavo Padovan

[permalink] [raw]
Subject: Re: [PATCH 16/60] Implement function to send md_reconnect_mdl_req

Hi Santiago,

* Santiago Carot-Nemesio <[email protected]> [2010-07-23 19:17:41 +0200]:

> Hi,
> On 07/23/10 13:30, Elvis Pf?tzenreuter wrote:
> > On 23/07/2010, at 07:44, Jos? Antonio Santos Cadenas wrote:
> >
> >
> >> Hi,
> >>
> >> El Friday 23 July 2010 12:31:03 Luiz Augusto von Dentz escribi?:
> >>
> >>> Hi,
> >>>
> >>> On Fri, Jul 23, 2010 at 12:58 PM, Johan Hedberg<[email protected]>
> >>>
> >> wrote:
> >>
> >>>> The SDP code in libbluetooth is probably the absolute worst place to
> >>>> look for good examples. In this case the second variable in the function
> >>>> is completely unnecessary. Just assign the malloc return directly to the
> >>>> mcap_md_req pointer and get rid of the uint8_t* variable.
> >>>>
> >>>> Btw, I'd like to understand why we should use different acceptance
> >>>> criteria for your patches compared to everything else that gets
> >>>> submitted to BlueZ. The convention (which I'm sure you've noticed if you
> >>>> follow the list) is that when issues are found in submitted patches the
> >>>> submitter is requested to fix the issue in the patch and resubmit a new
> >>>> version of the patch. You're essentially requesting for buggy patches to
> >>>> be accepted as such and only fix the issues through new patches on top
> >>>> of the buggy ones.
> >>>>
> >>> I completely agree with this, one of the reason for this convention is
> >>> that we don't want this changes split apart because they probably
> >>> cannot be reverted individually. Another point is the history will be
> >>> completely disorganized if we start to accept those fixes separately,
> >>> it worth mention that this can eventually happen with patches already
> >>> upstream, but then it is normally a regression fix and as such we
> >>> normally mention the original commit which has caused it. I would
> >>> understand if we were in the old days of cvs, but with git it is
> >>> pretty simple to rearrange the changes, just use git rebase -i + git
> >>> reset or whatever other form to get this fixed in place.
> >>>
> >> We agree with you two. This is the complete development history that we have
> >> now. We sent it like this because we understood that keeping the history will
> >> be better. We don't care sending a different history with all the bug
> >> corrections amended.
> >>
> >> About the use of git rebase, it is not the first time that we do this and
> >> because of this we know that rebase some commits will make some of the
> >> following commits not compile. It will be a long and hard work to fix this, so
> >> it will be better and easier to create a new "virtual" history that splits the
> >> whole implementation in smaller patches.
> >>
> > In this line, it is better to put MCAP files inside health/ as Marcel asked.
> Don't worry. I will set MCAP into health directory. I don't try to
> explain anymore that MCAP is not only a health focused specification. It
> is like I want to make program that only requires TCP to work and you
> are forcing to me to import HTTP libraries, change HTTP by HDP and TCP
> by MCAP and you will get the analogy.
> I just hope that nobody get surprised if in the coming years are new
> non-health related profiles that require use MCAP and you need import
> Health to implement it.

If that happens we can move to new 'mcap' directory. For now only HDP
uses it, so makes sense keep iut inside health/

--
Gustavo F. Padovan
http://padovan.org

2010-07-23 18:01:15

by Gustavo Padovan

[permalink] [raw]
Subject: Re: [PATCH 16/60] Implement function to send md_reconnect_mdl_req

Hi Jos?,

* Jos? Antonio Santos Cadenas <[email protected]> [2010-07-23 12:44:42 +0200]:

> Hi,
>
> El Friday 23 July 2010 12:31:03 Luiz Augusto von Dentz escribi?:
> > Hi,
> >
> > On Fri, Jul 23, 2010 at 12:58 PM, Johan Hedberg <[email protected]>
> wrote:
> > > The SDP code in libbluetooth is probably the absolute worst place to
> > > look for good examples. In this case the second variable in the function
> > > is completely unnecessary. Just assign the malloc return directly to the
> > > mcap_md_req pointer and get rid of the uint8_t* variable.
> > >
> > > Btw, I'd like to understand why we should use different acceptance
> > > criteria for your patches compared to everything else that gets
> > > submitted to BlueZ. The convention (which I'm sure you've noticed if you
> > > follow the list) is that when issues are found in submitted patches the
> > > submitter is requested to fix the issue in the patch and resubmit a new
> > > version of the patch. You're essentially requesting for buggy patches to
> > > be accepted as such and only fix the issues through new patches on top
> > > of the buggy ones.
> >
> > I completely agree with this, one of the reason for this convention is
> > that we don't want this changes split apart because they probably
> > cannot be reverted individually. Another point is the history will be
> > completely disorganized if we start to accept those fixes separately,
> > it worth mention that this can eventually happen with patches already
> > upstream, but then it is normally a regression fix and as such we
> > normally mention the original commit which has caused it. I would
> > understand if we were in the old days of cvs, but with git it is
> > pretty simple to rearrange the changes, just use git rebase -i + git
> > reset or whatever other form to get this fixed in place.
>
> We agree with you two. This is the complete development history that we have
> now. We sent it like this because we understood that keeping the history will
> be better. We don't care sending a different history with all the bug
> corrections amended.

You can keep the history and at same time do all the fixes in the
patches and amend them. That's not too hard.

>
> About the use of git rebase, it is not the first time that we do this and
> because of this we know that rebase some commits will make some of the
> following commits not compile. It will be a long and hard work to fix this, so
> it will be better and easier to create a new "virtual" history that splits the
> whole implementation in smaller patches.


--
Gustavo F. Padovan
http://padovan.org

2010-07-23 17:17:41

by Santiago Carot-Nemesio

[permalink] [raw]
Subject: Re: [PATCH 16/60] Implement function to send md_reconnect_mdl_req

Hi,
On 07/23/10 13:30, Elvis Pf?tzenreuter wrote:
> On 23/07/2010, at 07:44, Jos? Antonio Santos Cadenas wrote:
>
>
>> Hi,
>>
>> El Friday 23 July 2010 12:31:03 Luiz Augusto von Dentz escribi?:
>>
>>> Hi,
>>>
>>> On Fri, Jul 23, 2010 at 12:58 PM, Johan Hedberg<[email protected]>
>>>
>> wrote:
>>
>>>> The SDP code in libbluetooth is probably the absolute worst place to
>>>> look for good examples. In this case the second variable in the function
>>>> is completely unnecessary. Just assign the malloc return directly to the
>>>> mcap_md_req pointer and get rid of the uint8_t* variable.
>>>>
>>>> Btw, I'd like to understand why we should use different acceptance
>>>> criteria for your patches compared to everything else that gets
>>>> submitted to BlueZ. The convention (which I'm sure you've noticed if you
>>>> follow the list) is that when issues are found in submitted patches the
>>>> submitter is requested to fix the issue in the patch and resubmit a new
>>>> version of the patch. You're essentially requesting for buggy patches to
>>>> be accepted as such and only fix the issues through new patches on top
>>>> of the buggy ones.
>>>>
>>> I completely agree with this, one of the reason for this convention is
>>> that we don't want this changes split apart because they probably
>>> cannot be reverted individually. Another point is the history will be
>>> completely disorganized if we start to accept those fixes separately,
>>> it worth mention that this can eventually happen with patches already
>>> upstream, but then it is normally a regression fix and as such we
>>> normally mention the original commit which has caused it. I would
>>> understand if we were in the old days of cvs, but with git it is
>>> pretty simple to rearrange the changes, just use git rebase -i + git
>>> reset or whatever other form to get this fixed in place.
>>>
>> We agree with you two. This is the complete development history that we have
>> now. We sent it like this because we understood that keeping the history will
>> be better. We don't care sending a different history with all the bug
>> corrections amended.
>>
>> About the use of git rebase, it is not the first time that we do this and
>> because of this we know that rebase some commits will make some of the
>> following commits not compile. It will be a long and hard work to fix this, so
>> it will be better and easier to create a new "virtual" history that splits the
>> whole implementation in smaller patches.
>>
> In this line, it is better to put MCAP files inside health/ as Marcel asked.
Don't worry. I will set MCAP into health directory. I don't try to
explain anymore that MCAP is not only a health focused specification. It
is like I want to make program that only requires TCP to work and you
are forcing to me to import HTTP libraries, change HTTP by HDP and TCP
by MCAP and you will get the analogy.
I just hope that nobody get surprised if in the coming years are new
non-health related profiles that require use MCAP and you need import
Health to implement it.

Regards.

2010-07-23 11:30:28

by Elvis Pfutzenreuter

[permalink] [raw]
Subject: Re: [PATCH 16/60] Implement function to send md_reconnect_mdl_req


On 23/07/2010, at 07:44, Jos? Antonio Santos Cadenas wrote:

> Hi,
>
> El Friday 23 July 2010 12:31:03 Luiz Augusto von Dentz escribi?:
>> Hi,
>>
>> On Fri, Jul 23, 2010 at 12:58 PM, Johan Hedberg <[email protected]>
> wrote:
>>> The SDP code in libbluetooth is probably the absolute worst place to
>>> look for good examples. In this case the second variable in the function
>>> is completely unnecessary. Just assign the malloc return directly to the
>>> mcap_md_req pointer and get rid of the uint8_t* variable.
>>>
>>> Btw, I'd like to understand why we should use different acceptance
>>> criteria for your patches compared to everything else that gets
>>> submitted to BlueZ. The convention (which I'm sure you've noticed if you
>>> follow the list) is that when issues are found in submitted patches the
>>> submitter is requested to fix the issue in the patch and resubmit a new
>>> version of the patch. You're essentially requesting for buggy patches to
>>> be accepted as such and only fix the issues through new patches on top
>>> of the buggy ones.
>>
>> I completely agree with this, one of the reason for this convention is
>> that we don't want this changes split apart because they probably
>> cannot be reverted individually. Another point is the history will be
>> completely disorganized if we start to accept those fixes separately,
>> it worth mention that this can eventually happen with patches already
>> upstream, but then it is normally a regression fix and as such we
>> normally mention the original commit which has caused it. I would
>> understand if we were in the old days of cvs, but with git it is
>> pretty simple to rearrange the changes, just use git rebase -i + git
>> reset or whatever other form to get this fixed in place.
>
> We agree with you two. This is the complete development history that we have
> now. We sent it like this because we understood that keeping the history will
> be better. We don't care sending a different history with all the bug
> corrections amended.
>
> About the use of git rebase, it is not the first time that we do this and
> because of this we know that rebase some commits will make some of the
> following commits not compile. It will be a long and hard work to fix this, so
> it will be better and easier to create a new "virtual" history that splits the
> whole implementation in smaller patches.

In this line, it is better to put MCAP files inside health/ as Marcel asked.

Subject: Re: [PATCH 16/60] Implement function to send md_reconnect_mdl_req

Hi,

El Friday 23 July 2010 12:31:03 Luiz Augusto von Dentz escribi?:
> Hi,
>
> On Fri, Jul 23, 2010 at 12:58 PM, Johan Hedberg <[email protected]>
wrote:
> > The SDP code in libbluetooth is probably the absolute worst place to
> > look for good examples. In this case the second variable in the function
> > is completely unnecessary. Just assign the malloc return directly to the
> > mcap_md_req pointer and get rid of the uint8_t* variable.
> >
> > Btw, I'd like to understand why we should use different acceptance
> > criteria for your patches compared to everything else that gets
> > submitted to BlueZ. The convention (which I'm sure you've noticed if you
> > follow the list) is that when issues are found in submitted patches the
> > submitter is requested to fix the issue in the patch and resubmit a new
> > version of the patch. You're essentially requesting for buggy patches to
> > be accepted as such and only fix the issues through new patches on top
> > of the buggy ones.
>
> I completely agree with this, one of the reason for this convention is
> that we don't want this changes split apart because they probably
> cannot be reverted individually. Another point is the history will be
> completely disorganized if we start to accept those fixes separately,
> it worth mention that this can eventually happen with patches already
> upstream, but then it is normally a regression fix and as such we
> normally mention the original commit which has caused it. I would
> understand if we were in the old days of cvs, but with git it is
> pretty simple to rearrange the changes, just use git rebase -i + git
> reset or whatever other form to get this fixed in place.

We agree with you two. This is the complete development history that we have
now. We sent it like this because we understood that keeping the history will
be better. We don't care sending a different history with all the bug
corrections amended.

About the use of git rebase, it is not the first time that we do this and
because of this we know that rebase some commits will make some of the
following commits not compile. It will be a long and hard work to fix this, so
it will be better and easier to create a new "virtual" history that splits the
whole implementation in smaller patches.

Regards.

Jose.

2010-07-23 10:31:03

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH 16/60] Implement function to send md_reconnect_mdl_req

Hi,

On Fri, Jul 23, 2010 at 12:58 PM, Johan Hedberg <[email protected]> wrote:
> The SDP code in libbluetooth is probably the absolute worst place to
> look for good examples. In this case the second variable in the function
> is completely unnecessary. Just assign the malloc return directly to the
> mcap_md_req pointer and get rid of the uint8_t* variable.
>
> Btw, I'd like to understand why we should use different acceptance
> criteria for your patches compared to everything else that gets
> submitted to BlueZ. The convention (which I'm sure you've noticed if you
> follow the list) is that when issues are found in submitted patches the
> submitter is requested to fix the issue in the patch and resubmit a new
> version of the patch. You're essentially requesting for buggy patches to
> be accepted as such and only fix the issues through new patches on top
> of the buggy ones.

I completely agree with this, one of the reason for this convention is
that we don't want this changes split apart because they probably
cannot be reverted individually. Another point is the history will be
completely disorganized if we start to accept those fixes separately,
it worth mention that this can eventually happen with patches already
upstream, but then it is normally a regression fix and as such we
normally mention the original commit which has caused it. I would
understand if we were in the old days of cvs, but with git it is
pretty simple to rearrange the changes, just use git rebase -i + git
reset or whatever other form to get this fixed in place.

--
Luiz Augusto von Dentz
Computer Engineer

2010-07-23 09:58:13

by Johan Hedberg

[permalink] [raw]
Subject: Re: [PATCH 16/60] Implement function to send md_reconnect_mdl_req

Hi,

On Fri, Jul 23, 2010, Santiago Carot-Nemesio wrote:
> >>+static uint8_t *create_req(uint8_t op, uint16_t mdl_id)
> >>+{
> >>+ uint8_t *req;
> >>+ mcap_md_req *req_cmd;
> >>+
> >>+ req = g_malloc0(sizeof(mcap_md_req));
> >>+
> >>+ req_cmd = (mcap_md_req *)req;
> >>+ req_cmd->op = op;
> >>+ req_cmd->mdl = htons(mdl_id);
> >>+
> >>+ return req;
> >>+}
> >Why are you casting here? I would expect mcap_md_req * as return type
> >here. If the problem is with mcap_send_std_opcode() you can used "void *" as
> >parameter type there.
> >
> I don't see why is better doing it as you say.
> In fact I did it to make the code similar to other bluez modules
> like sdp. You can see the sdp_send_req_w4_rsp and the sdp_send_req
> functions in sdp.c to find similarities with my code.

The SDP code in libbluetooth is probably the absolute worst place to
look for good examples. In this case the second variable in the function
is completely unnecessary. Just assign the malloc return directly to the
mcap_md_req pointer and get rid of the uint8_t* variable.

Btw, I'd like to understand why we should use different acceptance
criteria for your patches compared to everything else that gets
submitted to BlueZ. The convention (which I'm sure you've noticed if you
follow the list) is that when issues are found in submitted patches the
submitter is requested to fix the issue in the patch and resubmit a new
version of the patch. You're essentially requesting for buggy patches to
be accepted as such and only fix the issues through new patches on top
of the buggy ones.

Johan

2010-07-23 09:49:01

by Santiago Carot-Nemesio

[permalink] [raw]
Subject: Re: [PATCH 16/60] Implement function to send md_reconnect_mdl_req

On 07/23/10 01:47, Gustavo F. Padovan wrote:
> * Santiago Carot-Nemesio<[email protected]> [2010-07-22 10:52:11 +0200]:
>
>
>> ---
>> mcap/mcap.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
>> 1 files changed, 51 insertions(+), 0 deletions(-)
>>
>> diff --git a/mcap/mcap.c b/mcap/mcap.c
>> index dc55cda..a0f00af 100644
>> --- a/mcap/mcap.c
>> +++ b/mcap/mcap.c
>> @@ -261,6 +261,20 @@ static uint16_t generate_mdlid(struct mcap_mcl *mcl)
>> return mdlid;
>> }
>>
>> +static uint8_t *create_req(uint8_t op, uint16_t mdl_id)
>> +{
>> + uint8_t *req;
>> + mcap_md_req *req_cmd;
>> +
>> + req = g_malloc0(sizeof(mcap_md_req));
>> +
>> + req_cmd = (mcap_md_req *)req;
>> + req_cmd->op = op;
>> + req_cmd->mdl = htons(mdl_id);
>> +
>> + return req;
>> +}
>>
> Why are you casting here? I would expect mcap_md_req * as return type
> here. If the problem is with mcap_send_std_opcode() you can used "void *" as
> parameter type there.
>
>
I don't see why is better doing it as you say.
In fact I did it to make the code similar to other bluez modules like
sdp. You can see the sdp_send_req_w4_rsp and the sdp_send_req functions
in sdp.c to find similarities with my code.

>> +
>> static uint8_t *create_mdl_req(uint16_t mdl_id, uint8_t mdep, uint8_t conf)
>> {
>> uint8_t *req;
>> @@ -356,6 +370,43 @@ void mcap_req_mdl_creation(struct mcap_mcl *mcl,
>> mcl);
>> }
>>
>> +void mcap_req_mdl_reconnect(struct mcap_mdl *mdl,
>> + GError **err,
>> + mcap_mdl_operation_cb reconnect_cb,
>> + gpointer user_data)
>> +{
>> + struct mcap_mdl_op_cb *con;
>> + struct mcap_mcl *mcl = mdl->mcl;
>> + uint8_t *cmd;
>> +
>> + if (mdl->state != MDL_CLOSED) {
>> + g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
>> + "MDL is not closed");
>> + return;
>> + }
>> + con = g_new0(struct mcap_mdl_op_cb, 1);
>> +
>> + cmd = create_req(MCAP_MD_RECONNECT_MDL_REQ, mdl->mdlid);
>> + mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_req), err);
>> + if (*err) {
>> + g_free(con);
>> + g_free(cmd);
>> + return;
>> + }
>> +
>> + mdl->state = MDL_WAITING;
>> +
>> + con->mdl = mdl;
>> + con->cb.op = reconnect_cb;
>> + con->user_data = user_data;
>> +
>> + mcl->state = MCL_ACTIVE;
>> + mcl->priv_data = con;
>> +
>> + mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
>> + mcl);
>> +}
>> +
>> static void update_mcl_state(struct mcap_mcl *mcl)
>> {
>> GSList *l;
>>
>


2010-07-23 09:24:57

by Santiago Carot-Nemesio

[permalink] [raw]
Subject: Re: [PATCH 18/60] Implement function to send md_abort_mdl_req

Hi,
On 07/23/10 02:07, Gustavo F. Padovan wrote:
> Hi Santiago,
>
> * Santiago Carot-Nemesio<[email protected]> [2010-07-22 10:52:13 +0200]:
>
>
>> ---
>> mcap/mcap.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
>> 1 files changed, 48 insertions(+), 0 deletions(-)
>>
>> diff --git a/mcap/mcap.c b/mcap/mcap.c
>> index 5419d54..6f6e08a 100644
>> --- a/mcap/mcap.c
>> +++ b/mcap/mcap.c
>> @@ -519,6 +519,38 @@ void mcap_req_mdl_deletion(struct mcap_mdl *mdl, GError **err,
>> g_free(con);
>> }
>>
>> +void mcap_mdl_abort(struct mcap_mdl *mdl, GError **err,
>> + mcap_mdl_del_cb abort_cb, gpointer user_data)
>> +{
>> + struct mcap_mdl_op_cb *con;
>> + struct mcap_mcl *mcl = mdl->mcl;
>> + uint8_t *cmd;
>> +
>> + if (mdl->state != MDL_WAITING) {
>> + g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
>> + "Mdl in invalid state");
>> + return;
>> + }
>> +
>> + con = g_new0(struct mcap_mdl_op_cb, 1);
>> + cmd = create_req(MCAP_MD_ABORT_MDL_REQ, mdl->mdlid);
>> + mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_req), err);
>> + if (*err) {
>> + g_free(con);
>> + g_free(cmd);
>> + return;
>> + }
>> +
>> + con->mdl = mdl;
>> + con->cb.del = abort_cb;
>> + con->user_data = user_data;
>> +
>> + mcl->priv_data = con;
>> +
>> + mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
>> + mcl);
>> +}
>> +
>> static void update_mcl_state(struct mcap_mcl *mcl)
>> {
>> GSList *l;
>> @@ -554,6 +586,22 @@ static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr)
>> return NULL;
>> }
>>
>> +int mcap_mdl_get_fd(struct mcap_mdl *mdl)
>> +{
>> + if ((!mdl) || (mdl->state != MDL_CONNECTED))
>> + return -1;
>>
> A proper Unix error is better than -1 here.
>
Patch 58 fix that.
>
>> +
>> + return g_io_channel_unix_get_fd(mdl->dc);
>> +}
>> +
>> +uint16_t mcap_mdl_get_mdlid(struct mcap_mdl *mdl)
>> +{
>> + if (!mdl)
>> + return MCAP_MDLID_RESERVED;
>> +
>> + return mdl->mdlid;
>> +}
>> +
>> static void shutdown_mdl(struct mcap_mdl *mdl)
>> {
>> mdl->state = MDL_CLOSED;
>>
>


2010-07-23 09:23:46

by Santiago Carot-Nemesio

[permalink] [raw]
Subject: Re: [PATCH 12/60] Managing connection of Data Channels

Hi Gustavo,

On 07/23/10 01:54, Gustavo F. Padovan wrote:
> Hi Santiago,
>
> * Santiago Carot-Nemesio<[email protected]> [2010-07-22 10:52:07 +0200]:
>
>
>> ---
>> mcap/mcap.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>> 1 files changed, 70 insertions(+), 1 deletions(-)
>>
>> diff --git a/mcap/mcap.c b/mcap/mcap.c
>> index cf44472..1d86c51 100644
>> --- a/mcap/mcap.c
>> +++ b/mcap/mcap.c
>> @@ -754,6 +754,27 @@ static void proc_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
>> proc_req[mcl->state](mcl, cmd, len);
>> }
>>
>> +static gboolean mdl_event_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
>> +{
>> +
>> + struct mcap_mdl *mdl = data;
>> + gboolean notify;
>> +
>> + DBG("Close MDL %d", mdl->mdlid);
>> +
>> + notify = (mdl->state == MDL_CONNECTED);
>>
> You actually don't need 'notify', just put the comparison in the if
> below.
>
>

That is not true, you need to do it there because you need to know if
the MDL has been closed due a delete operation initiated by upper layer
(HDP) or it has been closed by remote side. In any case, MCAP need
shutdown the channel to set the MDL in a proper state before make any
callback. See coment below:
>> + shutdown_mdl(mdl);
>>

Above function sets the MDL state to closed, due that you can not check
the MDL state after shutdown it. I suggest to look that part of the code
to understand how data channel are managed by each MCL.
Note that mdl_event_cb is called from the watcher funtion set to the
bluetooth channel. When control flow reaches this part of the code the
MDL state can be connected or deleted. How can you know the MDL state
after doing a shutdown over the data channel?, remember that MCAP does
not know what will happen into the upper layer callback, due that, it
need set the MDL in a proper state by shutting down it before make the
callback.

>> +
>> + update_mcl_state(mdl->mcl);
>> +
>> + if (notify) {
>> + /*Callback to upper layer */
>> + mdl->mcl->cb->mdl_closed(mdl, mdl->mcl->cb->user_data);
>> + }
>> +
>> + return FALSE;
>> +}
>> +
>> static gboolean mcl_control_cb(GIOChannel *chan, GIOCondition cond,
>> gpointer data)
>> {
>> @@ -779,9 +800,57 @@ fail:
>> return FALSE;
>> }
>>
>> +static void connect_dc_event_cb(GIOChannel *chan, GError *err,
>> + gpointer user_data)
>> +{
>> + struct mcap_mdl *mdl = user_data;
>> + struct mcap_mcl *mcl = mdl->mcl;
>> +
>> + mdl->state = MDL_CONNECTED;
>> + mdl->dc = g_io_channel_ref(chan);
>> + mdl->wid = g_io_add_watch(mdl->dc, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
>> + (GIOFunc) mdl_event_cb, mdl);
>> +
>> + mcl->state = MCL_ACTIVE;
>> + mcl->cb->mdl_connected(mdl, mcl->cb->user_data);
>> +}
>> +
>> static void confirm_dc_event_cb(GIOChannel *chan, gpointer user_data)
>> {
>> - /* TODO */
>> + struct mcap_instance *ms = user_data;
>> + struct mcap_mcl *mcl;
>> + struct mcap_mdl *mdl;
>> + GError *err = NULL;
>> + bdaddr_t dst;
>> + GSList *l;
>> +
>> + bt_io_get(chan, BT_IO_L2CAP,&err,
>> + BT_IO_OPT_DEST_BDADDR,&dst,
>> + BT_IO_OPT_INVALID);
>> + if (err) {
>> + error("%s", err->message);
>> + g_error_free(err);
>> + goto drop;
>> + }
>> +
>> + mcl = find_mcl(ms->mcls,&dst);
>> + if (!mcl || (mcl->state != MCL_PENDING))
>>
> No need for () in the '!=' comparison.
>
>
>> + goto drop;
>> +
>> + for (l = mcl->mdls; l; l = l->next) {
>> + mdl = l->data;
>> + if (mdl->state == MDL_WAITING) {
>> + if (!bt_io_accept(chan, connect_dc_event_cb, mdl, NULL,
>> + &err)) {
>> + error("MDL accept error %s", err->message);
>> + g_error_free(err);
>> + goto drop;
>> + }
>> + return;
>> + }
>> + }
>> +drop:
>> + g_io_channel_shutdown(chan, TRUE, NULL);
>> }
>>
>> static void connect_mcl_event_cb(GIOChannel *chan, GError *err,
>>
>


Subject: Re: MCAP Patches

Hi,

El Friday 23 July 2010 01:36:06 Gustavo F. Padovan escribi?:
> Hi Santiago,
>
> * Santiago Carot-Nemesio <[email protected]> [2010-07-22 10:51:55 +0200]:
> > Hello,
> >
> > Next you are MCAP patches that Jos? Antonio Santos Cadenas and me have
> > generated for BlueZ. We still believe that MCAP should be an independent
> > library from HDP because other profiles non health related may want to
> > use it in the future, if we set this health dependency we will force to
> > import health features in plugins that only require MCAP. Nevertheless,
> > as we accorded last week in Brazil we are sending a last patch to set
> > MCAP into health directory with HDP. We leave in your hands upload it as
> > health plugin or not.
>
> Please provide a git tree link for theses patches too. Thanks.

You have a copy of this changes in the follow git at branch mcap.

git://gitorious.org/bluez-mcap-hdp/mcap-hdp.git

Regards.

2010-07-23 08:00:00

by Santiago Carot-Nemesio

[permalink] [raw]
Subject: Re: [PATCH 10/60] Process md_abort_mdl_req in PENDING state

Hi Gustavo,

On 07/23/10 01:50, Gustavo F. Padovan wrote:
> Hi Santiago,
>
> * Santiago Carot-Nemesio<[email protected]> [2010-07-22 10:52:05 +0200]:
>
>
>> ---
>> mcap/mcap.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++++-
>> 1 files changed, 49 insertions(+), 1 deletions(-)
>>
>> diff --git a/mcap/mcap.c b/mcap/mcap.c
>> index d6a9760..9f41c6b 100644
>> --- a/mcap/mcap.c
>> +++ b/mcap/mcap.c
>> @@ -551,6 +551,51 @@ static void process_md_reconnect_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
>> send4B_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_SUCCESS, mdl_id);
>> }
>>
>> +static void process_md_abort_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
>> + uint32_t len)
>> +{
>> + mcap_md_req *req;
>> + GSList *l;
>> + struct mcap_mdl *mdl, *del;
>> + uint16_t mdl_id;
>> +
>> + if (len != sizeof(mcap_md_req)) {
>> + send4B_cmd(mcl, MCAP_MD_ABORT_MDL_RSP,
>> + MCAP_INVALID_PARAM_VALUE, MCAP_MDLID_RESERVED);
>>
> I remenber about a Johan's comment on send4B_cmd(). It was basically,
> wouldn't be better have function to send data of a arbritrary size. I
> think I saw a send5B_cmd() in these patches as well.
>

Yes, patch 56 Fix that.
That is a big change in MCAP core to be amended in previous patches and
to expect that intermediate patches still compile.
In fact, it may be a stupid waste of time try to do that to hide MCAP
developing history. I'm not sure if that it is a good idea and as far I
remember we accorded to keep MCAP history in last meeting.

>
>> + return;
>> + }
>> +
>> + req = (mcap_md_req *)cmd;
>> + mdl_id = ntohs(req->mdl);
>> + mcl->state = MCL_CONNECTED;
>> + for (l = mcl->mdls; l; l = l->next) {
>> + mdl = l->data;
>> + if ((mdl_id == mdl->mdlid)&& (mdl->state == MDL_WAITING)) {
>> + del = mdl;
>> + if (mcl->state != MCL_CONNECTED)
>> + break;
>> + continue;
>> + }
>> + if ((mdl->state == MDL_CONNECTED)&& (mcl->state != MCL_ACTIVE))
>> + mcl->state = MCL_ACTIVE;
>> +
>> + if ((del)&& (mcl->state == MCL_ACTIVE))
>> + break;
>> + }
>> +
>> + if (!del) {
>> + send4B_cmd(mcl, MCAP_MD_ABORT_MDL_RSP, MCAP_INVALID_MDL,
>> + mdl_id);
>> + return;
>> + }
>> +
>> + mcl->cb->mdl_aborted(del, mcl->cb->user_data);
>> +
>> + mcl->mdls = g_slist_remove(mcl->mdls, del);
>> + g_free(del);
>> + send4B_cmd(mcl, MCAP_MD_ABORT_MDL_RSP, MCAP_SUCCESS, mdl_id);
>> +}
>> +
>> static void process_md_delete_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
>> uint32_t len)
>> {
>> @@ -626,7 +671,10 @@ static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
>>
>> static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
>> {
>> - /* TODO */
>> + if (cmd[0] == MCAP_MD_ABORT_MDL_REQ)
>> + process_md_abort_mdl_req(mcl, cmd, len);
>> + else
>> + error_cmd_rsp(mcl, cmd, len);
>> }
>>
>> static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
>>
>


2010-07-23 00:09:44

by Gustavo Padovan

[permalink] [raw]
Subject: Re: [PATCH 19/60] Process response to std. op. codes

Hi Jose,

* Jose Antonio Santos Cadenas <[email protected]> [2010-07-22 10:56:12 +0200]:

> From: Jos? Antonio Santos-Cadenas <[email protected]>
>
> ---
> mcap/mcap.c | 141 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
> 1 files changed, 140 insertions(+), 1 deletions(-)
>
> diff --git a/mcap/mcap.c b/mcap/mcap.c
> index 6f6e08a..c775501 100644
> --- a/mcap/mcap.c
> +++ b/mcap/mcap.c
> @@ -1170,9 +1170,112 @@ static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
> }
> }
>
> +static gboolean process_md_create_mdl_rsp(struct mcap_mcl *mcl,
> + uint8_t *cmd, uint32_t len)
> +{
> + return FALSE;
> +}
> +
> +static gboolean process_md_reconnect_mdl_rsp(struct mcap_mcl *mcl,
> + uint8_t *cmd, uint32_t len)
> +{
> + return FALSE;
> +}
> +
> +static gboolean process_md_abort_mdl_rsp(struct mcap_mcl *mcl,
> + uint8_t *cmd, uint32_t len)
> +{
> + return FALSE;
> +}
> +
> +static gboolean process_md_delete_mdl_rsp(struct mcap_mcl *mcl, uint8_t *cmd,
> + uint32_t len)
> +{
> + return FALSE;
> +}
> +
> +static gboolean check_rsp(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
> +{
> + mcap4B_rsp *rsp;
> + GError *gerr = NULL;
> +
> + /* Check if the response matches with the last request */
> + if ((cmd[0] != MCAP_ERROR_RSP) && ((mcl->lcmd[0] + 1) != cmd[0]))
> + goto close_mcl;
> +
> + if (len < 4)
> + goto close_mcl;
> +
> + rsp = (mcap4B_rsp *)cmd;
> +
> + if (rsp->rc == MCAP_REQUEST_NOT_SUPPORTED) {
> + DBG("Remote does not support opcodes");
> + g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_REQUEST_NOT_SUPPORTED,
> + "%s", error2str(rsp->rc));
> + mcap_notify_error(mcl, gerr);
> + g_error_free(gerr);
> +
> + g_free(mcl->lcmd);
> + mcl->lcmd = NULL;
> + mcl->ctrl &= ~MCAP_CTRL_STD_OP;
> + mcl->req = MCL_AVAILABLE;
> + update_mcl_state(mcl);
> + return FALSE;
> + }
> +
> + if (rsp->rc == MCAP_UNSPECIFIED_ERROR)
> + goto close_mcl;
> +
> + return TRUE;
> +close_mcl:

Always put a blank line before labels.

> + if (rsp->rc == MCAP_UNSPECIFIED_ERROR)
> + g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_UNSPECIFIED_ERROR,
> + "%s", error2str(rsp->rc));
> + else
> + g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_FAILED,
> + "Protocol error");
> + mcap_notify_error(mcl, gerr);
> + g_error_free(gerr);
> + mcl->ms->mcl_disconnected_cb(mcl, mcl->ms->user_data);
> + mcap_cache_mcl(mcl);
> + return FALSE;
> +}
> +
> static void proc_response(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
> {
> - /* TODO */
> + gboolean close;
> + RELEASE_TIMER(mcl);
> +
> + if (!check_rsp(mcl, cmd, len))
> + return;
> +
> + switch (cmd[0]) {
> + case MCAP_ERROR_RSP:
> + error("MCAP_ERROR_RSP received");
> + close = TRUE;
> + break;
> + case MCAP_MD_CREATE_MDL_RSP:
> + close = process_md_create_mdl_rsp(mcl, cmd, len);
> + break;
> + case MCAP_MD_RECONNECT_MDL_RSP:
> + close = process_md_reconnect_mdl_rsp(mcl, cmd, len);
> + break;
> + case MCAP_MD_ABORT_MDL_RSP:
> + close = process_md_abort_mdl_rsp(mcl, cmd, len);
> + break;
> + case MCAP_MD_DELETE_MDL_RSP:
> + close = process_md_delete_mdl_rsp(mcl, cmd, len);
> + break;
> + default:
> + DBG("Unknown cmd response received (op code = %d)",cmd[0]);
> + close = TRUE;
> + break;
> + }
> +
> + if (close) {
> + mcl->ms->mcl_disconnected_cb(mcl, mcl->ms->user_data);
> + mcap_cache_mcl(mcl);
> + }
> }
>
> static void rsend_req(struct mcap_mcl *mcl)
> @@ -1631,3 +1734,39 @@ void mcap_release_instance(struct mcap_instance *ms)
>
> g_free(ms);
> }
> +
> +uint16_t mcap_get_ctrl_psm(struct mcap_instance *ms, GError **err)
> +{
> + uint16_t lpsm;
> +
> + if (!(ms && ms->ccio)) {
> + g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS,
> + "Invalid MCAP instance");
> + return 0;
> + }
> +
> + bt_io_get(ms->ccio, BT_IO_L2CAP, err,
> + BT_IO_OPT_PSM, &lpsm,
> + BT_IO_OPT_INVALID);
> + if (*err)
> + return 0;
> + return lpsm;
> +}
> +
> +uint16_t mcap_get_data_psm(struct mcap_instance *ms, GError **err)
> +{
> + uint16_t lpsm;
> +
> + if (!(ms && ms->dcio)) {
> + g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS,
> + "Invalid MCAP instance");
> + return 0;
> + }
> +
> + bt_io_get(ms->dcio, BT_IO_L2CAP, err,
> + BT_IO_OPT_PSM, &lpsm,
> + BT_IO_OPT_INVALID);
> + if (*err)
> + return 0;
> + return lpsm;
> +}
> --
> 1.6.3.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html

--
Gustavo F. Padovan
http://padovan.org

2010-07-23 00:07:09

by Gustavo Padovan

[permalink] [raw]
Subject: Re: [PATCH 18/60] Implement function to send md_abort_mdl_req

Hi Santiago,

* Santiago Carot-Nemesio <[email protected]> [2010-07-22 10:52:13 +0200]:

> ---
> mcap/mcap.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
> 1 files changed, 48 insertions(+), 0 deletions(-)
>
> diff --git a/mcap/mcap.c b/mcap/mcap.c
> index 5419d54..6f6e08a 100644
> --- a/mcap/mcap.c
> +++ b/mcap/mcap.c
> @@ -519,6 +519,38 @@ void mcap_req_mdl_deletion(struct mcap_mdl *mdl, GError **err,
> g_free(con);
> }
>
> +void mcap_mdl_abort(struct mcap_mdl *mdl, GError **err,
> + mcap_mdl_del_cb abort_cb, gpointer user_data)
> +{
> + struct mcap_mdl_op_cb *con;
> + struct mcap_mcl *mcl = mdl->mcl;
> + uint8_t *cmd;
> +
> + if (mdl->state != MDL_WAITING) {
> + g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
> + "Mdl in invalid state");
> + return;
> + }
> +
> + con = g_new0(struct mcap_mdl_op_cb, 1);
> + cmd = create_req(MCAP_MD_ABORT_MDL_REQ, mdl->mdlid);
> + mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_req), err);
> + if (*err) {
> + g_free(con);
> + g_free(cmd);
> + return;
> + }
> +
> + con->mdl = mdl;
> + con->cb.del = abort_cb;
> + con->user_data = user_data;
> +
> + mcl->priv_data = con;
> +
> + mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
> + mcl);
> +}
> +
> static void update_mcl_state(struct mcap_mcl *mcl)
> {
> GSList *l;
> @@ -554,6 +586,22 @@ static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr)
> return NULL;
> }
>
> +int mcap_mdl_get_fd(struct mcap_mdl *mdl)
> +{
> + if ((!mdl) || (mdl->state != MDL_CONNECTED))
> + return -1;

A proper Unix error is better than -1 here.

> +
> + return g_io_channel_unix_get_fd(mdl->dc);
> +}
> +
> +uint16_t mcap_mdl_get_mdlid(struct mcap_mdl *mdl)
> +{
> + if (!mdl)
> + return MCAP_MDLID_RESERVED;
> +
> + return mdl->mdlid;
> +}
> +
> static void shutdown_mdl(struct mcap_mdl *mdl)
> {
> mdl->state = MDL_CLOSED;

--
Gustavo F. Padovan
http://padovan.org

2010-07-22 23:54:52

by Gustavo Padovan

[permalink] [raw]
Subject: Re: [PATCH 12/60] Managing connection of Data Channels

Hi Santiago,

* Santiago Carot-Nemesio <[email protected]> [2010-07-22 10:52:07 +0200]:

> ---
> mcap/mcap.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
> 1 files changed, 70 insertions(+), 1 deletions(-)
>
> diff --git a/mcap/mcap.c b/mcap/mcap.c
> index cf44472..1d86c51 100644
> --- a/mcap/mcap.c
> +++ b/mcap/mcap.c
> @@ -754,6 +754,27 @@ static void proc_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
> proc_req[mcl->state](mcl, cmd, len);
> }
>
> +static gboolean mdl_event_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
> +{
> +
> + struct mcap_mdl *mdl = data;
> + gboolean notify;
> +
> + DBG("Close MDL %d", mdl->mdlid);
> +
> + notify = (mdl->state == MDL_CONNECTED);

You actually don't need 'notify', just put the comparison in the if
below.

> + shutdown_mdl(mdl);
> +
> + update_mcl_state(mdl->mcl);
> +
> + if (notify) {
> + /*Callback to upper layer */
> + mdl->mcl->cb->mdl_closed(mdl, mdl->mcl->cb->user_data);
> + }
> +
> + return FALSE;
> +}
> +
> static gboolean mcl_control_cb(GIOChannel *chan, GIOCondition cond,
> gpointer data)
> {
> @@ -779,9 +800,57 @@ fail:
> return FALSE;
> }
>
> +static void connect_dc_event_cb(GIOChannel *chan, GError *err,
> + gpointer user_data)
> +{
> + struct mcap_mdl *mdl = user_data;
> + struct mcap_mcl *mcl = mdl->mcl;
> +
> + mdl->state = MDL_CONNECTED;
> + mdl->dc = g_io_channel_ref(chan);
> + mdl->wid = g_io_add_watch(mdl->dc, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
> + (GIOFunc) mdl_event_cb, mdl);
> +
> + mcl->state = MCL_ACTIVE;
> + mcl->cb->mdl_connected(mdl, mcl->cb->user_data);
> +}
> +
> static void confirm_dc_event_cb(GIOChannel *chan, gpointer user_data)
> {
> - /* TODO */
> + struct mcap_instance *ms = user_data;
> + struct mcap_mcl *mcl;
> + struct mcap_mdl *mdl;
> + GError *err = NULL;
> + bdaddr_t dst;
> + GSList *l;
> +
> + bt_io_get(chan, BT_IO_L2CAP, &err,
> + BT_IO_OPT_DEST_BDADDR, &dst,
> + BT_IO_OPT_INVALID);
> + if (err) {
> + error("%s", err->message);
> + g_error_free(err);
> + goto drop;
> + }
> +
> + mcl = find_mcl(ms->mcls, &dst);
> + if (!mcl || (mcl->state != MCL_PENDING))

No need for () in the '!=' comparison.

> + goto drop;
> +
> + for (l = mcl->mdls; l; l = l->next) {
> + mdl = l->data;
> + if (mdl->state == MDL_WAITING) {
> + if (!bt_io_accept(chan, connect_dc_event_cb, mdl, NULL,
> + &err)) {
> + error("MDL accept error %s", err->message);
> + g_error_free(err);
> + goto drop;
> + }
> + return;
> + }
> + }
> +drop:
> + g_io_channel_shutdown(chan, TRUE, NULL);
> }
>
> static void connect_mcl_event_cb(GIOChannel *chan, GError *err,

--
Gustavo F. Padovan
http://padovan.org

2010-07-22 23:50:21

by Gustavo Padovan

[permalink] [raw]
Subject: Re: [PATCH 10/60] Process md_abort_mdl_req in PENDING state

Hi Santiago,

* Santiago Carot-Nemesio <[email protected]> [2010-07-22 10:52:05 +0200]:

> ---
> mcap/mcap.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++++-
> 1 files changed, 49 insertions(+), 1 deletions(-)
>
> diff --git a/mcap/mcap.c b/mcap/mcap.c
> index d6a9760..9f41c6b 100644
> --- a/mcap/mcap.c
> +++ b/mcap/mcap.c
> @@ -551,6 +551,51 @@ static void process_md_reconnect_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
> send4B_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_SUCCESS, mdl_id);
> }
>
> +static void process_md_abort_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
> + uint32_t len)
> +{
> + mcap_md_req *req;
> + GSList *l;
> + struct mcap_mdl *mdl, *del;
> + uint16_t mdl_id;
> +
> + if (len != sizeof(mcap_md_req)) {
> + send4B_cmd(mcl, MCAP_MD_ABORT_MDL_RSP,
> + MCAP_INVALID_PARAM_VALUE, MCAP_MDLID_RESERVED);

I remenber about a Johan's comment on send4B_cmd(). It was basically,
wouldn't be better have function to send data of a arbritrary size. I
think I saw a send5B_cmd() in these patches as well.

> + return;
> + }
> +
> + req = (mcap_md_req *)cmd;
> + mdl_id = ntohs(req->mdl);
> + mcl->state = MCL_CONNECTED;
> + for (l = mcl->mdls; l; l = l->next) {
> + mdl = l->data;
> + if ((mdl_id == mdl->mdlid) && (mdl->state == MDL_WAITING)) {
> + del = mdl;
> + if (mcl->state != MCL_CONNECTED)
> + break;
> + continue;
> + }
> + if ((mdl->state == MDL_CONNECTED) && (mcl->state != MCL_ACTIVE))
> + mcl->state = MCL_ACTIVE;
> +
> + if ((del) && (mcl->state == MCL_ACTIVE))
> + break;
> + }
> +
> + if (!del) {
> + send4B_cmd(mcl, MCAP_MD_ABORT_MDL_RSP, MCAP_INVALID_MDL,
> + mdl_id);
> + return;
> + }
> +
> + mcl->cb->mdl_aborted(del, mcl->cb->user_data);
> +
> + mcl->mdls = g_slist_remove(mcl->mdls, del);
> + g_free(del);
> + send4B_cmd(mcl, MCAP_MD_ABORT_MDL_RSP, MCAP_SUCCESS, mdl_id);
> +}
> +
> static void process_md_delete_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
> uint32_t len)
> {
> @@ -626,7 +671,10 @@ static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
>
> static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
> {
> - /* TODO */
> + if (cmd[0] == MCAP_MD_ABORT_MDL_REQ)
> + process_md_abort_mdl_req(mcl, cmd, len);
> + else
> + error_cmd_rsp(mcl, cmd, len);
> }
>
> static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)

--
Gustavo F. Padovan
http://padovan.org

2010-07-22 23:40:08

by Gustavo Padovan

[permalink] [raw]
Subject: Re: [PATCH 29/60] Fix missed state transition in MCAP

Hi Jose,

* Gustavo F. Padovan <[email protected]> [2010-07-22 20:37:22 -0300]:

> Hi Jose,
>
> * Jose Antonio Santos Cadenas <[email protected]> [2010-07-22 10:56:22 +0200]:
>
> > From: Jos? Antonio Santos-Cadenas <[email protected]>
> >
> > MCL should transite to properly state when a create_mdl_req is
> > not SUCCESS
> > ---
> > mcap/mcap.c | 1 +
> > 1 files changed, 1 insertions(+), 0 deletions(-)
> >
> > diff --git a/mcap/mcap.c b/mcap/mcap.c
> > index cf92368..1dfe083 100644
> > --- a/mcap/mcap.c
> > +++ b/mcap/mcap.c
> > @@ -1260,6 +1260,7 @@ fail:
> > mcl->mdls = g_slist_remove(mcl->mdls, mdl);
> > g_free(mdl);
> > g_error_free(gerr);
> > + update_mcl_state(mcl);
> > return close;
> > }
>
> The same should apply here. Can you merge this with the original commit
> that implemented create_mdl_req(), can't you?

There should be another patches here in the same situation, I'm not
checking all of them for this. Please check them and fix into the
original commits when possible. That can make the review easier. ;)

--
Gustavo F. Padovan
http://padovan.org

2010-07-22 23:47:24

by Gustavo Padovan

[permalink] [raw]
Subject: Re: [PATCH 16/60] Implement function to send md_reconnect_mdl_req

* Santiago Carot-Nemesio <[email protected]> [2010-07-22 10:52:11 +0200]:

> ---
> mcap/mcap.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 files changed, 51 insertions(+), 0 deletions(-)
>
> diff --git a/mcap/mcap.c b/mcap/mcap.c
> index dc55cda..a0f00af 100644
> --- a/mcap/mcap.c
> +++ b/mcap/mcap.c
> @@ -261,6 +261,20 @@ static uint16_t generate_mdlid(struct mcap_mcl *mcl)
> return mdlid;
> }
>
> +static uint8_t *create_req(uint8_t op, uint16_t mdl_id)
> +{
> + uint8_t *req;
> + mcap_md_req *req_cmd;
> +
> + req = g_malloc0(sizeof(mcap_md_req));
> +
> + req_cmd = (mcap_md_req *)req;
> + req_cmd->op = op;
> + req_cmd->mdl = htons(mdl_id);
> +
> + return req;
> +}

Why are you casting here? I would expect mcap_md_req * as return type
here. If the problem is with mcap_send_std_opcode() you can used "void *" as
parameter type there.

> +
> static uint8_t *create_mdl_req(uint16_t mdl_id, uint8_t mdep, uint8_t conf)
> {
> uint8_t *req;
> @@ -356,6 +370,43 @@ void mcap_req_mdl_creation(struct mcap_mcl *mcl,
> mcl);
> }
>
> +void mcap_req_mdl_reconnect(struct mcap_mdl *mdl,
> + GError **err,
> + mcap_mdl_operation_cb reconnect_cb,
> + gpointer user_data)
> +{
> + struct mcap_mdl_op_cb *con;
> + struct mcap_mcl *mcl = mdl->mcl;
> + uint8_t *cmd;
> +
> + if (mdl->state != MDL_CLOSED) {
> + g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
> + "MDL is not closed");
> + return;
> + }
> + con = g_new0(struct mcap_mdl_op_cb, 1);
> +
> + cmd = create_req(MCAP_MD_RECONNECT_MDL_REQ, mdl->mdlid);
> + mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_req), err);
> + if (*err) {
> + g_free(con);
> + g_free(cmd);
> + return;
> + }
> +
> + mdl->state = MDL_WAITING;
> +
> + con->mdl = mdl;
> + con->cb.op = reconnect_cb;
> + con->user_data = user_data;
> +
> + mcl->state = MCL_ACTIVE;
> + mcl->priv_data = con;
> +
> + mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
> + mcl);
> +}
> +
> static void update_mcl_state(struct mcap_mcl *mcl)
> {
> GSList *l;

--
Gustavo F. Padovan
http://padovan.org

2010-07-22 23:37:22

by Gustavo Padovan

[permalink] [raw]
Subject: Re: [PATCH 29/60] Fix missed state transition in MCAP

Hi Jose,

* Jose Antonio Santos Cadenas <[email protected]> [2010-07-22 10:56:22 +0200]:

> From: Jos? Antonio Santos-Cadenas <[email protected]>
>
> MCL should transite to properly state when a create_mdl_req is
> not SUCCESS
> ---
> mcap/mcap.c | 1 +
> 1 files changed, 1 insertions(+), 0 deletions(-)
>
> diff --git a/mcap/mcap.c b/mcap/mcap.c
> index cf92368..1dfe083 100644
> --- a/mcap/mcap.c
> +++ b/mcap/mcap.c
> @@ -1260,6 +1260,7 @@ fail:
> mcl->mdls = g_slist_remove(mcl->mdls, mdl);
> g_free(mdl);
> g_error_free(gerr);
> + update_mcl_state(mcl);
> return close;
> }

The same should apply here. Can you merge this with the original commit
that implemented create_mdl_req(), can't you?


--
Gustavo F. Padovan
http://padovan.org

2010-07-22 23:36:06

by Gustavo Padovan

[permalink] [raw]
Subject: Re: MCAP Patches

Hi Santiago,

* Santiago Carot-Nemesio <[email protected]> [2010-07-22 10:51:55 +0200]:

> Hello,
>
> Next you are MCAP patches that Jos? Antonio Santos Cadenas and me have generated for BlueZ.
> We still believe that MCAP should be an independent library from HDP because other profiles
> non health related may want to use it in the future, if we set this health dependency we will
> force to import health features in plugins that only require MCAP.
> Nevertheless, as we accorded last week in Brazil we are sending a last patch to set MCAP
> into health directory with HDP. We leave in your hands upload it as health plugin or not.

Please provide a git tree link for theses patches too. Thanks.

--
Gustavo F. Padovan
http://padovan.org

2010-07-22 23:31:07

by Gustavo Padovan

[permalink] [raw]
Subject: Re: [PATCH 27/60] Fix wrong response code rejecting reconnections

Hi Jose,

* Jose Antonio Santos Cadenas <[email protected]> [2010-07-22 10:56:20 +0200]:

> From: Jos? Antonio Santos-Cadenas <[email protected]>
>
> ---
> mcap/mcap.c | 2 +-
> 1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/mcap/mcap.c b/mcap/mcap.c
> index 43b215b..7098a8d 100644
> --- a/mcap/mcap.c
> +++ b/mcap/mcap.c
> @@ -1024,7 +1024,7 @@ static void process_md_reconnect_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
> return;
>
> if (rsp != MCAP_SUCCESS) {
> - send4B_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, rsp, mdl_id);
> + send4B_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, rsp, mdl_id);
> return;
> }

As we do not merged any patches for MCAP this fix could be amended with
the patch the implements process_md_reconnect_mdl_req().

--
Gustavo F. Padovan
http://padovan.org

2010-07-22 08:58:12

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 55/60] Change the get_addres function to match with other bluez functions

---
mcap/mcap.c | 4 ++--
mcap/mcap_lib.h | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index e9d5d36..a91f4b1 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -929,9 +929,9 @@ void mcap_mcl_set_cb(struct mcap_mcl *mcl, GError **gerr,
return;
}

-bdaddr_t mcap_mcl_get_addr(struct mcap_mcl *mcl)
+void mcap_mcl_get_addr(struct mcap_mcl *mcl, bdaddr_t *addr)
{
- return mcl->addr;
+ bacpy(addr, &mcl->addr);
}

static void mcap_delete_mdl(gpointer elem, gpointer user_data)
diff --git a/mcap/mcap_lib.h b/mcap/mcap_lib.h
index 3d6e0b6..54b40ad 100644
--- a/mcap/mcap_lib.h
+++ b/mcap/mcap_lib.h
@@ -134,7 +134,7 @@ void mcap_create_mcl(struct mcap_instance *ms,
void mcap_close_mcl(struct mcap_mcl *mcl, gboolean cache);
void mcap_mcl_set_cb(struct mcap_mcl *mcl, GError **gerr,
gpointer user_data, McapMclCb cb1, ...);
-bdaddr_t mcap_mcl_get_addr(struct mcap_mcl *mcl);
+void mcap_mcl_get_addr(struct mcap_mcl *mcl, bdaddr_t *addr);

struct mcap_mcl *mcap_mcl_ref(struct mcap_mcl *mcl);
void mcap_mcl_unref(struct mcap_mcl *mcl);
--
1.6.3.3


2010-07-22 08:58:17

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 60/60] Change variable name for MCAP Instances

---
mcap/mcap.c | 46 +++++++++++++++++++++++-----------------------
mcap/mcap_lib.h | 6 +++---
2 files changed, 26 insertions(+), 26 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 5369328..6155f0a 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1987,51 +1987,51 @@ struct mcap_instance *mcap_create_instance(struct btd_adapter *btd_adapter,
return ms;
}

-void mcap_release_instance(struct mcap_instance *ms)
+void mcap_release_instance(struct mcap_instance *mi)
{
GSList *l;

- if (!ms)
+ if (!mi)
return;

- if (ms->ccio) {
- g_io_channel_shutdown(ms->ccio, TRUE, NULL);
- g_io_channel_unref(ms->ccio);
- ms->ccio = NULL;
+ if (mi->ccio) {
+ g_io_channel_shutdown(mi->ccio, TRUE, NULL);
+ g_io_channel_unref(mi->ccio);
+ mi->ccio = NULL;
}

- if (ms->dcio) {
- g_io_channel_shutdown(ms->dcio, TRUE, NULL);
- g_io_channel_unref(ms->dcio);
- ms->dcio = NULL;
+ if (mi->dcio) {
+ g_io_channel_shutdown(mi->dcio, TRUE, NULL);
+ g_io_channel_unref(mi->dcio);
+ mi->dcio = NULL;
}

- for (l = ms->mcls; l; l = l->next) {
+ for (l = mi->mcls; l; l = l->next) {
mcap_mcl_shutdown(l->data);
mcap_mcl_unref(l->data);
}
- g_slist_free(ms->mcls);
- ms->mcls = NULL;
+ g_slist_free(mi->mcls);
+ mi->mcls = NULL;

- for (l = ms->cached; l; l = l->next)
+ for (l = mi->cached; l; l = l->next)
mcap_mcl_unref(l->data);
- g_slist_free(ms->cached);
- ms->cached = NULL;
+ g_slist_free(mi->cached);
+ mi->cached = NULL;

- g_free(ms);
+ g_free(mi);
}

-uint16_t mcap_get_ctrl_psm(struct mcap_instance *ms, GError **err)
+uint16_t mcap_get_ctrl_psm(struct mcap_instance *mi, GError **err)
{
uint16_t lpsm;

- if (!(ms && ms->ccio)) {
+ if (!(mi && mi->ccio)) {
g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS,
"Invalid MCAP instance");
return 0;
}

- bt_io_get(ms->ccio, BT_IO_L2CAP, err,
+ bt_io_get(mi->ccio, BT_IO_L2CAP, err,
BT_IO_OPT_PSM, &lpsm,
BT_IO_OPT_INVALID);
if (*err)
@@ -2039,17 +2039,17 @@ uint16_t mcap_get_ctrl_psm(struct mcap_instance *ms, GError **err)
return lpsm;
}

-uint16_t mcap_get_data_psm(struct mcap_instance *ms, GError **err)
+uint16_t mcap_get_data_psm(struct mcap_instance *mi, GError **err)
{
uint16_t lpsm;

- if (!(ms && ms->dcio)) {
+ if (!(mi && mi->dcio)) {
g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS,
"Invalid MCAP instance");
return 0;
}

- bt_io_get(ms->dcio, BT_IO_L2CAP, err,
+ bt_io_get(mi->dcio, BT_IO_L2CAP, err,
BT_IO_OPT_PSM, &lpsm,
BT_IO_OPT_INVALID);
if (*err)
diff --git a/mcap/mcap_lib.h b/mcap/mcap_lib.h
index fa62cbe..b6286a1 100644
--- a/mcap/mcap_lib.h
+++ b/mcap/mcap_lib.h
@@ -158,10 +158,10 @@ struct mcap_instance *mcap_create_instance(struct btd_adapter *btd_adapter,
gpointer user_data,
GError **gerr);

-void mcap_release_instance(struct mcap_instance *ms);
+void mcap_release_instance(struct mcap_instance *mi);

-uint16_t mcap_get_ctrl_psm(struct mcap_instance *ms, GError **err);
-uint16_t mcap_get_data_psm(struct mcap_instance *ms, GError **err);
+uint16_t mcap_get_ctrl_psm(struct mcap_instance *mi, GError **err);
+uint16_t mcap_get_data_psm(struct mcap_instance *mi, GError **err);

#ifdef __cplusplus
}
--
1.6.3.3


2010-07-22 08:58:16

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 59/60] Remove "req" word from MCAP API

---
mcap/mcap.c | 24 ++++++++++++------------
mcap/mcap_lib.h | 10 +++++-----
2 files changed, 17 insertions(+), 17 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index b3017fb..5369328 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -307,8 +307,8 @@ int mcap_send_data(int sock, const uint8_t *buf, uint32_t size)
return 0;
}

-static int mcap_send_cmd(struct mcap_mcl *mcl, uint8_t oc, uint8_t rc, uint16_t mdl,
- uint8_t *data, size_t len)
+static int mcap_send_cmd(struct mcap_mcl *mcl, uint8_t oc, uint8_t rc,
+ uint16_t mdl, uint8_t *data, size_t len)
{
mcap_rsp *cmd;
uint8_t *rsp;
@@ -427,7 +427,7 @@ static gboolean wait_response_timer(gpointer data)
return FALSE;
}

-void mcap_req_mdl_creation(struct mcap_mcl *mcl,
+void mcap_create_mdl(struct mcap_mcl *mcl,
uint8_t mdepid,
uint8_t conf,
mcap_mdl_operation_conf_cb connect_cb,
@@ -474,7 +474,7 @@ void mcap_req_mdl_creation(struct mcap_mcl *mcl,
mcl);
}

-void mcap_req_mdl_reconnect(struct mcap_mdl *mdl,
+void mcap_reconnect_mdl(struct mcap_mdl *mdl,
mcap_mdl_operation_cb reconnect_cb,
gpointer user_data,
GError **err)
@@ -529,7 +529,7 @@ static void send_delete_req(GError **err, struct mcap_mcl *mcl,
mcl);
}

-void mcap_req_mdl_delete_all(struct mcap_mcl *mcl, mcap_mdl_notify_cb delete_cb,
+void mcap_delete_all_mdls(struct mcap_mcl *mcl, mcap_mdl_notify_cb delete_cb,
gpointer user_data, GError **err)
{
GSList *l;
@@ -559,7 +559,7 @@ void mcap_req_mdl_delete_all(struct mcap_mcl *mcl, mcap_mdl_notify_cb delete_cb,
g_free(con);
}

-void mcap_req_mdl_deletion(struct mcap_mdl *mdl, mcap_mdl_notify_cb delete_cb,
+void mcap_delete_mdl(struct mcap_mdl *mdl, mcap_mdl_notify_cb delete_cb,
gpointer user_data, GError **err)
{
struct mcap_mcl *mcl= mdl->mcl;
@@ -915,7 +915,7 @@ void mcap_mcl_get_addr(struct mcap_mcl *mcl, bdaddr_t *addr)
bacpy(addr, &mcl->addr);
}

-static void mcap_delete_mdl(gpointer elem, gpointer user_data)
+static void mcap_del_mdl(gpointer elem, gpointer user_data)
{
struct mcap_mdl *mdl = elem;
gboolean notify = *(gboolean *)user_data;
@@ -1127,7 +1127,7 @@ static void process_md_delete_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
mdlid = ntohs(req->mdl);
if (mdlid == MCAP_ALL_MDLIDS) {
notify = FALSE;
- g_slist_foreach(mcl->mdls, mcap_delete_mdl, &notify);
+ g_slist_foreach(mcl->mdls, mcap_del_mdl, &notify);
g_slist_free(mcl->mdls);
mcl->mdls = NULL;
mcl->state = MCL_CONNECTED;
@@ -1158,7 +1158,7 @@ static void process_md_delete_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
mcl->mdls = g_slist_remove(mcl->mdls, mdl);
update_mcl_state(mcl);
notify = TRUE;
- mcap_delete_mdl(mdl, &notify);
+ mcap_del_mdl(mdl, &notify);

resp:
mcap_send_cmd(mcl, MCAP_MD_DELETE_MDL_RSP, MCAP_SUCCESS, mdlid,
@@ -1456,7 +1456,7 @@ static gboolean process_md_delete_mdl_rsp(struct mcap_mcl *mcl, uint8_t *cmd,
}

if (mdlid == MCAP_ALL_MDLIDS) {
- g_slist_foreach(mcl->mdls, mcap_delete_mdl, &notify);
+ g_slist_foreach(mcl->mdls, mcap_del_mdl, &notify);
g_slist_free(mcl->mdls);
mcl->mdls = NULL;
mcl->state = MCL_CONNECTED;
@@ -1465,7 +1465,7 @@ static gboolean process_md_delete_mdl_rsp(struct mcap_mcl *mcl, uint8_t *cmd,

mcl->mdls = g_slist_remove(mcl->mdls, mdl);
update_mcl_state(mcl);
- mcap_delete_mdl(mdl, &notify);
+ mcap_del_mdl(mdl, &notify);
end:
deleted_cb(gerr, user_data);
return close;
@@ -1594,7 +1594,7 @@ static void mcap_connect_mdl_cb(GIOChannel *chan, GError *conn_err,
cb(mdl, conn_err, user_data);
}

-void mcap_mdl_connect(struct mcap_mdl *mdl, BtIOType BtType, uint16_t dcpsm,
+void mcap_connect_mdl(struct mcap_mdl *mdl, BtIOType BtType, uint16_t dcpsm,
mcap_mdl_operation_cb connect_cb, gpointer user_data, GError **err)
{
struct mcap_mdl_op_cb *con;
diff --git a/mcap/mcap_lib.h b/mcap/mcap_lib.h
index 7b8fcfd..fa62cbe 100644
--- a/mcap/mcap_lib.h
+++ b/mcap/mcap_lib.h
@@ -98,25 +98,25 @@ typedef void (* mcap_mcl_connect_cb) (struct mcap_mcl *mcl, GError *err,

/* Mdl operations*/

-void mcap_req_mdl_creation(struct mcap_mcl *mcl,
+void mcap_create_mdl(struct mcap_mcl *mcl,
uint8_t mdepid,
uint8_t conf,
mcap_mdl_operation_conf_cb connect_cb,
gpointer user_data,
GError **err);
-void mcap_req_mdl_reconnect(struct mcap_mdl *mdl,
+void mcap_reconnect_mdl(struct mcap_mdl *mdl,
mcap_mdl_operation_cb reconnect_cb,
gpointer user_data,
GError **err);
-void mcap_req_mdl_delete_all(struct mcap_mcl *mcl,
+void mcap_delete_all_mdls(struct mcap_mcl *mcl,
mcap_mdl_notify_cb delete_cb,
gpointer user_data,
GError **err);
-void mcap_req_mdl_deletion(struct mcap_mdl *mdl,
+void mcap_delete_mdl(struct mcap_mdl *mdl,
mcap_mdl_notify_cb delete_cb,
gpointer user_data,
GError **err);
-void mcap_mdl_connect(struct mcap_mdl *mdl,
+void mcap_connect_mdl(struct mcap_mdl *mdl,
BtIOType BtType,
uint16_t dcpsm,
mcap_mdl_operation_cb connect_cb,
--
1.6.3.3


2010-07-22 08:58:15

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 58/60] Return a proper UNIX error instead of -1 in mcap_mdl_get_fd

From: Jose Antonio Santos Cadenas <[email protected]>

---
mcap/mcap.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 30a8d56..b3017fb 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -29,6 +29,7 @@

#include <netinet/in.h>
#include <stdlib.h>
+#include <errno.h>

#include "mcap.h"
#include "mcap_lib.h"
@@ -640,7 +641,7 @@ static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr)
int mcap_mdl_get_fd(struct mcap_mdl *mdl)
{
if ((!mdl) || (mdl->state != MDL_CONNECTED))
- return -1;
+ return -ENOTCONN;

return g_io_channel_unix_get_fd(mdl->dc);
}
--
1.6.3.3


2010-07-22 08:58:14

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 57/60] Set Gerror at the end of the output paremeters list

---
mcap/mcap.c | 34 +++++++++++++++++-----------------
mcap/mcap_lib.h | 49 ++++++++++++++++++++++++++++---------------------
2 files changed, 45 insertions(+), 38 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 869b6e7..30a8d56 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -429,9 +429,9 @@ static gboolean wait_response_timer(gpointer data)
void mcap_req_mdl_creation(struct mcap_mcl *mcl,
uint8_t mdepid,
uint8_t conf,
- GError **err,
mcap_mdl_operation_conf_cb connect_cb,
- gpointer user_data)
+ gpointer user_data,
+ GError **err)
{
struct mcap_mdl *mdl;
struct mcap_mdl_op_cb *con;
@@ -474,9 +474,9 @@ void mcap_req_mdl_creation(struct mcap_mcl *mcl,
}

void mcap_req_mdl_reconnect(struct mcap_mdl *mdl,
- GError **err,
mcap_mdl_operation_cb reconnect_cb,
- gpointer user_data)
+ gpointer user_data,
+ GError **err)
{
struct mcap_mdl_op_cb *con;
struct mcap_mcl *mcl = mdl->mcl;
@@ -528,8 +528,8 @@ static void send_delete_req(GError **err, struct mcap_mcl *mcl,
mcl);
}

-void mcap_req_mdl_delete_all(struct mcap_mcl *mcl, GError **err,
- mcap_mdl_notify_cb delete_cb, gpointer user_data)
+void mcap_req_mdl_delete_all(struct mcap_mcl *mcl, mcap_mdl_notify_cb delete_cb,
+ gpointer user_data, GError **err)
{
GSList *l;
struct mcap_mdl *mdl;
@@ -558,8 +558,8 @@ void mcap_req_mdl_delete_all(struct mcap_mcl *mcl, GError **err,
g_free(con);
}

-void mcap_req_mdl_deletion(struct mcap_mdl *mdl, GError **err,
- mcap_mdl_notify_cb delete_cb, gpointer user_data)
+void mcap_req_mdl_deletion(struct mcap_mdl *mdl, mcap_mdl_notify_cb delete_cb,
+ gpointer user_data, GError **err)
{
struct mcap_mcl *mcl= mdl->mcl;
struct mcap_mdl_op_cb *con;
@@ -590,8 +590,8 @@ void mcap_req_mdl_deletion(struct mcap_mdl *mdl, GError **err,
g_free(con);
}

-void mcap_mdl_abort(struct mcap_mdl *mdl, GError **err,
- mcap_mdl_notify_cb abort_cb, gpointer user_data)
+void mcap_mdl_abort(struct mcap_mdl *mdl, mcap_mdl_notify_cb abort_cb,
+ gpointer user_data, GError **err)
{
struct mcap_mdl_op_cb *con;
struct mcap_mcl *mcl = mdl->mcl;
@@ -892,8 +892,8 @@ static gboolean parse_set_opts(struct mcap_mdl_cb *mdl_cb, GError **err,
return TRUE;
}

-void mcap_mcl_set_cb(struct mcap_mcl *mcl, GError **gerr,
- gpointer user_data, McapMclCb cb1, ...)
+void mcap_mcl_set_cb(struct mcap_mcl *mcl, gpointer user_data, GError **gerr,
+ McapMclCb cb1, ...)
{
va_list args;
gboolean ret;
@@ -1594,7 +1594,7 @@ static void mcap_connect_mdl_cb(GIOChannel *chan, GError *conn_err,
}

void mcap_mdl_connect(struct mcap_mdl *mdl, BtIOType BtType, uint16_t dcpsm,
- GError **err, mcap_mdl_operation_cb connect_cb, gpointer user_data)
+ mcap_mdl_operation_cb connect_cb, gpointer user_data, GError **err)
{
struct mcap_mdl_op_cb *con;

@@ -1738,9 +1738,9 @@ static void connect_dc_event_cb(GIOChannel *chan, GError *err,
void mcap_create_mcl(struct mcap_instance *ms,
const bdaddr_t *addr,
uint16_t ccpsm,
- GError **err,
mcap_mcl_connect_cb connect_cb,
- gpointer user_data)
+ gpointer user_data,
+ GError **err)
{
struct mcap_mcl *mcl;
struct connect_mcl *con;
@@ -1917,12 +1917,12 @@ struct mcap_instance *mcap_create_instance(struct btd_adapter *btd_adapter,
BtIOSecLevel sec,
uint16_t ccpsm,
uint16_t dcpsm,
- GError **gerr,
mcap_mcl_event_cb mcl_connected,
mcap_mcl_event_cb mcl_reconnected,
mcap_mcl_event_cb mcl_disconnected,
mcap_mcl_event_cb mcl_uncached,
- gpointer user_data)
+ gpointer user_data,
+ GError **gerr)
{
struct mcap_instance *ms;

diff --git a/mcap/mcap_lib.h b/mcap/mcap_lib.h
index 54b40ad..7b8fcfd 100644
--- a/mcap/mcap_lib.h
+++ b/mcap/mcap_lib.h
@@ -101,24 +101,31 @@ typedef void (* mcap_mcl_connect_cb) (struct mcap_mcl *mcl, GError *err,
void mcap_req_mdl_creation(struct mcap_mcl *mcl,
uint8_t mdepid,
uint8_t conf,
- GError **err,
mcap_mdl_operation_conf_cb connect_cb,
- gpointer user_data);
-void mcap_req_mdl_reconnect(struct mcap_mdl *mdl, GError **err,
+ gpointer user_data,
+ GError **err);
+void mcap_req_mdl_reconnect(struct mcap_mdl *mdl,
mcap_mdl_operation_cb reconnect_cb,
- gpointer user_data);
-void mcap_req_mdl_delete_all(struct mcap_mcl *mcl, GError **err,
- mcap_mdl_notify_cb delete_cb, gpointer user_data);
-void mcap_req_mdl_deletion(struct mcap_mdl *mdl, GError **err,
- mcap_mdl_notify_cb delete_cb, gpointer user_data);
+ gpointer user_data,
+ GError **err);
+void mcap_req_mdl_delete_all(struct mcap_mcl *mcl,
+ mcap_mdl_notify_cb delete_cb,
+ gpointer user_data,
+ GError **err);
+void mcap_req_mdl_deletion(struct mcap_mdl *mdl,
+ mcap_mdl_notify_cb delete_cb,
+ gpointer user_data,
+ GError **err);
void mcap_mdl_connect(struct mcap_mdl *mdl,
- BtIOType BtType,
- uint16_t dcpsm,
- GError **err,
- mcap_mdl_operation_cb connect_cb,
- gpointer user_data);
-void mcap_mdl_abort(struct mcap_mdl *mdl, GError **err,
- mcap_mdl_notify_cb abort_cb, gpointer user_data);
+ BtIOType BtType,
+ uint16_t dcpsm,
+ mcap_mdl_operation_cb connect_cb,
+ gpointer user_data,
+ GError **err);
+void mcap_mdl_abort(struct mcap_mdl *mdl,
+ mcap_mdl_notify_cb abort_cb,
+ gpointer user_data,
+ GError **err);

int mcap_mdl_get_fd(struct mcap_mdl *mdl);
uint16_t mcap_mdl_get_mdlid(struct mcap_mdl *mdl);
@@ -128,12 +135,12 @@ uint16_t mcap_mdl_get_mdlid(struct mcap_mdl *mdl);
void mcap_create_mcl(struct mcap_instance *ms,
const bdaddr_t *addr,
uint16_t ccpsm,
- GError **err,
mcap_mcl_connect_cb connect_cb,
- gpointer user_data);
+ gpointer user_data,
+ GError **err);
void mcap_close_mcl(struct mcap_mcl *mcl, gboolean cache);
-void mcap_mcl_set_cb(struct mcap_mcl *mcl, GError **gerr,
- gpointer user_data, McapMclCb cb1, ...);
+void mcap_mcl_set_cb(struct mcap_mcl *mcl, gpointer user_data, GError **gerr,
+ McapMclCb cb1, ...);
void mcap_mcl_get_addr(struct mcap_mcl *mcl, bdaddr_t *addr);

struct mcap_mcl *mcap_mcl_ref(struct mcap_mcl *mcl);
@@ -144,12 +151,12 @@ void mcap_mcl_unref(struct mcap_mcl *mcl);
struct mcap_instance *mcap_create_instance(struct btd_adapter *btd_adapter,
BtIOSecLevel sec, uint16_t ccpsm,
uint16_t dcpsm,
- GError **gerr,
mcap_mcl_event_cb mcl_connected,
mcap_mcl_event_cb mcl_reconnected,
mcap_mcl_event_cb mcl_disconnected,
mcap_mcl_event_cb mcl_uncached,
- gpointer user_data);
+ gpointer user_data,
+ GError **gerr);

void mcap_release_instance(struct mcap_instance *ms);

--
1.6.3.3


2010-07-22 08:58:13

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 56/60] Use a generic function to send commands with variable parameters

Future commands added to MCAP specification may use a variable
parameters greater than one Byte. This patch sets the fixed
part of a mcap response and append at the end of the command
the variable parameter depending of length provided.
---
mcap/mcap.c | 159 +++++++++++++++++++++++--------------------------
mcap/mcap.h | 14 +----
mcap/mcap_internal.h | 1 +
mcap/mcap_sync.c | 23 -------
4 files changed, 79 insertions(+), 118 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index a91f4b1..869b6e7 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -36,7 +36,6 @@

#define RESPONSE_TIMER 2 /* seconds */
#define MAX_CACHED 10 /* 10 devices */
-#define MIN_RSP_LEN 4 /* 4 Bytes */

#define MCAP_ERROR g_quark_from_static_string("mcap-error-quark")

@@ -307,46 +306,28 @@ int mcap_send_data(int sock, const uint8_t *buf, uint32_t size)
return 0;
}

-static int send4B_cmd(struct mcap_mcl *mcl, uint8_t oc, uint8_t rc,
- uint16_t mdl)
+static int mcap_send_cmd(struct mcap_mcl *mcl, uint8_t oc, uint8_t rc, uint16_t mdl,
+ uint8_t *data, size_t len)
{
+ mcap_rsp *cmd;
uint8_t *rsp;
- mcap4B_rsp *rsp_err;
- int sent = -1;
+ int sock, sent;

+ if (mcl->cc == NULL)
+ return -1;

- rsp = g_malloc0(sizeof(mcap4B_rsp));
-
- rsp_err = (mcap4B_rsp *)rsp;
- rsp_err->op = oc;
- rsp_err->rc = rc;
- rsp_err->mdl = htons (mdl);
-
- if (mcl->cc)
- sent = mcap_send_data(g_io_channel_unix_get_fd(mcl->cc), rsp,
- sizeof(mcap4B_rsp));
- g_free(rsp);
- return sent;
-}
-
-static int send5B_cmd(struct mcap_mcl *mcl, uint8_t oc, uint8_t rc,
- uint16_t mdl, uint8_t param)
-{
- uint8_t *rsp;
- mcap5B_rsp *suc;
- int sent = -1;
+ sock = g_io_channel_unix_get_fd(mcl->cc);

- rsp = g_malloc0(sizeof(mcap5B_rsp));
+ rsp = g_malloc(sizeof(mcap_rsp) + len);
+ cmd = (mcap_rsp *)rsp;
+ cmd->op = oc;
+ cmd->rc = rc;
+ cmd->mdl = htons(mdl);

- suc = (mcap5B_rsp *)rsp;
- suc->op = oc;
- suc->rc = rc;
- suc->mdl = htons(mdl);
- suc->param = param;
+ if (data && (len > 0))
+ memcpy(rsp + sizeof(mcap_rsp), data, len);

- if (mcl->cc)
- sent = mcap_send_data(g_io_channel_unix_get_fd(mcl->cc), rsp,
- sizeof(mcap5B_rsp));
+ sent = mcap_send_data(sock, rsp, sizeof(mcap_rsp) + len);
g_free(rsp);
return sent;
}
@@ -371,7 +352,6 @@ static uint16_t generate_mdlid(struct mcap_mcl *mcl)
struct mcap_mdl *mdl;

do {
- DBG("Testing %d", mdlid);
mdl = get_mdl(mcl, mdlid);
if (!mdl) {
mcl->next_mdl = (mdlid % MCAP_MDLID_FINAL) + 1;
@@ -957,8 +937,10 @@ static void process_md_create_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
uint8_t rsp;

if (len != sizeof(mcap_md_create_mdl_req)) {
- send4B_cmd(mcl, MCAP_MD_CREATE_MDL_RSP,
- MCAP_INVALID_PARAM_VALUE, MCAP_MDLID_RESERVED);
+ mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP,
+ MCAP_INVALID_PARAM_VALUE,
+ MCAP_MDLID_RESERVED,
+ NULL, 0);
return;
}

@@ -966,15 +948,15 @@ static void process_md_create_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,

mdl_id = ntohs(req->mdl);
if ((mdl_id < MCAP_MDLID_INITIAL) || (mdl_id > MCAP_MDLID_FINAL)) {
- send4B_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_INVALID_MDL,
- mdl_id);
+ mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_INVALID_MDL,
+ mdl_id, NULL, 0);
return;
}

mdep_id = req->mdep;
if (mdep_id > MCAP_MDEPID_FINAL) {
- send4B_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_INVALID_MDEP,
- mdl_id);
+ mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_INVALID_MDEP,
+ mdl_id, NULL, 0);
return;
}

@@ -982,7 +964,8 @@ static void process_md_create_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
if (mdl && (mdl->state == MDL_WAITING || mdl->state == MDL_DELETING )) {
/* Creation request arrives for a MDL that is being managed
* at current moment */
- send4B_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_MDL_BUSY, mdl_id);
+ mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_MDL_BUSY,
+ mdl_id, NULL, 0);
return;
}

@@ -999,12 +982,13 @@ static void process_md_create_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
/* Remote device set default configuration but upper profile */
/* has changed it. Protocol Error: force closing the MCL by */
/* remote device using UNSPECIFIED_ERROR response */
- send4B_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_UNSPECIFIED_ERROR,
- mdl_id);
+ mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP,
+ MCAP_UNSPECIFIED_ERROR, mdl_id, NULL, 0);
return;
}
if (rsp != MCAP_SUCCESS) {
- send4B_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, rsp, mdl_id);
+ mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, rsp, mdl_id,
+ NULL, 0);
return;
}

@@ -1023,7 +1007,8 @@ static void process_md_create_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
mdl->state = MDL_WAITING;

mcl->state = MCL_PENDING;
- send5B_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_SUCCESS, mdl_id, conf);
+ mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_SUCCESS, mdl_id,
+ &conf, 1);
}

static void process_md_reconnect_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
@@ -1035,8 +1020,10 @@ static void process_md_reconnect_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
uint8_t rsp;

if (len != sizeof(mcap_md_req)) {
- send4B_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP,
- MCAP_INVALID_PARAM_VALUE, MCAP_MDLID_RESERVED);
+ mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP,
+ MCAP_INVALID_PARAM_VALUE,
+ MCAP_MDLID_RESERVED,
+ NULL, 0);
return;
}

@@ -1045,14 +1032,14 @@ static void process_md_reconnect_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,

mdl = get_mdl(mcl, mdl_id);
if (!mdl) {
- send4B_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP,
- MCAP_INVALID_MDL, mdl_id);
+ mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_INVALID_MDL,
+ mdl_id, NULL, 0);
return;
} else if (mdl->state == MDL_WAITING || mdl->state == MDL_DELETING ) {
/* Creation request arrives for a MDL that is being managed
* at current moment */
- send4B_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_MDL_BUSY,
- mdl_id);
+ mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_MDL_BUSY,
+ mdl_id, NULL, 0);
return;
}

@@ -1062,7 +1049,8 @@ static void process_md_reconnect_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
return;

if (rsp != MCAP_SUCCESS) {
- send4B_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, rsp, mdl_id);
+ mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, rsp, mdl_id,
+ NULL, 0);
return;
}

@@ -1071,7 +1059,8 @@ static void process_md_reconnect_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,

mdl->state = MDL_WAITING;
mcl->state = MCL_PENDING;
- send4B_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_SUCCESS, mdl_id);
+ mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_SUCCESS, mdl_id,
+ NULL, 0);
}

static void process_md_abort_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
@@ -1083,8 +1072,8 @@ static void process_md_abort_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
uint16_t mdl_id;

if (len != sizeof(mcap_md_req)) {
- send4B_cmd(mcl, MCAP_MD_ABORT_MDL_RSP,
- MCAP_INVALID_PARAM_VALUE, MCAP_MDLID_RESERVED);
+ mcap_send_cmd(mcl, MCAP_MD_ABORT_MDL_RSP,
+ MCAP_INVALID_PARAM_VALUE, MCAP_MDLID_RESERVED, NULL, 0);
return;
}

@@ -1107,14 +1096,15 @@ static void process_md_abort_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
}

if (!abrt) {
- send4B_cmd(mcl, MCAP_MD_ABORT_MDL_RSP, MCAP_INVALID_MDL,
- mdl_id);
+ mcap_send_cmd(mcl, MCAP_MD_ABORT_MDL_RSP, MCAP_INVALID_MDL,
+ mdl_id, NULL, 0);
return;
}

mcl->cb->mdl_aborted(abrt, mcl->cb->user_data);
abrt->state = MDL_CLOSED;
- send4B_cmd(mcl, MCAP_MD_ABORT_MDL_RSP, MCAP_SUCCESS, mdl_id);
+ mcap_send_cmd(mcl, MCAP_MD_ABORT_MDL_RSP, MCAP_SUCCESS, mdl_id,
+ NULL, 0);
}

static void process_md_delete_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
@@ -1127,8 +1117,8 @@ static void process_md_delete_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
GSList *l;

if (len != sizeof(mcap_md_req)) {
- send4B_cmd(mcl, MCAP_MD_ABORT_MDL_RSP,
- MCAP_INVALID_PARAM_VALUE, MCAP_MDLID_RESERVED);
+ mcap_send_cmd(mcl, MCAP_MD_ABORT_MDL_RSP,
+ MCAP_INVALID_PARAM_VALUE, MCAP_MDLID_RESERVED, NULL, 0);
return;
}

@@ -1146,8 +1136,8 @@ static void process_md_delete_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
}

if ((mdlid < MCAP_MDLID_INITIAL) || (mdlid > MCAP_MDLID_FINAL)) {
- send4B_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_INVALID_MDL,
- mdlid);
+ mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_INVALID_MDL,
+ mdlid, NULL, 0);
return;
}

@@ -1160,8 +1150,8 @@ static void process_md_delete_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
}

if (!mdl || (mdl->state == MDL_WAITING)) {
- send4B_cmd(mcl, MCAP_MD_DELETE_MDL_RSP, MCAP_INVALID_MDL,
- mdlid);
+ mcap_send_cmd(mcl, MCAP_MD_DELETE_MDL_RSP, MCAP_INVALID_MDL,
+ mdlid, NULL, 0);
return;
}
mcl->mdls = g_slist_remove(mcl->mdls, mdl);
@@ -1170,7 +1160,8 @@ static void process_md_delete_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
mcap_delete_mdl(mdl, &notify);

resp:
- send4B_cmd(mcl, MCAP_MD_DELETE_MDL_RSP, MCAP_SUCCESS, mdlid);
+ mcap_send_cmd(mcl, MCAP_MD_DELETE_MDL_RSP, MCAP_SUCCESS, mdlid,
+ NULL, 0);
}

static void invalid_req_state(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
@@ -1183,7 +1174,7 @@ static void invalid_req_state(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
* response if it is possible */
mdlr = len < sizeof(mcap_md_req) ? MCAP_MDLID_RESERVED :
ntohs(((mcap_md_req *)cmd)->mdl);
- send4B_cmd(mcl, cmd[0]+1, MCAP_INVALID_OPERATION, mdlr);
+ mcap_send_cmd(mcl, cmd[0]+1, MCAP_INVALID_OPERATION, mdlr, NULL, 0);
}

/* Function used to process commands depending of MCL state */
@@ -1237,7 +1228,7 @@ static gboolean check_err_rsp(struct mcap_mcl *mcl, uint8_t *cmd,
gint err = MCAP_ERROR_FAILED;
gboolean close = FALSE;
uint16_t rmdl, smdl;
- mcap4B_rsp *rsp;
+ mcap_rsp *rsp;
char *msg;

if (cmd[0] == MCAP_ERROR_RSP) {
@@ -1247,7 +1238,7 @@ static gboolean check_err_rsp(struct mcap_mcl *mcl, uint8_t *cmd,
}

/* Check if the response matches with the last request */
- if ((rlen < MIN_RSP_LEN) || ((mcl->lcmd[0] + 1) != cmd[0])) {
+ if ((rlen < sizeof(mcap_rsp)) || ((mcl->lcmd[0] + 1) != cmd[0])) {
msg = "Protocol error";
close = TRUE;
goto fail;
@@ -1259,7 +1250,7 @@ static gboolean check_err_rsp(struct mcap_mcl *mcl, uint8_t *cmd,
goto fail;
}

- rsp = (mcap4B_rsp *)cmd;
+ rsp = (mcap_rsp *)cmd;
smdl = ntohs(cmdlast->mdl);
rmdl = ntohs(rsp->mdl);
if (rmdl != smdl) {
@@ -1304,12 +1295,12 @@ static gboolean process_md_create_mdl_rsp(struct mcap_mcl *mcl,
uint8_t conf = cmdlast->conf;
gboolean close = FALSE;
GError *gerr = NULL;
- mcap5B_rsp *rsp;
+ uint8_t *param;

g_free(mcl->priv_data);
mcl->priv_data = NULL;

- close = check_err_rsp(mcl, cmd, len, sizeof(mcap4B_rsp), &gerr);
+ close = check_err_rsp(mcl, cmd, len, sizeof(mcap_rsp) + 1, &gerr);
g_free(mcl->lcmd);
mcl->lcmd = NULL;
mcl->req = MCL_AVAILABLE;
@@ -1317,23 +1308,23 @@ static gboolean process_md_create_mdl_rsp(struct mcap_mcl *mcl,
if (gerr)
goto fail;

- if (len < sizeof(mcap5B_rsp)) {
+ if (len < sizeof(mcap_rsp)) {
g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_FAILED,
"Protocol error");
close = TRUE;
goto fail;
}

- rsp = (mcap5B_rsp *)cmd;
+ param = cmd + sizeof(mcap_rsp);
/* Check if preferences changed */
- if ((conf != 0x00) && (rsp->param != conf)) {
+ if ((conf != 0x00) && (*param != conf)) {
g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_FAILED,
"Configuration changed");
close = TRUE;
goto fail;
}

- connect_cb(mdl, rsp->param, gerr, user_data);
+ connect_cb(mdl, *param, gerr, user_data);
return close;
fail:
connect_cb(NULL, 0, gerr, user_data);
@@ -1351,14 +1342,14 @@ static gboolean process_md_reconnect_mdl_rsp(struct mcap_mcl *mcl,
mcap_mdl_operation_cb reconn_cb = reconn->cb.op;
gpointer user_data = reconn->user_data;
struct mcap_mdl *mdl = reconn->mdl;
- mcap4B_rsp *rsp = (mcap4B_rsp *)cmd;
+ mcap_rsp *rsp = (mcap_rsp *)cmd;
GError *gerr = NULL;
gboolean close = FALSE;

g_free(mcl->priv_data);
mcl->priv_data = NULL;

- close = check_err_rsp(mcl, cmd, len, sizeof(mcap4B_rsp), &gerr);
+ close = check_err_rsp(mcl, cmd, len, sizeof(mcap_rsp), &gerr);

g_free(mcl->lcmd);
mcl->lcmd = NULL;
@@ -1390,14 +1381,14 @@ static gboolean process_md_abort_mdl_rsp(struct mcap_mcl *mcl,
mcap_mdl_notify_cb abrt_cb = abrt->cb.notify;
gpointer user_data = abrt->user_data;
struct mcap_mdl *mdl = abrt->mdl;
- mcap4B_rsp *rsp = (mcap4B_rsp *)cmd;
+ mcap_rsp *rsp = (mcap_rsp *)cmd;
GError *gerr = NULL;
gboolean close = FALSE;

g_free(mcl->priv_data);
mcl->priv_data = NULL;

- close = check_err_rsp(mcl, cmd, len, sizeof(mcap4B_rsp), &gerr);
+ close = check_err_rsp(mcl, cmd, len, sizeof(mcap_rsp), &gerr);

g_free(mcl->lcmd);
mcl->lcmd = NULL;
@@ -1406,7 +1397,7 @@ static gboolean process_md_abort_mdl_rsp(struct mcap_mcl *mcl,
abrt_cb(gerr, user_data);
shutdown_mdl(mdl);

- if ((len >= MIN_RSP_LEN) && (rsp->rc == MCAP_INVALID_MDL)) {
+ if ((len >= sizeof(mcap_rsp)) && (rsp->rc == MCAP_INVALID_MDL)) {
mcl->mdls = g_slist_remove(mcl->mdls, mdl);
g_free(mdl);
}
@@ -1447,7 +1438,7 @@ static gboolean process_md_delete_mdl_rsp(struct mcap_mcl *mcl, uint8_t *cmd,
g_free(mcl->priv_data);
mcl->priv_data = NULL;

- close = check_err_rsp(mcl, cmd, len, sizeof(mcap4B_rsp), &gerr);
+ close = check_err_rsp(mcl, cmd, len, sizeof(mcap_rsp), &gerr);

g_free(mcl->lcmd);
mcl->lcmd = NULL;
@@ -1517,8 +1508,8 @@ static void proc_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
(cmd[0] > MCAP_MD_DELETE_MDL_RSP &&
cmd[0] < MCAP_MD_SYNC_CAP_REQ)) {
error("Unknown cmd received (op code = %d)", cmd[0]);
- send4B_cmd(mcl, MCAP_ERROR_RSP, MCAP_INVALID_OP_CODE,
- MCAP_MDLID_RESERVED);
+ mcap_send_cmd(mcl, MCAP_ERROR_RSP, MCAP_INVALID_OP_CODE,
+ MCAP_MDLID_RESERVED, NULL, 0);
return;
}

diff --git a/mcap/mcap.h b/mcap/mcap.h
index 0299f42..9b95473 100644
--- a/mcap/mcap.h
+++ b/mcap/mcap.h
@@ -106,18 +106,10 @@ typedef struct {
*/

typedef struct {
- uint8_t op;
- uint8_t rc;
+ uint8_t op;
+ uint8_t rc;
uint16_t mdl;
-} __attribute__ ((packed)) mcap4B_rsp;
-
-typedef struct {
- uint8_t op;
- uint8_t rc;
- uint16_t mdl;
- uint8_t param;
-} __attribute__ ((packed)) mcap5B_rsp;
-
+} __attribute__ ((packed)) mcap_rsp;

/*
* MCAP Clock Synchronization Protocol
diff --git a/mcap/mcap_internal.h b/mcap/mcap_internal.h
index 9dacc12..7f16ab7 100644
--- a/mcap/mcap_internal.h
+++ b/mcap/mcap_internal.h
@@ -114,6 +114,7 @@ struct mcap_mdl {
};

int mcap_send_data(int sock, const uint8_t *buf, uint32_t size);
+
void proc_sync_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len);

#endif /* __MCAP_INTERNAL_H */
diff --git a/mcap/mcap_sync.c b/mcap/mcap_sync.c
index 76f1377..569a40a 100644
--- a/mcap/mcap_sync.c
+++ b/mcap/mcap_sync.c
@@ -33,27 +33,6 @@
#include "mcap_lib.h"
#include "mcap_internal.h"

-static int send_unsupported_req(struct mcap_mcl *mcl, uint8_t oc)
-{
- uint8_t *rsp;
- mcap4B_rsp *rsp_err;
- int sent;
-
-
- rsp = g_malloc0(sizeof(mcap4B_rsp));
-
- rsp_err = (mcap4B_rsp *)rsp;
- rsp_err->op = oc;
- rsp_err->rc = MCAP_REQUEST_NOT_SUPPORTED;
- rsp_err->mdl = htons (MCAP_MDLID_RESERVED);
-
- sent = mcap_send_data(g_io_channel_unix_get_fd(mcl->cc),
- rsp,
- sizeof(mcap4B_rsp));
- g_free(rsp);
- return sent;
-}
-
void proc_sync_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
{
switch (cmd[0]) {
@@ -61,7 +40,6 @@ void proc_sync_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
DBG("TODO: received MCAP_MD_SYNC_CAP_REQ: %d",
MCAP_MD_SYNC_CAP_REQ);
/* Not implemented yet. Reply with unsupported request */
- send_unsupported_req(mcl, cmd[0]);
break;
case MCAP_MD_SYNC_CAP_RSP:
DBG("TODO: received MCAP_MD_SYNC_CAP_RSP: %d",
@@ -71,7 +49,6 @@ void proc_sync_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
DBG("TODO: received MCAP_MD_SYNC_SET_REQ: %d",
MCAP_MD_SYNC_SET_REQ);
/* Not implemented yet. Reply with unsupported request */
- send_unsupported_req(mcl, cmd[0]);
break;
case MCAP_MD_SYNC_SET_RSP:
DBG("TODO: received MCAP_MD_SYNC_SET_RSP: %d",
--
1.6.3.3


2010-07-22 08:58:11

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 54/60] Set MDL state to closed when a connection failed

---
mcap/mcap.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 788b565..e9d5d36 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1823,6 +1823,7 @@ static void confirm_dc_event_cb(GIOChannel *chan, gpointer user_data)
if (!bt_io_accept(chan, connect_dc_event_cb, mdl, NULL,
&err)) {
error("MDL accept error %s", err->message);
+ mdl->state = MDL_CLOSED;
g_error_free(err);
goto drop;
}
--
1.6.3.3


2010-07-22 08:58:10

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 53/60] Send error response when an unknown command is received.

If an invalid Op Code is received (i.e. neither a Standard Op Code
nor a Clock Synchronization Protocol Op Code), we will send an reply
using an "Invalid Op Code" and the Op Code field to ERROR_RSP
---
mcap/mcap.c | 49 +++++++++++++++++++++++++------------------------
1 files changed, 25 insertions(+), 24 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 30e0827..788b565 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -934,27 +934,6 @@ bdaddr_t mcap_mcl_get_addr(struct mcap_mcl *mcl)
return mcl->addr;
}

-static void error_cmd_rsp(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
-{
- uint16_t mdlr;
-
- if (cmd[0] <= MCAP_MD_DELETE_MDL_RSP) {
- /* Standard Op Code request is invalid in current state */
- error("Invalid cmd received (op code = %d) in state %d",
- cmd[0], mcl->state);
- /* Get previously mdlid sent to generate an appropriate
- * response if it is possible */
- mdlr = len < sizeof(mcap_md_req) ? MCAP_MDLID_RESERVED :
- ntohs(((mcap_md_req *)cmd)->mdl);
- send4B_cmd(mcl, cmd[0]+1, MCAP_INVALID_OPERATION, mdlr);
- } else {
- error("Unknown cmd request received (op code = %d) in state %d",
- cmd[0], mcl->state);
- send4B_cmd(mcl, MCAP_ERROR_RSP, MCAP_INVALID_OP_CODE,
- MCAP_MDLID_RESERVED);
- }
-}
-
static void mcap_delete_mdl(gpointer elem, gpointer user_data)
{
struct mcap_mdl *mdl = elem;
@@ -1194,6 +1173,19 @@ resp:
send4B_cmd(mcl, MCAP_MD_DELETE_MDL_RSP, MCAP_SUCCESS, mdlid);
}

+static void invalid_req_state(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
+{
+ uint16_t mdlr;
+
+ error("Invalid cmd received (op code = %d) in state %d", cmd[0],
+ mcl->state);
+ /* Get previously mdlid sent to generate an appropriate
+ * response if it is possible */
+ mdlr = len < sizeof(mcap_md_req) ? MCAP_MDLID_RESERVED :
+ ntohs(((mcap_md_req *)cmd)->mdl);
+ send4B_cmd(mcl, cmd[0]+1, MCAP_INVALID_OPERATION, mdlr);
+}
+
/* Function used to process commands depending of MCL state */
static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
{
@@ -1208,7 +1200,7 @@ static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
process_md_delete_mdl_req(mcl, cmd, len);
break;
default:
- error_cmd_rsp(mcl, cmd, len);
+ invalid_req_state(mcl, cmd, len);
}
}

@@ -1217,7 +1209,7 @@ static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
if (cmd[0] == MCAP_MD_ABORT_MDL_REQ)
process_md_abort_mdl_req(mcl, cmd, len);
else
- error_cmd_rsp(mcl, cmd, len);
+ invalid_req_state(mcl, cmd, len);
}

static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
@@ -1233,7 +1225,7 @@ static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
process_md_delete_mdl_req(mcl, cmd, len);
break;
default:
- error_cmd_rsp(mcl, cmd, len);
+ invalid_req_state(mcl, cmd, len);
}
}

@@ -1521,6 +1513,15 @@ static void proc_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
{
GError *gerr = NULL;

+ if (cmd[0] > MCAP_MD_SYNC_INFO_IND ||
+ (cmd[0] > MCAP_MD_DELETE_MDL_RSP &&
+ cmd[0] < MCAP_MD_SYNC_CAP_REQ)) {
+ error("Unknown cmd received (op code = %d)", cmd[0]);
+ send4B_cmd(mcl, MCAP_ERROR_RSP, MCAP_INVALID_OP_CODE,
+ MCAP_MDLID_RESERVED);
+ return;
+ }
+
if ((cmd[0] >= MCAP_MD_SYNC_CAP_REQ) &&
(cmd[0] <= MCAP_MD_SYNC_INFO_IND)) {
proc_sync_cmd(mcl, cmd, len);
--
1.6.3.3


2010-07-22 08:58:09

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 52/60] Avoid double insertion of the same MDL in an MCL

We don't have to insert an MDL in the list when we receive a
request to create a new data channel using a mdlid that it is
already created.
---
mcap/mcap.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 1e55bc7..30e0827 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1033,6 +1033,7 @@ static void process_md_create_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
mdl = g_malloc0(sizeof(struct mcap_mdl));
mdl->mcl = mcl;
mdl->mdlid = mdl_id;
+ mcl->mdls = g_slist_insert_sorted(mcl->mdls, mdl, compare_mdl);
} else if (mdl->state == MDL_CONNECTED) {
/* MCAP specification says that we should close the MCL if
* it is open when we receive a MD_CREATE_MDL_REQ */
@@ -1041,7 +1042,6 @@ static void process_md_create_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,

mdl->mdep_id = mdep_id;
mdl->state = MDL_WAITING;
- mcl->mdls = g_slist_insert_sorted(mcl->mdls, mdl, compare_mdl);

mcl->state = MCL_PENDING;
send5B_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_SUCCESS, mdl_id, conf);
--
1.6.3.3


2010-07-22 08:58:08

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 51/60] Change name for callback used to report status of delete and abort operations

---
mcap/mcap.c | 22 +++++++++++-----------
mcap/mcap_lib.h | 8 ++++----
2 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index e89b720..1e55bc7 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -54,7 +54,7 @@ struct connect_mcl {
typedef union {
mcap_mdl_operation_cb op;
mcap_mdl_operation_conf_cb op_conf;
- mcap_mdl_del_cb del;
+ mcap_mdl_notify_cb notify;
} mcap_cb_type;

struct mcap_mdl_op_cb {
@@ -266,7 +266,7 @@ static void mcap_notify_error(struct mcap_mcl *mcl, GError *err)
l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state);
shutdown_mdl(l->data);
update_mcl_state(mcl);
- con->cb.del(err, con->user_data);
+ con->cb.notify(err, con->user_data);
break;
case MCAP_MD_DELETE_MDL_REQ:
for (l = mcl->mdls; l; l = l->next) {
@@ -276,7 +276,7 @@ static void mcap_notify_error(struct mcap_mcl *mcl, GError *err)
MDL_CLOSED;
}
update_mcl_state(mcl);
- con->cb.del(err, con->user_data);
+ con->cb.notify(err, con->user_data);
break;
case MCAP_MD_RECONNECT_MDL_REQ:
st = MDL_WAITING;
@@ -549,7 +549,7 @@ static void send_delete_req(GError **err, struct mcap_mcl *mcl,
}

void mcap_req_mdl_delete_all(struct mcap_mcl *mcl, GError **err,
- mcap_mdl_del_cb delete_cb, gpointer user_data)
+ mcap_mdl_notify_cb delete_cb, gpointer user_data)
{
GSList *l;
struct mcap_mdl *mdl;
@@ -570,7 +570,7 @@ void mcap_req_mdl_delete_all(struct mcap_mcl *mcl, GError **err,

con = g_new0(struct mcap_mdl_op_cb, 1);
con->mdl = NULL;
- con->cb.del = delete_cb;
+ con->cb.notify = delete_cb;
con->user_data = user_data;

send_delete_req(err, mcl, con, MCAP_ALL_MDLIDS);
@@ -579,7 +579,7 @@ void mcap_req_mdl_delete_all(struct mcap_mcl *mcl, GError **err,
}

void mcap_req_mdl_deletion(struct mcap_mdl *mdl, GError **err,
- mcap_mdl_del_cb delete_cb, gpointer user_data)
+ mcap_mdl_notify_cb delete_cb, gpointer user_data)
{
struct mcap_mcl *mcl= mdl->mcl;
struct mcap_mdl_op_cb *con;
@@ -602,7 +602,7 @@ void mcap_req_mdl_deletion(struct mcap_mdl *mdl, GError **err,

con = g_new0(struct mcap_mdl_op_cb, 1);
con->mdl = mdl;
- con->cb.del = delete_cb;
+ con->cb.notify = delete_cb;
con->user_data = user_data;

send_delete_req(err, mcl, con, mdl->mdlid);
@@ -611,7 +611,7 @@ void mcap_req_mdl_deletion(struct mcap_mdl *mdl, GError **err,
}

void mcap_mdl_abort(struct mcap_mdl *mdl, GError **err,
- mcap_mdl_del_cb abort_cb, gpointer user_data)
+ mcap_mdl_notify_cb abort_cb, gpointer user_data)
{
struct mcap_mdl_op_cb *con;
struct mcap_mcl *mcl = mdl->mcl;
@@ -633,7 +633,7 @@ void mcap_mdl_abort(struct mcap_mdl *mdl, GError **err,
}

con->mdl = mdl;
- con->cb.del = abort_cb;
+ con->cb.notify = abort_cb;
con->user_data = user_data;

mcl->priv_data = con;
@@ -1395,7 +1395,7 @@ static gboolean process_md_abort_mdl_rsp(struct mcap_mcl *mcl,
uint8_t *cmd, uint32_t len)
{
struct mcap_mdl_op_cb *abrt = mcl->priv_data;
- mcap_mdl_del_cb abrt_cb = abrt->cb.del;
+ mcap_mdl_notify_cb abrt_cb = abrt->cb.notify;
gpointer user_data = abrt->user_data;
struct mcap_mdl *mdl = abrt->mdl;
mcap4B_rsp *rsp = (mcap4B_rsp *)cmd;
@@ -1444,7 +1444,7 @@ static gboolean process_md_delete_mdl_rsp(struct mcap_mcl *mcl, uint8_t *cmd,
{
struct mcap_mdl_op_cb *del = mcl->priv_data;
struct mcap_mdl *mdl = del->mdl;
- mcap_mdl_del_cb deleted_cb = del->cb.del;
+ mcap_mdl_notify_cb deleted_cb = del->cb.notify;
gpointer user_data = del->user_data;
mcap_md_req *cmdlast = (mcap_md_req *) mcl->lcmd;
uint16_t mdlid = ntohs(cmdlast->mdl);
diff --git a/mcap/mcap_lib.h b/mcap/mcap_lib.h
index afac8aa..3d6e0b6 100644
--- a/mcap/mcap_lib.h
+++ b/mcap/mcap_lib.h
@@ -79,7 +79,7 @@ typedef void (* mcap_mdl_operation_conf_cb) (struct mcap_mdl *mdl, uint8_t conf,
GError *err, gpointer data);
typedef void (* mcap_mdl_operation_cb) (struct mcap_mdl *mdl, GError *err,
gpointer data);
-typedef void (* mcap_mdl_del_cb) (GError *err, gpointer data);
+typedef void (* mcap_mdl_notify_cb) (GError *err, gpointer data);

/* Next function should return an MCAP appropriate response code */
typedef uint8_t (* mcap_remote_mdl_conn_req_cb) (struct mcap_mcl *mcl,
@@ -108,9 +108,9 @@ void mcap_req_mdl_reconnect(struct mcap_mdl *mdl, GError **err,
mcap_mdl_operation_cb reconnect_cb,
gpointer user_data);
void mcap_req_mdl_delete_all(struct mcap_mcl *mcl, GError **err,
- mcap_mdl_del_cb delete_cb, gpointer user_data);
+ mcap_mdl_notify_cb delete_cb, gpointer user_data);
void mcap_req_mdl_deletion(struct mcap_mdl *mdl, GError **err,
- mcap_mdl_del_cb delete_cb, gpointer user_data);
+ mcap_mdl_notify_cb delete_cb, gpointer user_data);
void mcap_mdl_connect(struct mcap_mdl *mdl,
BtIOType BtType,
uint16_t dcpsm,
@@ -118,7 +118,7 @@ void mcap_mdl_connect(struct mcap_mdl *mdl,
mcap_mdl_operation_cb connect_cb,
gpointer user_data);
void mcap_mdl_abort(struct mcap_mdl *mdl, GError **err,
- mcap_mdl_del_cb abort_cb, gpointer user_data);
+ mcap_mdl_notify_cb abort_cb, gpointer user_data);

int mcap_mdl_get_fd(struct mcap_mdl *mdl);
uint16_t mcap_mdl_get_mdlid(struct mcap_mdl *mdl);
--
1.6.3.3


2010-07-22 08:58:06

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 49/60] Restore state in MCL whenever an error takes place.

---
mcap/mcap.c | 55 +++++++++++++++++++++++--------------------------------
1 files changed, 23 insertions(+), 32 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 434d50f..e8a93a1 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -241,8 +241,7 @@ static gint cmp_mdl_state(gconstpointer a, gconstpointer b)
return 1;
}

-static void mcap_notify_error(struct mcap_mcl *mcl, GError *err,
- gboolean restore)
+static void mcap_notify_error(struct mcap_mcl *mcl, GError *err)
{
struct mcap_mdl_op_cb *con = mcl->priv_data;
struct mcap_mdl *mdl;
@@ -254,44 +253,36 @@ static void mcap_notify_error(struct mcap_mcl *mcl, GError *err,

switch (mcl->lcmd[0]){
case MCAP_MD_CREATE_MDL_REQ:
- if (restore) {
- st = MDL_WAITING;
- l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state);
- mdl = l->data;
- mcl->mdls = g_slist_remove(mcl->mdls, mdl);
- g_free(mdl);
- update_mcl_state(mcl);
- }
+ st = MDL_WAITING;
+ l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state);
+ mdl = l->data;
+ mcl->mdls = g_slist_remove(mcl->mdls, mdl);
+ g_free(mdl);
+ update_mcl_state(mcl);
con->cb.op_conf(NULL, 0, err, con->user_data);
break;
case MCAP_MD_ABORT_MDL_REQ:
- if (restore) {
- st = MDL_WAITING;
- l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state);
- shutdown_mdl(l->data);
- update_mcl_state(mcl);
- }
+ st = MDL_WAITING;
+ l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state);
+ shutdown_mdl(l->data);
+ update_mcl_state(mcl);
con->cb.del(err, con->user_data);
break;
case MCAP_MD_DELETE_MDL_REQ:
- if (restore) {
- for (l = mcl->mdls; l; l = l->next) {
- mdl = l->data;
- if (mdl->state == MDL_DELETING)
- mdl->state = (mdl->dc) ? MDL_CONNECTED :
+ for (l = mcl->mdls; l; l = l->next) {
+ mdl = l->data;
+ if (mdl->state == MDL_DELETING)
+ mdl->state = (mdl->dc) ? MDL_CONNECTED :
MDL_CLOSED;
- }
- update_mcl_state(mcl);
}
+ update_mcl_state(mcl);
con->cb.del(err, con->user_data);
break;
case MCAP_MD_RECONNECT_MDL_REQ:
- if (restore) {
- st = MDL_WAITING;
- l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state);
- shutdown_mdl(l->data);
- update_mcl_state(mcl);
- }
+ st = MDL_WAITING;
+ l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state);
+ shutdown_mdl(l->data);
+ update_mcl_state(mcl);
con->cb.op(NULL, err, con->user_data);
break;
}
@@ -446,7 +437,7 @@ static gboolean wait_response_timer(gpointer data)
g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_FAILED,
"Timeout waiting response");

- mcap_notify_error(mcl, gerr, FALSE);
+ mcap_notify_error(mcl, gerr);

g_error_free(gerr);
mcl->ms->mcl_disconnected_cb(mcl, mcl->ms->user_data);
@@ -1551,7 +1542,7 @@ static void proc_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
mcl->req = MCL_AVAILABLE;
g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_REQ_IGNORED,
"Initiator sent a request with more priority");
- mcap_notify_error(mcl, gerr, TRUE);
+ mcap_notify_error(mcl, gerr);
return;
}
proc_response(mcl, cmd, len);
@@ -1665,7 +1656,7 @@ fail:
/* notify error in pending callback */
g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_MCL_CLOSED,
"MCL closed");
- mcap_notify_error(mcl, gerr, TRUE);
+ mcap_notify_error(mcl, gerr);
g_error_free(gerr);
}
mcl->ms->mcl_disconnected_cb(mcl, mcl->ms->user_data);
--
1.6.3.3


2010-07-22 08:58:07

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 50/60] Check control channel before calling to g_io_channel_unix_get_fd

Glib does not return file descriptor -1 when a NULL pointer is passed
as parameter in g_io_channel_unix_get_fd function. Pointer parameter
is deferrence in glib without checking NULL
---
mcap/mcap.c | 15 +++++++++------
1 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index e8a93a1..e89b720 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -312,7 +312,7 @@ static int send4B_cmd(struct mcap_mcl *mcl, uint8_t oc, uint8_t rc,
{
uint8_t *rsp;
mcap4B_rsp *rsp_err;
- int sent;
+ int sent = -1;


rsp = g_malloc0(sizeof(mcap4B_rsp));
@@ -322,9 +322,9 @@ static int send4B_cmd(struct mcap_mcl *mcl, uint8_t oc, uint8_t rc,
rsp_err->rc = rc;
rsp_err->mdl = htons (mdl);

- sent = mcap_send_data(g_io_channel_unix_get_fd(mcl->cc),
- rsp,
- sizeof(mcap4B_rsp));
+ if (mcl->cc)
+ sent = mcap_send_data(g_io_channel_unix_get_fd(mcl->cc), rsp,
+ sizeof(mcap4B_rsp));
g_free(rsp);
return sent;
}
@@ -334,7 +334,7 @@ static int send5B_cmd(struct mcap_mcl *mcl, uint8_t oc, uint8_t rc,
{
uint8_t *rsp;
mcap5B_rsp *suc;
- int sent;
+ int sent = -1;

rsp = g_malloc0(sizeof(mcap5B_rsp));

@@ -344,7 +344,8 @@ static int send5B_cmd(struct mcap_mcl *mcl, uint8_t oc, uint8_t rc,
suc->mdl = htons(mdl);
suc->param = param;

- sent = mcap_send_data(g_io_channel_unix_get_fd(mcl->cc), rsp,
+ if (mcl->cc)
+ sent = mcap_send_data(g_io_channel_unix_get_fd(mcl->cc), rsp,
sizeof(mcap5B_rsp));
g_free(rsp);
return sent;
@@ -962,6 +963,7 @@ static void mcap_delete_mdl(gpointer elem, gpointer user_data)
shutdown_mdl(mdl);
if (notify)
mdl->mcl->cb->mdl_deleted(mdl, mdl->mcl->cb->user_data);
+
g_free(mdl);
}

@@ -1187,6 +1189,7 @@ static void process_md_delete_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
update_mcl_state(mcl);
notify = TRUE;
mcap_delete_mdl(mdl, &notify);
+
resp:
send4B_cmd(mcl, MCAP_MD_DELETE_MDL_RSP, MCAP_SUCCESS, mdlid);
}
--
1.6.3.3


Subject: [PATCH 24/60] Enable connection of Data Channel with remote MCAP instances

From: José Antonio Santos-Cadenas <[email protected]>

---
mcap/mcap.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 60 insertions(+), 0 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 61d6621..b70545a 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1558,6 +1558,66 @@ static gboolean mdl_event_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
return FALSE;
}

+static void mcap_connect_mdl_cb(GIOChannel *chan, GError *conn_err,
+ gpointer data)
+{
+ struct mcap_mdl_op_cb *con = data;
+ struct mcap_mdl *mdl = con->mdl;
+ mcap_mdl_operation_cb cb = con->cb.op;
+ gpointer user_data = con->user_data;
+
+ g_free(con);
+ DBG("mdl connect callback");
+
+ if (conn_err) {
+ DBG("ERROR: mdl connect callback");
+ mdl->state = MDL_CLOSED;
+ g_io_channel_unref(mdl->dc);
+ mdl->dc = NULL;
+ cb(mdl, conn_err, user_data);
+ return;
+ }
+
+ mdl->state = MDL_CONNECTED;
+ mdl->wid = g_io_add_watch(mdl->dc, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ (GIOFunc) mdl_event_cb, mdl);
+
+ cb(mdl, conn_err, user_data);
+}
+
+void mcap_mdl_connect(struct mcap_mdl *mdl, BtIOType BtType, uint16_t dcpsm,
+ GError **err, mcap_mdl_operation_cb connect_cb, gpointer user_data)
+{
+ struct mcap_mdl_op_cb *con;
+
+ if (mdl->state != MDL_WAITING) {
+ g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_MDL,
+ "%s", error2str(MCAP_INVALID_MDL));
+ return;
+ }
+
+ con = g_new0(struct mcap_mdl_op_cb, 1);
+ con->mdl = mdl;
+ con->cb.op = connect_cb;
+ con->user_data = user_data;
+
+ /* TODO: Check if BtIOType is ERTM or Streaming before continue */
+
+ mdl->dc = bt_io_connect(BtType, mcap_connect_mdl_cb, con,
+ NULL, err,
+ BT_IO_OPT_SOURCE_BDADDR, &mdl->mcl->ms->src,
+ BT_IO_OPT_DEST_BDADDR, &mdl->mcl->addr,
+ BT_IO_OPT_PSM, dcpsm,
+ BT_IO_OPT_MTU, MCAP_DC_MTU,
+ BT_IO_OPT_SEC_LEVEL, mdl->mcl->ms->sec,
+ BT_IO_OPT_INVALID);
+ if (*err) {
+ DBG("MDL Connection error");
+ mdl->state = MDL_CLOSED;
+ g_free(con);
+ }
+}
+
static gboolean mcl_control_cb(GIOChannel *chan, GIOCondition cond,
gpointer data)
{
--
1.6.3.3


Subject: [PATCH 35/60] Remove magic number to check commands of 5 Bytes

From: José Antonio Santos-Cadenas <[email protected]>

---
mcap/mcap.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index d3c92dc..f408cbf 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1262,7 +1262,7 @@ static gboolean process_md_create_mdl_rsp(struct mcap_mcl *mcl,
if (gerr)
goto fail;

- if (len < 5) {
+ if (len < sizeof(mcap5B_rsp)) {
g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_FAILED,
"Protocol error");
close = TRUE;
--
1.6.3.3


Subject: [PATCH 28/60] Solve a non initialized memory segmentation fault

---
mcap/mcap.c | 3 +--
1 files changed, 1 insertions(+), 2 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 7098a8d..cf92368 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1412,6 +1412,7 @@ static gboolean check_rsp(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
mcap4B_rsp *rsp;
GError *gerr = NULL;

+ rsp = (mcap4B_rsp *)cmd;
/* Check if the response matches with the last request */
if ((cmd[0] != MCAP_ERROR_RSP) && ((mcl->lcmd[0] + 1) != cmd[0]))
goto close_mcl;
@@ -1419,8 +1420,6 @@ static gboolean check_rsp(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
if (len < 4)
goto close_mcl;

- rsp = (mcap4B_rsp *)cmd;
-
if (rsp->rc == MCAP_REQUEST_NOT_SUPPORTED) {
DBG("Remote does not support opcodes");
g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_REQUEST_NOT_SUPPORTED,
--
1.6.3.3


Subject: [PATCH 37/60] Remove MDL when delete operation fails with INVALID_MDL response code

From: José Antonio Santos-Cadenas <[email protected]>

---
mcap/mcap.c | 23 ++++++++++++++++-------
1 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 63058d1..87aa233 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1385,6 +1385,7 @@ static gboolean process_md_delete_mdl_rsp(struct mcap_mcl *mcl, uint8_t *cmd,
gpointer user_data = del->user_data;
mcap_md_req *cmdlast = (mcap_md_req *) mcl->lcmd;
uint16_t mdlid = ntohs(cmdlast->mdl);
+ mcap4B_rsp *rsp = (mcap4B_rsp *)cmd;
GError *gerr = NULL;
gboolean close = FALSE;
gboolean notify = FALSE;
@@ -1397,14 +1398,20 @@ static gboolean process_md_delete_mdl_rsp(struct mcap_mcl *mcl, uint8_t *cmd,
g_free(mcl->lcmd);
mcl->lcmd = NULL;
mcl->req = MCL_AVAILABLE;
+
if (gerr) {
- if (mdl)
- restore_mdl(mdl, NULL);
- else
+ if (!mdl) {
+ /* Deletion of all mdls failed */
g_slist_foreach(mcl->mdls, restore_mdl, NULL);
- deleted_cb(gerr, user_data);
- g_error_free(gerr);
- return close;
+ } else if ((len >= MIN_RSP_LEN) &&
+ (rsp->rc == MCAP_INVALID_MDL)) {
+ /* Mdl does not exist in remote side */
+ goto del_mdl;
+ } else {
+ /* this mdl couldn't be deleted */
+ restore_mdl(mdl, NULL);
+ }
+ goto end;
}

if (mdlid == MCAP_ALL_MDLIDS) {
@@ -1414,12 +1421,14 @@ static gboolean process_md_delete_mdl_rsp(struct mcap_mcl *mcl, uint8_t *cmd,
mcl->state = MCL_CONNECTED;
goto end;
}
-
+del_mdl:
mcl->mdls = g_slist_remove(mcl->mdls, mdl);
update_mcl_state(mcl);
mcap_delete_mdl(mdl, &notify);
end:
deleted_cb(gerr, user_data);
+ if (gerr)
+ g_error_free(gerr);
return close;
}

--
1.6.3.3


Subject: [PATCH 36/60] Set MDL to closed when abort operation takes place

From: José Antonio Santos-Cadenas <[email protected]>

---
mcap/mcap.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index f408cbf..63058d1 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1349,6 +1349,7 @@ static gboolean process_md_abort_mdl_rsp(struct mcap_mcl *mcl,
mcl->req = MCL_AVAILABLE;

abrt_cb(gerr, user_data);
+ shutdown_mdl(mdl);

if ((len >= MIN_RSP_LEN) && (rsp->rc == MCAP_INVALID_MDL)) {
mcl->mdls = g_slist_remove(mcl->mdls, mdl);
--
1.6.3.3


Subject: [PATCH 39/60] Fix double memory free on simultaneus deletion of MDLs

From: José Antonio Santos-Cadenas <[email protected]>

---
mcap/mcap.c | 7 ++++++-
1 files changed, 6 insertions(+), 1 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index d268bf6..51f0d87 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1130,7 +1130,12 @@ static void process_md_delete_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
mcl->mdls = g_slist_remove(mcl->mdls, mdl);
update_mcl_state(mcl);
notify = TRUE;
- mcap_delete_mdl(mdl, &notify);
+ if (mdl->state == MDL_DELETING) {
+ /* Remote deviced requests deleting an MDL that upper profile
+ * tries to delete, MDL will be freed when reply arrives. */
+ mdl->mcl->cb->mdl_deleted(mdl, mdl->mcl->cb->user_data);
+ } else
+ mcap_delete_mdl(mdl, &notify);
resp:
send4B_cmd(mcl, MCAP_MD_DELETE_MDL_RSP, MCAP_SUCCESS, mdlid);
}
--
1.6.3.3


Subject: [PATCH 47/60] Random generation of first mdlid used as based to create data channels

From: José Antonio Santos-Cadenas <[email protected]>

Add random mdlid generation to avoid mdlid collisions when
two instances create a data channel at the same time.
---
mcap/mcap.c | 53 ++++++++++++++++++++++++++-----------------------
mcap/mcap_internal.h | 1 +
2 files changed, 29 insertions(+), 25 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 3f3268b..f164e76 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -28,6 +28,7 @@
#include "error.h"

#include <netinet/in.h>
+#include <stdlib.h>

#include "mcap.h"
#include "mcap_lib.h"
@@ -358,24 +359,37 @@ static int send5B_cmd(struct mcap_mcl *mcl, uint8_t oc, uint8_t rc,
return sent;
}

-static uint16_t generate_mdlid(struct mcap_mcl *mcl)
+static struct mcap_mdl *get_mdl(struct mcap_mcl *mcl, uint16_t mdlid)
{
- uint16_t mdlid = MCAP_MDLID_INITIAL;
- struct mcap_mdl *mdl;
GSList *l;
+ struct mcap_mdl *mdl;

for (l = mcl->mdls; l; l = l->next) {
mdl = l->data;
- if (mdlid < mdl->mdlid)
- break;
- else
- mdlid = mdl->mdlid + 1;
+ if (mdlid == mdl->mdlid)
+ return mdl;
}

- if (mdlid > MCAP_MDLID_FINAL)
- return 0;
+ return NULL;
+}
+
+static uint16_t generate_mdlid(struct mcap_mcl *mcl)
+{
+ uint16_t mdlid = mcl->next_mdl;
+ struct mcap_mdl *mdl;

- return mdlid;
+ do {
+ DBG("Testing %d", mdlid);
+ mdl = get_mdl(mcl, mdlid);
+ if (!mdl) {
+ mcl->next_mdl = (mdlid % MCAP_MDLID_FINAL) + 1;
+ return mdlid;
+ } else
+ mdlid = (mdlid % MCAP_MDLID_FINAL) + 1;
+ } while (mdlid != mcl->next_mdl);
+
+ /* No more mdlids availables */
+ return 0;
}

static uint8_t *create_req(uint8_t op, uint16_t mdl_id)
@@ -949,20 +963,6 @@ static void error_cmd_rsp(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
}
}

-static struct mcap_mdl *get_mdl(struct mcap_mcl *mcl, uint16_t mdlid)
-{
- GSList *l;
- struct mcap_mdl *mdl;
-
- for (l = mcl->mdls; l; l = l->next) {
- mdl = l->data;
- if (mdlid == mdl->mdlid)
- return mdl;
- }
-
- return NULL;
-}
-
static void mcap_delete_mdl(gpointer elem, gpointer user_data)
{
struct mcap_mdl *mdl = elem;
@@ -1764,6 +1764,7 @@ void mcap_create_mcl(struct mcap_instance *ms,
mcl->state = MCL_IDLE;
bacpy(&mcl->addr, addr);
set_default_cb(mcl);
+ mcl->next_mdl = (rand() % MCAP_MDLID_FINAL) + 1;
mcl = mcap_mcl_ref(mcl);
} else
mcl->ctrl |= MCAP_CTRL_CONN;
@@ -1899,6 +1900,7 @@ static void confirm_mcl_event_cb(GIOChannel *chan, gpointer user_data)
mcl->ms = ms;
bacpy(&mcl->addr, &dst);
set_default_cb(mcl);
+ mcl->next_mdl = (rand() % MCAP_MDLID_FINAL) + 1;
mcl = mcap_mcl_ref(mcl);
}

@@ -1983,7 +1985,8 @@ struct mcap_instance *mcap_create_instance(struct btd_adapter *btd_adapter,
g_free(ms);
return NULL;
}
-
+ /* Initialize random seed to generate mdlids for this instance */
+ srand(time(NULL));
return ms;
}

diff --git a/mcap/mcap_internal.h b/mcap/mcap_internal.h
index 3aaeed5..9dacc12 100644
--- a/mcap/mcap_internal.h
+++ b/mcap/mcap_internal.h
@@ -94,6 +94,7 @@ struct mcap_mcl {
uint8_t *lcmd; /* Last command sent */
guint ref; /* References counter */
uint8_t ctrl; /* MCL control flag */
+ uint16_t next_mdl; /* id used to create next MDL */
};

#define MCAP_CTRL_CACHED 0x01 /* MCL is cached */
--
1.6.3.3


Subject: [PATCH 46/60] Process received command in base to previous request sent

From: José Antonio Santos-Cadenas <[email protected]>

---
mcap/mcap.c | 12 +++++++-----
1 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 18220bc..3f3268b 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1254,6 +1254,12 @@ static gboolean check_err_rsp(struct mcap_mcl *mcl, uint8_t *cmd,
mcap4B_rsp *rsp;
char *msg;

+ if (cmd[0] == MCAP_ERROR_RSP) {
+ msg = "MCAP_ERROR_RSP received";
+ close = TRUE;
+ goto fail;
+ }
+
/* Check if the response matches with the last request */
if ((rlen < MIN_RSP_LEN) || ((mcl->lcmd[0] + 1) != cmd[0])) {
msg = "Protocol error";
@@ -1492,11 +1498,7 @@ static void proc_response(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
gboolean close;
RELEASE_TIMER(mcl);

- switch (cmd[0]) {
- case MCAP_ERROR_RSP:
- error("MCAP_ERROR_RSP received");
- close = TRUE;
- break;
+ switch (mcl->lcmd[0] + 1) {
case MCAP_MD_CREATE_MDL_RSP:
close = process_md_create_mdl_rsp(mcl, cmd, len);
break;
--
1.6.3.3


Subject: [PATCH 48/60] Notify MCL closed when there is a pending callback

From: José Antonio Santos-Cadenas <[email protected]>

---
mcap/mcap.c | 11 ++++++++++-
mcap/mcap_lib.h | 1 +
2 files changed, 11 insertions(+), 1 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index f164e76..434d50f 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1643,6 +1643,7 @@ void mcap_mdl_connect(struct mcap_mdl *mdl, BtIOType BtType, uint16_t dcpsm,
static gboolean mcl_control_cb(GIOChannel *chan, GIOCondition cond,
gpointer data)
{
+ GError *gerr = NULL;

struct mcap_mcl *mcl = data;
int sk, len;
@@ -1659,8 +1660,16 @@ static gboolean mcl_control_cb(GIOChannel *chan, GIOCondition cond,
proc_cmd(mcl, buf, (uint32_t)len);
return TRUE;
fail:
- if (mcl->state != MCL_IDLE)
+ if (mcl->state != MCL_IDLE) {
+ if (mcl->req == MCL_WAITING_RSP) {
+ /* notify error in pending callback */
+ g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_MCL_CLOSED,
+ "MCL closed");
+ mcap_notify_error(mcl, gerr, TRUE);
+ g_error_free(gerr);
+ }
mcl->ms->mcl_disconnected_cb(mcl, mcl->ms->user_data);
+ }
mcap_cache_mcl(mcl);
return FALSE;
}
diff --git a/mcap/mcap_lib.h b/mcap/mcap_lib.h
index 67c2f29..afac8aa 100644
--- a/mcap/mcap_lib.h
+++ b/mcap/mcap_lib.h
@@ -52,6 +52,7 @@ typedef enum {
MCAP_ERROR_INVALID_ARGS,
MCAP_ERROR_ALREADY_EXISTS,
MCAP_ERROR_REQ_IGNORED,
+ MCAP_ERROR_MCL_CLOSED,
MCAP_ERROR_FAILED
} McapError;

--
1.6.3.3


Subject: [PATCH 42/60] Move assignment of data channel configuration

---
mcap/mcap.c | 5 ++---
1 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 1d33452..ff6766d 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -955,8 +955,6 @@ static void process_md_create_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
return;
}

- cfga = conf = req->conf;
-
mdl = get_mdl(mcl, mdl_id);
if (mdl && mdl->state == MDL_WAITING) {
/* A remote petition is also triying to connect this mdl_id
@@ -964,7 +962,9 @@ static void process_md_create_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
send4B_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_MDL_BUSY, mdl_id);
return;
}
+
/* Callback to upper layer */
+ cfga = conf = req->conf;
rsp = mcl->cb->mdl_conn_req(mcl, mdep_id, mdl_id, &conf,
mcl->cb->user_data);
if (mcl->state == MCL_IDLE) {
@@ -985,7 +985,6 @@ static void process_md_create_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
return;
}

-
if (!mdl) {
mdl = g_malloc0(sizeof(struct mcap_mdl));
mdl->mcl = mcl;
--
1.6.3.3


Subject: [PATCH 45/60] Fix double reconnection problem using the same mdlid

From: José Antonio Santos-Cadenas <[email protected]>

---
mcap/mcap.c | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index a2cfa8c..18220bc 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1076,6 +1076,12 @@ static void process_md_reconnect_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
send4B_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP,
MCAP_INVALID_MDL, mdl_id);
return;
+ } else if (mdl->state == MDL_WAITING || mdl->state == MDL_DELETING ) {
+ /* Creation request arrives for a MDL that is being managed
+ * at current moment */
+ send4B_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_MDL_BUSY,
+ mdl_id);
+ return;
}

/* Callback to upper layer */
--
1.6.3.3


Subject: [PATCH 44/60] Restore state after INITIATOR ignore a request

From: José Antonio Santos-Cadenas <[email protected]>

When ACEPTOR receives a request when an outstanding request is
pending it should reply to the INITIATOR and restore previous state
if it is needed.
---
mcap/mcap.c | 140 ++++++++++++++++++++++++++++++++++++++++--------------
mcap/mcap_lib.h | 1 +
2 files changed, 104 insertions(+), 37 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 7bea1ad..a2cfa8c 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -194,28 +194,112 @@ static void mcap_send_std_opcode(struct mcap_mcl *mcl, uint8_t *cmd,
mcl->req = MCL_WAITING_RSP;
}

-static void mcap_notify_error(struct mcap_mcl *mcl, GError *err)
+static void update_mcl_state(struct mcap_mcl *mcl)
+{
+ GSList *l;
+ struct mcap_mdl *mdl;
+
+ if (mcl->state == MCL_PENDING)
+ return;
+
+ for (l = mcl->mdls; l; l = l->next) {
+ mdl = l->data;
+
+ if (mdl->state == MDL_CONNECTED) {
+ mcl->state = MCL_ACTIVE;
+ return;
+ }
+ }
+
+ mcl->state = MCL_CONNECTED;
+}
+
+static void shutdown_mdl(struct mcap_mdl *mdl)
+{
+ mdl->state = MDL_CLOSED;
+
+ g_source_remove(mdl->wid);
+
+ if (mdl->dc) {
+ g_io_channel_shutdown(mdl->dc, TRUE, NULL);
+ g_io_channel_unref(mdl->dc);
+ mdl->dc = NULL;
+ }
+}
+
+static gint cmp_mdl_state(gconstpointer a, gconstpointer b)
+{
+ const struct mcap_mdl *mdl = a;
+ const MDLState *st = b;
+
+ if (mdl->state == *st)
+ return 0;
+ else if (mdl->state < *st)
+ return -1;
+ else
+ return 1;
+}
+
+static void mcap_notify_error(struct mcap_mcl *mcl, GError *err,
+ gboolean restore)
{
struct mcap_mdl_op_cb *con = mcl->priv_data;
+ struct mcap_mdl *mdl;
+ MDLState st;
+ GSList *l;

if (!con || !mcl->lcmd)
return;

switch (mcl->lcmd[0]){
case MCAP_MD_CREATE_MDL_REQ:
+ if (restore) {
+ st = MDL_WAITING;
+ l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state);
+ mdl = l->data;
+ mcl->mdls = g_slist_remove(mcl->mdls, mdl);
+ g_free(mdl);
+ update_mcl_state(mcl);
+ }
con->cb.op_conf(NULL, 0, err, con->user_data);
break;
case MCAP_MD_ABORT_MDL_REQ:
+ if (restore) {
+ st = MDL_WAITING;
+ l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state);
+ shutdown_mdl(l->data);
+ update_mcl_state(mcl);
+ }
+ con->cb.del(err, con->user_data);
+ break;
case MCAP_MD_DELETE_MDL_REQ:
+ if (restore) {
+ for (l = mcl->mdls; l; l = l->next) {
+ mdl = l->data;
+ if (mdl->state == MDL_DELETING)
+ mdl->state = (mdl->dc) ? MDL_CONNECTED :
+ MDL_CLOSED;
+ }
+ update_mcl_state(mcl);
+ }
con->cb.del(err, con->user_data);
break;
case MCAP_MD_RECONNECT_MDL_REQ:
+ if (restore) {
+ st = MDL_WAITING;
+ l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state);
+ shutdown_mdl(l->data);
+ update_mcl_state(mcl);
+ }
con->cb.op(NULL, err, con->user_data);
break;
}

g_free(mcl->priv_data);
mcl->priv_data = NULL;
+
+ g_free(mcl->lcmd);
+ mcl->lcmd = NULL;
}

int mcap_send_data(int sock, const uint8_t *buf, uint32_t size)
@@ -348,7 +432,7 @@ static gboolean wait_response_timer(gpointer data)
g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_FAILED,
"Timeout waiting response");

- mcap_notify_error(mcl, gerr);
+ mcap_notify_error(mcl, gerr, FALSE);

g_error_free(gerr);
mcl->ms->mcl_disconnected_cb(mcl, mcl->ms->user_data);
@@ -552,26 +636,6 @@ void mcap_mdl_abort(struct mcap_mdl *mdl, GError **err,
mcl);
}

-static void update_mcl_state(struct mcap_mcl *mcl)
-{
- GSList *l;
- struct mcap_mdl *mdl;
-
- if (mcl->state == MCL_PENDING)
- return;
-
- for (l = mcl->mdls; l; l = l->next) {
- mdl = l->data;
-
- if (mdl->state == MDL_CONNECTED) {
- mcl->state = MCL_ACTIVE;
- return;
- }
- }
-
- mcl->state = MCL_CONNECTED;
-}
-
static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr)
{
GSList *l;
@@ -603,19 +667,6 @@ uint16_t mcap_mdl_get_mdlid(struct mcap_mdl *mdl)
return mdl->mdlid;
}

-static void shutdown_mdl(struct mcap_mdl *mdl)
-{
- mdl->state = MDL_CLOSED;
-
- g_source_remove(mdl->wid);
-
- if (mdl->dc) {
- g_io_channel_shutdown(mdl->dc, TRUE, NULL);
- g_io_channel_unref(mdl->dc);
- mdl->dc = NULL;
- }
-}
-
static void mcap_free_mdls(struct mcap_mcl *mcl, gboolean save)
{
GSList *l;
@@ -955,6 +1006,14 @@ static void process_md_create_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
return;
}

+ mdl = get_mdl(mcl, mdl_id);
+ if (mdl && (mdl->state == MDL_WAITING || mdl->state == MDL_DELETING )) {
+ /* Creation request arrives for a MDL that is being managed
+ * at current moment */
+ send4B_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_MDL_BUSY, mdl_id);
+ return;
+ }
+
cfga = conf = req->conf;
/* Callback to upper layer */
rsp = mcl->cb->mdl_conn_req(mcl, mdep_id, mdl_id, &conf,
@@ -977,7 +1036,6 @@ static void process_md_create_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
return;
}

- mdl = get_mdl(mcl, mdl_id);
if (!mdl) {
mdl = g_malloc0(sizeof(struct mcap_mdl));
mdl->mcl = mcl;
@@ -987,6 +1045,7 @@ static void process_md_create_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
* it is open when we receive a MD_CREATE_MDL_REQ */
shutdown_mdl(mdl);
}
+
mdl->mdep_id = mdep_id;
mdl->state = MDL_WAITING;
mcl->mdls = g_slist_insert_sorted(mcl->mdls, mdl, compare_mdl);
@@ -1458,6 +1517,8 @@ static void proc_response(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)

static void proc_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
{
+ GError *gerr = NULL;
+
if ((cmd[0] >= MCAP_MD_SYNC_CAP_REQ) &&
(cmd[0] <= MCAP_MD_SYNC_INFO_IND)) {
proc_sync_cmd(mcl, cmd, len);
@@ -1476,8 +1537,13 @@ static void proc_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
if (mcl->role == MCL_INITIATOR)
/* ignore */
return;
- proc_req[mcl->state](mcl, cmd, len);
/* Initiator will ignore our last request */
+ proc_req[mcl->state](mcl, cmd, len);
+ RELEASE_TIMER(mcl);
+ mcl->req = MCL_AVAILABLE;
+ g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_REQ_IGNORED,
+ "Initiator sent a request with more priority");
+ mcap_notify_error(mcl, gerr, TRUE);
return;
}
proc_response(mcl, cmd, len);
diff --git a/mcap/mcap_lib.h b/mcap/mcap_lib.h
index 2283dac..67c2f29 100644
--- a/mcap/mcap_lib.h
+++ b/mcap/mcap_lib.h
@@ -51,6 +51,7 @@ typedef enum {
/* MCAP Internal Errors */
MCAP_ERROR_INVALID_ARGS,
MCAP_ERROR_ALREADY_EXISTS,
+ MCAP_ERROR_REQ_IGNORED,
MCAP_ERROR_FAILED
} McapError;

--
1.6.3.3


Subject: [PATCH 43/60] Acceptor should not resend commands

From: José Antonio Santos-Cadenas <[email protected]>

Acceptor of the MCL should not send the last commands sent when there
is an outstanding request.
---
mcap/mcap.c | 72 +++++++++--------------------------------------------------
1 files changed, 11 insertions(+), 61 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index ff6766d..7bea1ad 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -955,16 +955,8 @@ static void process_md_create_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
return;
}

- mdl = get_mdl(mcl, mdl_id);
- if (mdl && mdl->state == MDL_WAITING) {
- /* A remote petition is also triying to connect this mdl_id
- * so the petition is rejected by the moment */
- send4B_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_MDL_BUSY, mdl_id);
- return;
- }
-
- /* Callback to upper layer */
cfga = conf = req->conf;
+ /* Callback to upper layer */
rsp = mcl->cb->mdl_conn_req(mcl, mdep_id, mdl_id, &conf,
mcl->cb->user_data);
if (mcl->state == MCL_IDLE) {
@@ -985,6 +977,7 @@ static void process_md_create_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
return;
}

+ mdl = get_mdl(mcl, mdl_id);
if (!mdl) {
mdl = g_malloc0(sizeof(struct mcap_mdl));
mdl->mcl = mcl;
@@ -1137,12 +1130,7 @@ static void process_md_delete_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
mcl->mdls = g_slist_remove(mcl->mdls, mdl);
update_mcl_state(mcl);
notify = TRUE;
- if (mdl->state == MDL_DELETING) {
- /* Remote deviced requests deleting an MDL that upper profile
- * is trying to delete, MDL will be freed when reply arrives. */
- mdl->mcl->cb->mdl_deleted(mdl, mdl->mcl->cb->user_data);
- } else
- mcap_delete_mdl(mdl, &notify);
+ mcap_delete_mdl(mdl, &notify);
resp:
send4B_cmd(mcl, MCAP_MD_DELETE_MDL_RSP, MCAP_SUCCESS, mdlid);
}
@@ -1395,7 +1383,6 @@ static gboolean process_md_delete_mdl_rsp(struct mcap_mcl *mcl, uint8_t *cmd,
gpointer user_data = del->user_data;
mcap_md_req *cmdlast = (mcap_md_req *) mcl->lcmd;
uint16_t mdlid = ntohs(cmdlast->mdl);
- mcap4B_rsp *rsp = (mcap4B_rsp *)cmd;
GError *gerr = NULL;
gboolean close = FALSE;
gboolean notify = FALSE;
@@ -1410,23 +1397,13 @@ static gboolean process_md_delete_mdl_rsp(struct mcap_mcl *mcl, uint8_t *cmd,
mcl->req = MCL_AVAILABLE;

if (gerr) {
- if (!mdl) {
- /* Deletion of all mdls failed */
- g_slist_foreach(mcl->mdls, restore_mdl, NULL);
- } else if ((len >= MIN_RSP_LEN) &&
- (rsp->rc == MCAP_INVALID_MDL)) {
- /* Mdl does not exist in remote side */
- goto del_mdl;
- } else if (g_slist_find(mdl->mcl->mdls, mdl)){
- /* this mdl couldn't be deleted */
+ if (mdl)
restore_mdl(mdl, NULL);
- } else {
- /* MDL deleted request was sent by remote side while an
- * outgoing request for delete it was pending */
- shutdown_mdl(mdl);
- g_free(mdl);
- }
- goto end;
+ else
+ g_slist_foreach(mcl->mdls, restore_mdl, NULL);
+ deleted_cb(gerr, user_data);
+ g_error_free(gerr);
+ return close;
}

if (mdlid == MCAP_ALL_MDLIDS) {
@@ -1436,14 +1413,12 @@ static gboolean process_md_delete_mdl_rsp(struct mcap_mcl *mcl, uint8_t *cmd,
mcl->state = MCL_CONNECTED;
goto end;
}
-del_mdl:
+
mcl->mdls = g_slist_remove(mcl->mdls, mdl);
update_mcl_state(mcl);
mcap_delete_mdl(mdl, &notify);
end:
deleted_cb(gerr, user_data);
- if (gerr)
- g_error_free(gerr);
return close;
}

@@ -1481,30 +1456,6 @@ static void proc_response(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
}
}

-static void rsend_req(struct mcap_mcl *mcl)
-{
- uint8_t *cmd = mcl->lcmd;
- int len;
-
- if (!cmd)
- return;
-
- switch (cmd[0]) {
- case MCAP_MD_RECONNECT_MDL_REQ:
- case MCAP_MD_ABORT_MDL_REQ:
- case MCAP_MD_DELETE_MDL_REQ:
- len = 3;
- break;
- case MCAP_MD_CREATE_MDL_REQ:
- len = 5;
- break;
- default:
- return;
- }
-
- mcap_send_data(g_io_channel_unix_get_fd(mcl->cc), cmd, len);
-}
-
static void proc_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
{
if ((cmd[0] >= MCAP_MD_SYNC_CAP_REQ) &&
@@ -1526,8 +1477,7 @@ static void proc_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
/* ignore */
return;
proc_req[mcl->state](mcl, cmd, len);
- /* Initiator will ignore our last request => re-send */
- rsend_req(mcl);
+ /* Initiator will ignore our last request */
return;
}
proc_response(mcl, cmd, len);
--
1.6.3.3


Subject: [PATCH 41/60] Solve a bug when both sides request a creation of data channel with the same mdlid

---
mcap/mcap.c | 10 +++++++++-
1 files changed, 9 insertions(+), 1 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 64e76b5..1d33452 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -956,6 +956,14 @@ static void process_md_create_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
}

cfga = conf = req->conf;
+
+ mdl = get_mdl(mcl, mdl_id);
+ if (mdl && mdl->state == MDL_WAITING) {
+ /* A remote petition is also triying to connect this mdl_id
+ * so the petition is rejected by the moment */
+ send4B_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_MDL_BUSY, mdl_id);
+ return;
+ }
/* Callback to upper layer */
rsp = mcl->cb->mdl_conn_req(mcl, mdep_id, mdl_id, &conf,
mcl->cb->user_data);
@@ -977,7 +985,7 @@ static void process_md_create_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
return;
}

- mdl = get_mdl(mcl, mdl_id);
+
if (!mdl) {
mdl = g_malloc0(sizeof(struct mcap_mdl));
mdl->mcl = mcl;
--
1.6.3.3


Subject: [PATCH 40/60] Fix memory leak when double deletion happens and response code isn't SUCCESS

From: José Antonio Santos-Cadenas <[email protected]>

---
mcap/mcap.c | 9 +++++++--
1 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 51f0d87..64e76b5 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1132,7 +1132,7 @@ static void process_md_delete_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
notify = TRUE;
if (mdl->state == MDL_DELETING) {
/* Remote deviced requests deleting an MDL that upper profile
- * tries to delete, MDL will be freed when reply arrives. */
+ * is trying to delete, MDL will be freed when reply arrives. */
mdl->mcl->cb->mdl_deleted(mdl, mdl->mcl->cb->user_data);
} else
mcap_delete_mdl(mdl, &notify);
@@ -1410,9 +1410,14 @@ static gboolean process_md_delete_mdl_rsp(struct mcap_mcl *mcl, uint8_t *cmd,
(rsp->rc == MCAP_INVALID_MDL)) {
/* Mdl does not exist in remote side */
goto del_mdl;
- } else {
+ } else if (g_slist_find(mdl->mcl->mdls, mdl)){
/* this mdl couldn't be deleted */
restore_mdl(mdl, NULL);
+ } else {
+ /* MDL deleted request was sent by remote side while an
+ * outgoing request for delete it was pending */
+ shutdown_mdl(mdl);
+ g_free(mdl);
}
goto end;
}
--
1.6.3.3


Subject: [PATCH 38/60] Don't delete aborted MDLS

From: José Antonio Santos-Cadenas <[email protected]>

When a request for abort MDL creation fails we shouldn't delete the
MDL because it may be used for future reconnections.
---
mcap/mcap.c | 14 ++++++--------
1 files changed, 6 insertions(+), 8 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 87aa233..d268bf6 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1042,7 +1042,7 @@ static void process_md_abort_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
{
mcap_md_req *req;
GSList *l;
- struct mcap_mdl *mdl, *del;
+ struct mcap_mdl *mdl, *abrt;
uint16_t mdl_id;

if (len != sizeof(mcap_md_req)) {
@@ -1057,7 +1057,7 @@ static void process_md_abort_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
for (l = mcl->mdls; l; l = l->next) {
mdl = l->data;
if ((mdl_id == mdl->mdlid) && (mdl->state == MDL_WAITING)) {
- del = mdl;
+ abrt = mdl;
if (mcl->state != MCL_CONNECTED)
break;
continue;
@@ -1065,20 +1065,18 @@ static void process_md_abort_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
if ((mdl->state == MDL_CONNECTED) && (mcl->state != MCL_ACTIVE))
mcl->state = MCL_ACTIVE;

- if ((del) && (mcl->state == MCL_ACTIVE))
+ if ((abrt) && (mcl->state == MCL_ACTIVE))
break;
}

- if (!del) {
+ if (!abrt) {
send4B_cmd(mcl, MCAP_MD_ABORT_MDL_RSP, MCAP_INVALID_MDL,
mdl_id);
return;
}

- mcl->cb->mdl_aborted(del, mcl->cb->user_data);
-
- mcl->mdls = g_slist_remove(mcl->mdls, del);
- g_free(del);
+ mcl->cb->mdl_aborted(abrt, mcl->cb->user_data);
+ abrt->state = MDL_CLOSED;
send4B_cmd(mcl, MCAP_MD_ABORT_MDL_RSP, MCAP_SUCCESS, mdl_id);
}

--
1.6.3.3


Subject: [PATCH 30/60] Fix missed state transition in MCAP on reconnections

From: José Antonio Santos-Cadenas <[email protected]>

MCL should transite to properly state when a reconnect_mdl_req is
not SUCCESS.
---
mcap/mcap.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 1dfe083..34fd43b 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1303,6 +1303,7 @@ static gboolean process_md_reconnect_mdl_rsp(struct mcap_mcl *mcl,
mcl->mdls = g_slist_remove(mcl->mdls, mdl);
mcl->cb->mdl_deleted(mdl, mcl->cb->user_data);
g_free(mdl);
+ update_mcl_state(mcl);

return close;
}
--
1.6.3.3


Subject: [PATCH 34/60] Add macro to get minimum command length for respones

From: José Antonio Santos-Cadenas <[email protected]>

Minimum length responses are provided using a new macro to avoid using
magic numbers in source code.
---
mcap/mcap.c | 5 +++--
1 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 6031bd4..d3c92dc 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -35,6 +35,7 @@

#define RESPONSE_TIMER 2 /* seconds */
#define MAX_CACHED 10 /* 10 devices */
+#define MIN_RSP_LEN 4 /* 4 Bytes */

#define MCAP_ERROR g_quark_from_static_string("mcap-error-quark")

@@ -1191,7 +1192,7 @@ static gboolean check_err_rsp(struct mcap_mcl *mcl, uint8_t *cmd,
char *msg;

/* Check if the response matches with the last request */
- if ((rlen < 4) || ((mcl->lcmd[0] + 1) != cmd[0])) {
+ if ((rlen < MIN_RSP_LEN) || ((mcl->lcmd[0] + 1) != cmd[0])) {
msg = "Protocol error";
close = TRUE;
goto fail;
@@ -1349,7 +1350,7 @@ static gboolean process_md_abort_mdl_rsp(struct mcap_mcl *mcl,

abrt_cb(gerr, user_data);

- if ((len >= 4) && (rsp->rc == MCAP_INVALID_MDL)) {
+ if ((len >= MIN_RSP_LEN) && (rsp->rc == MCAP_INVALID_MDL)) {
mcl->mdls = g_slist_remove(mcl->mdls, mdl);
g_free(mdl);
}
--
1.6.3.3


Subject: [PATCH 32/60] Fix MCL transitions when responses are not success

From: José Antonio Santos-Cadenas <[email protected]>

---
mcap/mcap.c | 18 ++++++++++--------
1 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index d20b3d5..73abb90 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1315,6 +1315,7 @@ static gboolean process_md_reconnect_mdl_rsp(struct mcap_mcl *mcl,

g_error_free(gerr);
shutdown_mdl(mdl);
+ update_mcl_state(mcl);

if (rsp->rc != MCAP_INVALID_MDL)
return close;
@@ -1323,7 +1324,6 @@ static gboolean process_md_reconnect_mdl_rsp(struct mcap_mcl *mcl,
mcl->mdls = g_slist_remove(mcl->mdls, mdl);
mcl->cb->mdl_deleted(mdl, mcl->cb->user_data);
g_free(mdl);
- update_mcl_state(mcl);

return close;
}
@@ -1335,6 +1335,7 @@ static gboolean process_md_abort_mdl_rsp(struct mcap_mcl *mcl,
mcap_mdl_del_cb abrt_cb = abrt->cb.del;
gpointer user_data = abrt->user_data;
struct mcap_mdl *mdl = abrt->mdl;
+ mcap4B_rsp *rsp = (mcap4B_rsp *)cmd;
GError *gerr = NULL;
gboolean close = FALSE;

@@ -1347,16 +1348,17 @@ static gboolean process_md_abort_mdl_rsp(struct mcap_mcl *mcl,
mcl->lcmd = NULL;
mcl->req = MCL_AVAILABLE;

- if (gerr) {
- abrt_cb(gerr, user_data);
- g_error_free(gerr);
- return close;
+ abrt_cb(gerr, user_data);
+
+ if ((len >= 4) && (rsp->rc == MCAP_INVALID_MDL)) {
+ mcl->mdls = g_slist_remove(mcl->mdls, mdl);
+ g_free(mdl);
}

- mcl->mdls = g_slist_remove(mcl->mdls, mdl);
- g_free(mdl);
+ if (!gerr)
+ g_error_free(gerr);
+
update_mcl_state(mcl);
- abrt_cb(gerr, user_data);
return close;
}

--
1.6.3.3


Subject: [PATCH 31/60] Fix MCAP bug processing responses

From: José Antonio Santos-Cadenas <[email protected]>

---
mcap/mcap.c | 138 +++++++++++++++++++++-------------------------------------
1 files changed, 50 insertions(+), 88 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 34fd43b..d20b3d5 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1180,31 +1180,59 @@ static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
}

/* Function used to process replies */
-static gboolean check_err_rsp(uint16_t rmdl, uint16_t smdl, uint8_t rc,
+static gboolean check_err_rsp(struct mcap_mcl *mcl, uint8_t *cmd,
uint32_t rlen, uint32_t len, GError **gerr)
{
+ mcap_md_req *cmdlast = (mcap_md_req *) mcl->lcmd;
+ gint err = MCAP_ERROR_FAILED;
gboolean close = FALSE;
+ uint16_t rmdl, smdl;
+ mcap4B_rsp *rsp;
char *msg;
- gint err = MCAP_ERROR_FAILED;

+ /* Check if the response matches with the last request */
+ if ((rlen < 4) || ((mcl->lcmd[0] + 1) != cmd[0])) {
+ msg = "Protocol error";
+ close = TRUE;
+ goto fail;
+ }
+
+ if (rlen < len) {
+ msg = "Protocol error";
+ close = TRUE;
+ goto fail;
+ }
+
+ rsp = (mcap4B_rsp *)cmd;
+ smdl = ntohs(cmdlast->mdl);
+ rmdl = ntohs(rsp->mdl);
if (rmdl != smdl) {
- msg = "MDLID received doesn't match with MDLID sent";
+ msg = "MDLID %d received doesn't match with MDLID %d sent",
+ rmdl, smdl;
close = TRUE;
goto fail;
}

- if ((rc != MCAP_SUCCESS) && (rc <= MCAP_CONFIGURATION_REJECTED)) {
- msg = error2str(rc);
- err = rc;
+ if (rsp->rc == MCAP_REQUEST_NOT_SUPPORTED) {
+ msg = "Remote does not support opcodes";
+ mcl->ctrl &= ~MCAP_CTRL_STD_OP;
goto fail;
}

- if (rlen < len) {
- msg = "Protocol error";
+ if (rsp->rc == MCAP_UNSPECIFIED_ERROR) {
+ msg = "Unspecified error";
close = TRUE;
goto fail;
}
+
+ if (rsp->rc != MCAP_SUCCESS) {
+ msg = error2str(rsp->rc);
+ err = rsp->rc;
+ goto fail;
+ }
+
return FALSE;
+
fail:
g_set_error(gerr, MCAP_ERROR, err, "%s", msg);
return close;
@@ -1213,27 +1241,23 @@ fail:
static gboolean process_md_create_mdl_rsp(struct mcap_mcl *mcl,
uint8_t *cmd, uint32_t len)
{
+ mcap_md_create_mdl_req *cmdlast = (mcap_md_create_mdl_req *)mcl->lcmd;
struct mcap_mdl_op_cb *conn = mcl->priv_data;
- struct mcap_mdl *mdl = conn->mdl;
mcap_mdl_operation_conf_cb connect_cb = conn->cb.op_conf;
gpointer user_data = conn->user_data;
- uint16_t mdlid;
- mcap5B_rsp *rsp = (mcap5B_rsp *) cmd;
- mcap_md_create_mdl_req *cmdlast;
- GError *gerr = NULL;
+ struct mcap_mdl *mdl = conn->mdl;
+ uint8_t conf = cmdlast->conf;
gboolean close = FALSE;
+ GError *gerr = NULL;
+ mcap5B_rsp *rsp;

g_free(mcl->priv_data);
mcl->priv_data = NULL;

- cmdlast = (mcap_md_create_mdl_req *) mcl->lcmd;
- mdlid = ntohs(cmdlast->mdl);
- rsp->mdl = ntohs(rsp->mdl);
-
+ close = check_err_rsp(mcl, cmd, len, sizeof(mcap4B_rsp), &gerr);
g_free(mcl->lcmd);
mcl->lcmd = NULL;
mcl->req = MCL_AVAILABLE;
- close = check_err_rsp(rsp->mdl, mdlid, rsp->rc, 0, 0, &gerr);

if (gerr)
goto fail;
@@ -1245,8 +1269,9 @@ static gboolean process_md_create_mdl_rsp(struct mcap_mcl *mcl,
goto fail;
}

+ rsp = (mcap5B_rsp *)cmd;
/* Check if preferences changed */
- if ((cmdlast->conf != 0x00) && (rsp->param != cmdlast->conf)) {
+ if ((conf != 0x00) && (rsp->param != conf)) {
g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_FAILED,
"Configuration changed");
close = TRUE;
@@ -1268,22 +1293,17 @@ static gboolean process_md_reconnect_mdl_rsp(struct mcap_mcl *mcl,
uint8_t *cmd, uint32_t len)
{
struct mcap_mdl_op_cb *reconn = mcl->priv_data;
- struct mcap_mdl *mdl = reconn->mdl;
mcap_mdl_operation_cb reconn_cb = reconn->cb.op;
gpointer user_data = reconn->user_data;
- mcap4B_rsp *rsp = (mcap4B_rsp *) cmd;
- mcap_md_req *cmdlast = (mcap_md_req *) mcl->lcmd;
- uint16_t mdlid = ntohs(cmdlast->mdl);
+ struct mcap_mdl *mdl = reconn->mdl;
+ mcap4B_rsp *rsp = (mcap4B_rsp *)cmd;
GError *gerr = NULL;
gboolean close = FALSE;

g_free(mcl->priv_data);
mcl->priv_data = NULL;

- rsp->mdl = ntohs(rsp->mdl);
-
- close = check_err_rsp(rsp->mdl, mdlid, rsp->rc, len,
- sizeof(mcap4B_rsp), &gerr);
+ close = check_err_rsp(mcl, cmd, len, sizeof(mcap4B_rsp), &gerr);

g_free(mcl->lcmd);
mcl->lcmd = NULL;
@@ -1312,22 +1332,17 @@ static gboolean process_md_abort_mdl_rsp(struct mcap_mcl *mcl,
uint8_t *cmd, uint32_t len)
{
struct mcap_mdl_op_cb *abrt = mcl->priv_data;
- struct mcap_mdl *mdl = abrt->mdl;
mcap_mdl_del_cb abrt_cb = abrt->cb.del;
gpointer user_data = abrt->user_data;
- mcap4B_rsp *rsp = (mcap4B_rsp *) cmd;
- mcap_md_req *cmdlast = (mcap_md_req *) mcl->lcmd;
- uint16_t mdlid = ntohs(cmdlast->mdl);
+ struct mcap_mdl *mdl = abrt->mdl;
GError *gerr = NULL;
gboolean close = FALSE;

g_free(mcl->priv_data);
mcl->priv_data = NULL;

- rsp->mdl = ntohs(rsp->mdl);
+ close = check_err_rsp(mcl, cmd, len, sizeof(mcap4B_rsp), &gerr);

- close = check_err_rsp(rsp->mdl, mdlid, rsp->rc, len,
- sizeof(mcap4B_rsp), &gerr);
g_free(mcl->lcmd);
mcl->lcmd = NULL;
mcl->req = MCL_AVAILABLE;
@@ -1365,7 +1380,6 @@ static gboolean process_md_delete_mdl_rsp(struct mcap_mcl *mcl, uint8_t *cmd,
struct mcap_mdl *mdl = del->mdl;
mcap_mdl_del_cb deleted_cb = del->cb.del;
gpointer user_data = del->user_data;
- mcap4B_rsp *rsp = (mcap4B_rsp *) cmd;
mcap_md_req *cmdlast = (mcap_md_req *) mcl->lcmd;
uint16_t mdlid = ntohs(cmdlast->mdl);
GError *gerr = NULL;
@@ -1375,10 +1389,7 @@ static gboolean process_md_delete_mdl_rsp(struct mcap_mcl *mcl, uint8_t *cmd,
g_free(mcl->priv_data);
mcl->priv_data = NULL;

- rsp->mdl = ntohs(rsp->mdl);
-
- close = check_err_rsp(rsp->mdl, mdlid, rsp->rc, len,
- sizeof(mcap4B_rsp), &gerr);
+ close = check_err_rsp(mcl, cmd, len, sizeof(mcap4B_rsp), &gerr);

g_free(mcl->lcmd);
mcl->lcmd = NULL;
@@ -1409,60 +1420,11 @@ end:
return close;
}

-static gboolean check_rsp(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
-{
- mcap4B_rsp *rsp;
- GError *gerr = NULL;
-
- rsp = (mcap4B_rsp *)cmd;
- /* Check if the response matches with the last request */
- if ((cmd[0] != MCAP_ERROR_RSP) && ((mcl->lcmd[0] + 1) != cmd[0]))
- goto close_mcl;
-
- if (len < 4)
- goto close_mcl;
-
- if (rsp->rc == MCAP_REQUEST_NOT_SUPPORTED) {
- DBG("Remote does not support opcodes");
- g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_REQUEST_NOT_SUPPORTED,
- "%s", error2str(rsp->rc));
- mcap_notify_error(mcl, gerr);
- g_error_free(gerr);
-
- g_free(mcl->lcmd);
- mcl->lcmd = NULL;
- mcl->ctrl &= ~MCAP_CTRL_STD_OP;
- mcl->req = MCL_AVAILABLE;
- update_mcl_state(mcl);
- return FALSE;
- }
-
- if (rsp->rc == MCAP_UNSPECIFIED_ERROR)
- goto close_mcl;
-
- return TRUE;
-close_mcl:
- if (rsp->rc == MCAP_UNSPECIFIED_ERROR)
- g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_UNSPECIFIED_ERROR,
- "%s", error2str(rsp->rc));
- else
- g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_FAILED,
- "Protocol error");
- mcap_notify_error(mcl, gerr);
- g_error_free(gerr);
- mcl->ms->mcl_disconnected_cb(mcl, mcl->ms->user_data);
- mcap_cache_mcl(mcl);
- return FALSE;
-}
-
static void proc_response(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
{
gboolean close;
RELEASE_TIMER(mcl);

- if (!check_rsp(mcl, cmd, len))
- return;
-
switch (cmd[0]) {
case MCAP_ERROR_RSP:
error("MCAP_ERROR_RSP received");
--
1.6.3.3


Subject: [PATCH 33/60] Change error messagge

From: José Antonio Santos-Cadenas <[email protected]>

---
mcap/mcap.c | 3 +--
1 files changed, 1 insertions(+), 2 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 73abb90..6031bd4 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1207,8 +1207,7 @@ static gboolean check_err_rsp(struct mcap_mcl *mcl, uint8_t *cmd,
smdl = ntohs(cmdlast->mdl);
rmdl = ntohs(rsp->mdl);
if (rmdl != smdl) {
- msg = "MDLID %d received doesn't match with MDLID %d sent",
- rmdl, smdl;
+ msg = "MDLID received doesn't match with MDLID sent";
close = TRUE;
goto fail;
}
--
1.6.3.3


Subject: [PATCH 29/60] Fix missed state transition in MCAP

From: José Antonio Santos-Cadenas <[email protected]>

MCL should transite to properly state when a create_mdl_req is
not SUCCESS
---
mcap/mcap.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index cf92368..1dfe083 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1260,6 +1260,7 @@ fail:
mcl->mdls = g_slist_remove(mcl->mdls, mdl);
g_free(mdl);
g_error_free(gerr);
+ update_mcl_state(mcl);
return close;
}

--
1.6.3.3


Subject: [PATCH 27/60] Fix wrong response code rejecting reconnections

From: José Antonio Santos-Cadenas <[email protected]>

---
mcap/mcap.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 43b215b..7098a8d 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1024,7 +1024,7 @@ static void process_md_reconnect_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
return;

if (rsp != MCAP_SUCCESS) {
- send4B_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, rsp, mdl_id);
+ send4B_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, rsp, mdl_id);
return;
}

--
1.6.3.3


Subject: [PATCH 19/60] Process response to std. op. codes

From: José Antonio Santos-Cadenas <[email protected]>

---
mcap/mcap.c | 141 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 140 insertions(+), 1 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 6f6e08a..c775501 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1170,9 +1170,112 @@ static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
}
}

+static gboolean process_md_create_mdl_rsp(struct mcap_mcl *mcl,
+ uint8_t *cmd, uint32_t len)
+{
+ return FALSE;
+}
+
+static gboolean process_md_reconnect_mdl_rsp(struct mcap_mcl *mcl,
+ uint8_t *cmd, uint32_t len)
+{
+ return FALSE;
+}
+
+static gboolean process_md_abort_mdl_rsp(struct mcap_mcl *mcl,
+ uint8_t *cmd, uint32_t len)
+{
+ return FALSE;
+}
+
+static gboolean process_md_delete_mdl_rsp(struct mcap_mcl *mcl, uint8_t *cmd,
+ uint32_t len)
+{
+ return FALSE;
+}
+
+static gboolean check_rsp(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
+{
+ mcap4B_rsp *rsp;
+ GError *gerr = NULL;
+
+ /* Check if the response matches with the last request */
+ if ((cmd[0] != MCAP_ERROR_RSP) && ((mcl->lcmd[0] + 1) != cmd[0]))
+ goto close_mcl;
+
+ if (len < 4)
+ goto close_mcl;
+
+ rsp = (mcap4B_rsp *)cmd;
+
+ if (rsp->rc == MCAP_REQUEST_NOT_SUPPORTED) {
+ DBG("Remote does not support opcodes");
+ g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_REQUEST_NOT_SUPPORTED,
+ "%s", error2str(rsp->rc));
+ mcap_notify_error(mcl, gerr);
+ g_error_free(gerr);
+
+ g_free(mcl->lcmd);
+ mcl->lcmd = NULL;
+ mcl->ctrl &= ~MCAP_CTRL_STD_OP;
+ mcl->req = MCL_AVAILABLE;
+ update_mcl_state(mcl);
+ return FALSE;
+ }
+
+ if (rsp->rc == MCAP_UNSPECIFIED_ERROR)
+ goto close_mcl;
+
+ return TRUE;
+close_mcl:
+ if (rsp->rc == MCAP_UNSPECIFIED_ERROR)
+ g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_UNSPECIFIED_ERROR,
+ "%s", error2str(rsp->rc));
+ else
+ g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_FAILED,
+ "Protocol error");
+ mcap_notify_error(mcl, gerr);
+ g_error_free(gerr);
+ mcl->ms->mcl_disconnected_cb(mcl, mcl->ms->user_data);
+ mcap_cache_mcl(mcl);
+ return FALSE;
+}
+
static void proc_response(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
{
- /* TODO */
+ gboolean close;
+ RELEASE_TIMER(mcl);
+
+ if (!check_rsp(mcl, cmd, len))
+ return;
+
+ switch (cmd[0]) {
+ case MCAP_ERROR_RSP:
+ error("MCAP_ERROR_RSP received");
+ close = TRUE;
+ break;
+ case MCAP_MD_CREATE_MDL_RSP:
+ close = process_md_create_mdl_rsp(mcl, cmd, len);
+ break;
+ case MCAP_MD_RECONNECT_MDL_RSP:
+ close = process_md_reconnect_mdl_rsp(mcl, cmd, len);
+ break;
+ case MCAP_MD_ABORT_MDL_RSP:
+ close = process_md_abort_mdl_rsp(mcl, cmd, len);
+ break;
+ case MCAP_MD_DELETE_MDL_RSP:
+ close = process_md_delete_mdl_rsp(mcl, cmd, len);
+ break;
+ default:
+ DBG("Unknown cmd response received (op code = %d)",cmd[0]);
+ close = TRUE;
+ break;
+ }
+
+ if (close) {
+ mcl->ms->mcl_disconnected_cb(mcl, mcl->ms->user_data);
+ mcap_cache_mcl(mcl);
+ }
}

static void rsend_req(struct mcap_mcl *mcl)
@@ -1631,3 +1734,39 @@ void mcap_release_instance(struct mcap_instance *ms)

g_free(ms);
}
+
+uint16_t mcap_get_ctrl_psm(struct mcap_instance *ms, GError **err)
+{
+ uint16_t lpsm;
+
+ if (!(ms && ms->ccio)) {
+ g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS,
+ "Invalid MCAP instance");
+ return 0;
+ }
+
+ bt_io_get(ms->ccio, BT_IO_L2CAP, err,
+ BT_IO_OPT_PSM, &lpsm,
+ BT_IO_OPT_INVALID);
+ if (*err)
+ return 0;
+ return lpsm;
+}
+
+uint16_t mcap_get_data_psm(struct mcap_instance *ms, GError **err)
+{
+ uint16_t lpsm;
+
+ if (!(ms && ms->dcio)) {
+ g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS,
+ "Invalid MCAP instance");
+ return 0;
+ }
+
+ bt_io_get(ms->dcio, BT_IO_L2CAP, err,
+ BT_IO_OPT_PSM, &lpsm,
+ BT_IO_OPT_INVALID);
+ if (*err)
+ return 0;
+ return lpsm;
+}
--
1.6.3.3


Subject: [PATCH 25/60] Initial support for clock synchronization protocol

From: José Antonio Santos-Cadenas <[email protected]>

---
Makefile.am | 4 +-
mcap/mcap.c | 3 +-
mcap/mcap_sync.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 88 insertions(+), 4 deletions(-)
create mode 100644 mcap/mcap_sync.c

diff --git a/Makefile.am b/Makefile.am
index d1e6b0e..87c79a5 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -170,8 +170,8 @@ builtin_sources += plugins/service.c
endif

if MCAP
-mcap_sources += mcap/mcap_internal.h \
- mcap/mcap_lib.h \
+mcap_sources += mcap/mcap_internal.h \
+ mcap/mcap_lib.h mcap/mcap_sync.c \
mcap/mcap.h mcap/mcap.c
endif

diff --git a/mcap/mcap.c b/mcap/mcap.c
index b70545a..a32511e 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1510,8 +1510,7 @@ static void proc_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
{
if ((cmd[0] >= MCAP_MD_SYNC_CAP_REQ) &&
(cmd[0] <= MCAP_MD_SYNC_INFO_IND)) {
- send4B_cmd(mcl, cmd[0], MCAP_REQUEST_NOT_SUPPORTED,
- MCAP_MDLID_RESERVED);
+ proc_sync_cmd(mcl, cmd, len);
return;
}

diff --git a/mcap/mcap_sync.c b/mcap/mcap_sync.c
new file mode 100644
index 0000000..76f1377
--- /dev/null
+++ b/mcap/mcap_sync.c
@@ -0,0 +1,85 @@
+/*
+ *
+ * MCAP for BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ *
+ * Authors:
+ * Santiago Carot-Nemesio <sancane at gmail.com>
+ * Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <stdint.h>
+#include <netinet/in.h>
+
+#include "log.h"
+
+#include "mcap.h"
+#include "mcap_lib.h"
+#include "mcap_internal.h"
+
+static int send_unsupported_req(struct mcap_mcl *mcl, uint8_t oc)
+{
+ uint8_t *rsp;
+ mcap4B_rsp *rsp_err;
+ int sent;
+
+
+ rsp = g_malloc0(sizeof(mcap4B_rsp));
+
+ rsp_err = (mcap4B_rsp *)rsp;
+ rsp_err->op = oc;
+ rsp_err->rc = MCAP_REQUEST_NOT_SUPPORTED;
+ rsp_err->mdl = htons (MCAP_MDLID_RESERVED);
+
+ sent = mcap_send_data(g_io_channel_unix_get_fd(mcl->cc),
+ rsp,
+ sizeof(mcap4B_rsp));
+ g_free(rsp);
+ return sent;
+}
+
+void proc_sync_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
+{
+ switch (cmd[0]) {
+ case MCAP_MD_SYNC_CAP_REQ:
+ DBG("TODO: received MCAP_MD_SYNC_CAP_REQ: %d",
+ MCAP_MD_SYNC_CAP_REQ);
+ /* Not implemented yet. Reply with unsupported request */
+ send_unsupported_req(mcl, cmd[0]);
+ break;
+ case MCAP_MD_SYNC_CAP_RSP:
+ DBG("TODO: received MCAP_MD_SYNC_CAP_RSP: %d",
+ MCAP_MD_SYNC_CAP_RSP);
+ break;
+ case MCAP_MD_SYNC_SET_REQ:
+ DBG("TODO: received MCAP_MD_SYNC_SET_REQ: %d",
+ MCAP_MD_SYNC_SET_REQ);
+ /* Not implemented yet. Reply with unsupported request */
+ send_unsupported_req(mcl, cmd[0]);
+ break;
+ case MCAP_MD_SYNC_SET_RSP:
+ DBG("TODO: received MCAP_MD_SYNC_SET_RSP: %d",
+ MCAP_MD_SYNC_SET_RSP);
+ break;
+ case MCAP_MD_SYNC_INFO_IND:
+ DBG("TODO: received MCAP_MD_SYNC_INFO_IND :%d",
+ MCAP_MD_SYNC_INFO_IND);
+ break;
+ }
+}
--
1.6.3.3


Subject: [PATCH 26/60] Free memory when a unref operation happens over a cached MCL

From: José Antonio Santos-Cadenas <[email protected]>

MCAP should free memory in cached MCL list if an unref operation
happens over a cached MCL and only MCAP has a local copy of it.
MCL is removed from cached list and memory resources are freed.
---
mcap/mcap.c | 9 +++++++++
1 files changed, 9 insertions(+), 0 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index a32511e..43b215b 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -779,6 +779,15 @@ void mcap_mcl_unref(struct mcap_mcl *mcl)

DBG("mcap_mcl_unref(%p): ref=%d", mcl, mcl->ref);

+ if ((mcl->ctrl & MCAP_CTRL_CACHED) && (mcl->ref < 2)) {
+ /* Free space in cache memory due any other profile has a local
+ * copy of current MCL stored in cache */
+ DBG("Remove from cache (%p): ref=%d", mcl, mcl->ref);
+ mcl->ms->cached = g_slist_remove(mcl->ms->cached, mcl);
+ mcap_mcl_release(mcl);
+ return;
+ }
+
if (mcl->ref > 0)
return;

--
1.6.3.3


Subject: [PATCH 23/60] Process md_delete_mdl_rsp

From: José Antonio Santos-Cadenas <[email protected]>

---
mcap/mcap.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 59 insertions(+), 1 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index e0f3fec..61d6621 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1334,10 +1334,68 @@ static gboolean process_md_abort_mdl_rsp(struct mcap_mcl *mcl,
return close;
}

+static void restore_mdl(gpointer elem, gpointer data)
+{
+ struct mcap_mdl *mdl = elem;
+
+ if (mdl->state == MDL_DELETING) {
+ if (mdl->dc)
+ mdl->state = MDL_CONNECTED;
+ else
+ mdl->state = MDL_CLOSED;
+ } else if (mdl->state == MDL_CLOSED)
+ mdl->mcl->cb->mdl_closed(mdl, mdl->mcl->cb->user_data);
+}
+
static gboolean process_md_delete_mdl_rsp(struct mcap_mcl *mcl, uint8_t *cmd,
uint32_t len)
{
- return FALSE;
+ struct mcap_mdl_op_cb *del = mcl->priv_data;
+ struct mcap_mdl *mdl = del->mdl;
+ mcap_mdl_del_cb deleted_cb = del->cb.del;
+ gpointer user_data = del->user_data;
+ mcap4B_rsp *rsp = (mcap4B_rsp *) cmd;
+ mcap_md_req *cmdlast = (mcap_md_req *) mcl->lcmd;
+ uint16_t mdlid = ntohs(cmdlast->mdl);
+ GError *gerr = NULL;
+ gboolean close = FALSE;
+ gboolean notify = FALSE;
+
+ g_free(mcl->priv_data);
+ mcl->priv_data = NULL;
+
+ rsp->mdl = ntohs(rsp->mdl);
+
+ close = check_err_rsp(rsp->mdl, mdlid, rsp->rc, len,
+ sizeof(mcap4B_rsp), &gerr);
+
+ g_free(mcl->lcmd);
+ mcl->lcmd = NULL;
+ mcl->req = MCL_AVAILABLE;
+ if (gerr) {
+ if (mdl)
+ restore_mdl(mdl, NULL);
+ else
+ g_slist_foreach(mcl->mdls, restore_mdl, NULL);
+ deleted_cb(gerr, user_data);
+ g_error_free(gerr);
+ return close;
+ }
+
+ if (mdlid == MCAP_ALL_MDLIDS) {
+ g_slist_foreach(mcl->mdls, mcap_delete_mdl, &notify);
+ g_slist_free(mcl->mdls);
+ mcl->mdls = NULL;
+ mcl->state = MCL_CONNECTED;
+ goto end;
+ }
+
+ mcl->mdls = g_slist_remove(mcl->mdls, mdl);
+ update_mcl_state(mcl);
+ mcap_delete_mdl(mdl, &notify);
+end:
+ deleted_cb(gerr, user_data);
+ return close;
}

static gboolean check_rsp(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
--
1.6.3.3


Subject: [PATCH 21/60] Process md_reconnect_mdl_rsp

From: José Antonio Santos-Cadenas <[email protected]>

---
mcap/mcap.c | 39 ++++++++++++++++++++++++++++++++++++++-
1 files changed, 38 insertions(+), 1 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index aa9f1a3..b1498ca 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1257,7 +1257,44 @@ fail:
static gboolean process_md_reconnect_mdl_rsp(struct mcap_mcl *mcl,
uint8_t *cmd, uint32_t len)
{
- return FALSE;
+ struct mcap_mdl_op_cb *reconn = mcl->priv_data;
+ struct mcap_mdl *mdl = reconn->mdl;
+ mcap_mdl_operation_cb reconn_cb = reconn->cb.op;
+ gpointer user_data = reconn->user_data;
+ mcap4B_rsp *rsp = (mcap4B_rsp *) cmd;
+ mcap_md_req *cmdlast = (mcap_md_req *) mcl->lcmd;
+ uint16_t mdlid = ntohs(cmdlast->mdl);
+ GError *gerr = NULL;
+ gboolean close = FALSE;
+
+ g_free(mcl->priv_data);
+ mcl->priv_data = NULL;
+
+ rsp->mdl = ntohs(rsp->mdl);
+
+ close = check_err_rsp(rsp->mdl, mdlid, rsp->rc, len,
+ sizeof(mcap4B_rsp), &gerr);
+
+ g_free(mcl->lcmd);
+ mcl->lcmd = NULL;
+ mcl->req = MCL_AVAILABLE;
+
+ reconn_cb(mdl, gerr, user_data);
+ if (!gerr)
+ return close;
+
+ g_error_free(gerr);
+ shutdown_mdl(mdl);
+
+ if (rsp->rc != MCAP_INVALID_MDL)
+ return close;
+
+ /* Remove cached mdlid */
+ mcl->mdls = g_slist_remove(mcl->mdls, mdl);
+ mcl->cb->mdl_deleted(mdl, mcl->cb->user_data);
+ g_free(mdl);
+
+ return close;
}

static gboolean process_md_abort_mdl_rsp(struct mcap_mcl *mcl,
--
1.6.3.3


Subject: [PATCH 22/60] Process md_abort_mdl_rsp

From: José Antonio Santos-Cadenas <[email protected]>

---
mcap/mcap.c | 33 ++++++++++++++++++++++++++++++++-
1 files changed, 32 insertions(+), 1 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index b1498ca..e0f3fec 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1300,7 +1300,38 @@ static gboolean process_md_reconnect_mdl_rsp(struct mcap_mcl *mcl,
static gboolean process_md_abort_mdl_rsp(struct mcap_mcl *mcl,
uint8_t *cmd, uint32_t len)
{
- return FALSE;
+ struct mcap_mdl_op_cb *abrt = mcl->priv_data;
+ struct mcap_mdl *mdl = abrt->mdl;
+ mcap_mdl_del_cb abrt_cb = abrt->cb.del;
+ gpointer user_data = abrt->user_data;
+ mcap4B_rsp *rsp = (mcap4B_rsp *) cmd;
+ mcap_md_req *cmdlast = (mcap_md_req *) mcl->lcmd;
+ uint16_t mdlid = ntohs(cmdlast->mdl);
+ GError *gerr = NULL;
+ gboolean close = FALSE;
+
+ g_free(mcl->priv_data);
+ mcl->priv_data = NULL;
+
+ rsp->mdl = ntohs(rsp->mdl);
+
+ close = check_err_rsp(rsp->mdl, mdlid, rsp->rc, len,
+ sizeof(mcap4B_rsp), &gerr);
+ g_free(mcl->lcmd);
+ mcl->lcmd = NULL;
+ mcl->req = MCL_AVAILABLE;
+
+ if (gerr) {
+ abrt_cb(gerr, user_data);
+ g_error_free(gerr);
+ return close;
+ }
+
+ mcl->mdls = g_slist_remove(mcl->mdls, mdl);
+ g_free(mdl);
+ update_mcl_state(mcl);
+ abrt_cb(gerr, user_data);
+ return close;
}

static gboolean process_md_delete_mdl_rsp(struct mcap_mcl *mcl, uint8_t *cmd,
--
1.6.3.3


Subject: [PATCH 20/60] Process md_create_mdl_rsp

From: José Antonio Santos-Cadenas <[email protected]>

---
mcap/mcap.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 79 insertions(+), 1 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index c775501..aa9f1a3 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1170,10 +1170,88 @@ static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
}
}

+/* Function used to process replies */
+static gboolean check_err_rsp(uint16_t rmdl, uint16_t smdl, uint8_t rc,
+ uint32_t rlen, uint32_t len, GError **gerr)
+{
+ gboolean close = FALSE;
+ char *msg;
+ gint err = MCAP_ERROR_FAILED;
+
+ if (rmdl != smdl) {
+ msg = "MDLID received doesn't match with MDLID sent";
+ close = TRUE;
+ goto fail;
+ }
+
+ if ((rc != MCAP_SUCCESS) && (rc <= MCAP_CONFIGURATION_REJECTED)) {
+ msg = error2str(rc);
+ err = rc;
+ goto fail;
+ }
+
+ if (rlen < len) {
+ msg = "Protocol error";
+ close = TRUE;
+ goto fail;
+ }
+ return FALSE;
+fail:
+ g_set_error(gerr, MCAP_ERROR, err, "%s", msg);
+ return close;
+}
+
static gboolean process_md_create_mdl_rsp(struct mcap_mcl *mcl,
uint8_t *cmd, uint32_t len)
{
- return FALSE;
+ struct mcap_mdl_op_cb *conn = mcl->priv_data;
+ struct mcap_mdl *mdl = conn->mdl;
+ mcap_mdl_operation_conf_cb connect_cb = conn->cb.op_conf;
+ gpointer user_data = conn->user_data;
+ uint16_t mdlid;
+ mcap5B_rsp *rsp = (mcap5B_rsp *) cmd;
+ mcap_md_create_mdl_req *cmdlast;
+ GError *gerr = NULL;
+ gboolean close = FALSE;
+
+ g_free(mcl->priv_data);
+ mcl->priv_data = NULL;
+
+ cmdlast = (mcap_md_create_mdl_req *) mcl->lcmd;
+ mdlid = ntohs(cmdlast->mdl);
+ rsp->mdl = ntohs(rsp->mdl);
+
+ g_free(mcl->lcmd);
+ mcl->lcmd = NULL;
+ mcl->req = MCL_AVAILABLE;
+ close = check_err_rsp(rsp->mdl, mdlid, rsp->rc, 0, 0, &gerr);
+
+ if (gerr)
+ goto fail;
+
+ if (len < 5) {
+ g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_FAILED,
+ "Protocol error");
+ close = TRUE;
+ goto fail;
+ }
+
+ /* Check if preferences changed */
+ if ((cmdlast->conf != 0x00) && (rsp->param != cmdlast->conf)) {
+ g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_FAILED,
+ "Configuration changed");
+ close = TRUE;
+ goto fail;
+ }
+
+ connect_cb(mdl, rsp->param, gerr, user_data);
+ return close;
+fail:
+ connect_cb(NULL, 0, gerr, user_data);
+ mcl->mdls = g_slist_remove(mcl->mdls, mdl);
+ g_free(mdl);
+ g_error_free(gerr);
+ return close;
}

static gboolean process_md_reconnect_mdl_rsp(struct mcap_mcl *mcl,
--
1.6.3.3


2010-07-22 08:52:02

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 07/60] Process md_create_mdl_req in CONNECTED state

---
mcap/mcap.c | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 155 insertions(+), 1 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 0bc5035..b2d1d86 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -139,6 +139,40 @@ static int send4B_cmd(struct mcap_mcl *mcl, uint8_t oc, uint8_t rc,
return sent;
}

+static int send5B_cmd(struct mcap_mcl *mcl, uint8_t oc, uint8_t rc,
+ uint16_t mdl, uint8_t param)
+{
+ uint8_t *rsp;
+ mcap5B_rsp *suc;
+ int sent;
+
+ rsp = g_malloc0(sizeof(mcap5B_rsp));
+
+ suc = (mcap5B_rsp *)rsp;
+ suc->op = oc;
+ suc->rc = rc;
+ suc->mdl = htons(mdl);
+ suc->param = param;
+
+ sent = mcap_send_data(g_io_channel_unix_get_fd(mcl->cc), rsp,
+ sizeof(mcap5B_rsp));
+ g_free(rsp);
+ return sent;
+}
+
+static gint compare_mdl(gconstpointer a, gconstpointer b)
+{
+ const struct mcap_mdl *mdla = a;
+ const struct mcap_mdl *mdlb = b;
+
+ if (mdla->mdlid == mdlb->mdlid)
+ return 0;
+ else if (mdla->mdlid < mdlb->mdlid)
+ return -1;
+ else
+ return 1;
+}
+
static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr)
{
GSList *l;
@@ -337,9 +371,129 @@ void mcap_mcl_unref(struct mcap_mcl *mcl)
mcap_mcl_release(mcl);
}

+static void error_cmd_rsp(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
+{
+ uint16_t mdlr;
+
+ if (cmd[0] <= MCAP_MD_DELETE_MDL_RSP) {
+ /* Standard Op Code request is invalid in current state */
+ error("Invalid cmd received (op code = %d) in state %d",
+ cmd[0], mcl->state);
+ /* Get previously mdlid sent to generate an appropriate
+ * response if it is possible */
+ mdlr = len < sizeof(mcap_md_req) ? MCAP_MDLID_RESERVED :
+ ntohs(((mcap_md_req *)cmd)->mdl);
+ send4B_cmd(mcl, cmd[0]+1, MCAP_INVALID_OPERATION, mdlr);
+ } else {
+ error("Unknown cmd request received (op code = %d) in state %d",
+ cmd[0], mcl->state);
+ send4B_cmd(mcl, MCAP_ERROR_RSP, MCAP_INVALID_OP_CODE,
+ MCAP_MDLID_RESERVED);
+ }
+}
+
+static struct mcap_mdl *get_mdl(struct mcap_mcl *mcl, uint16_t mdlid)
+{
+ GSList *l;
+ struct mcap_mdl *mdl;
+
+ for (l = mcl->mdls; l; l = l->next) {
+ mdl = l->data;
+ if (mdlid == mdl->mdlid)
+ return mdl;
+ }
+
+ return NULL;
+}
+
+static void process_md_create_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
+ uint32_t len)
+{
+ mcap_md_create_mdl_req *req;
+ struct mcap_mdl *mdl;
+ uint16_t mdl_id;
+ uint8_t mdep_id;
+ uint8_t cfga, conf;
+ uint8_t rsp;
+
+ if (len != sizeof(mcap_md_create_mdl_req)) {
+ send4B_cmd(mcl, MCAP_MD_CREATE_MDL_RSP,
+ MCAP_INVALID_PARAM_VALUE, MCAP_MDLID_RESERVED);
+ return;
+ }
+
+ req = (mcap_md_create_mdl_req *)cmd;
+
+ mdl_id = ntohs(req->mdl);
+ if ((mdl_id < MCAP_MDLID_INITIAL) || (mdl_id > MCAP_MDLID_FINAL)) {
+ send4B_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_INVALID_MDL,
+ mdl_id);
+ return;
+ }
+
+ mdep_id = req->mdep;
+ if (mdep_id > MCAP_MDEPID_FINAL) {
+ send4B_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_INVALID_MDEP,
+ mdl_id);
+ return;
+ }
+
+ cfga = conf = req->conf;
+ /* Callback to upper layer */
+ rsp = mcl->cb->mdl_conn_req(mcl, mdep_id, mdl_id, &conf,
+ mcl->cb->user_data);
+ if (mcl->state == MCL_IDLE) {
+ /* MCL has been closed int the callback */
+ return;
+ }
+
+ if ((cfga != 0) && (cfga != conf)) {
+ /* Remote device set default configuration but upper profile */
+ /* has changed it. Protocol Error: force closing the MCL by */
+ /* remote device using UNSPECIFIED_ERROR response */
+ send4B_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_UNSPECIFIED_ERROR,
+ mdl_id);
+ return;
+ }
+ if (rsp != MCAP_SUCCESS) {
+ send4B_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, rsp, mdl_id);
+ return;
+ }
+
+ mdl = get_mdl(mcl, mdl_id);
+ if (!mdl) {
+ mdl = g_malloc0(sizeof(struct mcap_mdl));
+ mdl->mcl = mcl;
+ mdl->mdlid = mdl_id;
+ } else if (mdl->state == MDL_CONNECTED) {
+ /* MCAP specification says that we should close the MCL if
+ * it is open when we receive a MD_CREATE_MDL_REQ */
+ shutdown_mdl(mdl);
+ }
+ mdl->mdep_id = mdep_id;
+ mdl->state = MDL_WAITING;
+ mcl->mdls = g_slist_insert_sorted(mcl->mdls, mdl, compare_mdl);
+
+ mcl->state = MCL_PENDING;
+ send5B_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_SUCCESS, mdl_id, conf);
+}
+
+/* Function used to process commands depending of MCL state */
static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
{
- /* TODO */
+ switch (cmd[0]) {
+ case MCAP_MD_CREATE_MDL_REQ:
+ process_md_create_mdl_req(mcl, cmd, len);
+ break;
+ case MCAP_MD_RECONNECT_MDL_REQ:
+ /*process_md_reconnect_mdl_req(mcl, cmd, len);*/
+ break;
+ case MCAP_MD_DELETE_MDL_REQ:
+ /*process_md_delete_mdl_req(mcl, cmd, len);*/
+ break;
+ default:
+ error_cmd_rsp(mcl, cmd, len);
+ }
}

static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
--
1.6.3.3


2010-07-22 08:52:10

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 15/60] Implement function to send md_create_mdl_req

---
mcap/mcap.c | 177 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 177 insertions(+), 0 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index aaac709..dc55cda 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -33,6 +33,7 @@
#include "mcap_lib.h"
#include "mcap_internal.h"

+#define RESPONSE_TIMER 2 /* seconds */
#define MAX_CACHED 10 /* 10 devices */

#define MCAP_ERROR g_quark_from_static_string("mcap-error-quark")
@@ -48,6 +49,17 @@ struct connect_mcl {
gpointer user_data; /* Callback user data */
};

+typedef union {
+ mcap_mdl_operation_cb op;
+ mcap_mdl_operation_conf_cb op_conf;
+ mcap_mdl_del_cb del;
+} mcap_cb_type;
+
+struct mcap_mdl_op_cb {
+ struct mcap_mdl *mdl; /* MDL for this operation */
+ mcap_cb_type cb; /* Operation callback */
+ gpointer user_data; /* Callback user data */
+};

/* MCAP finite state machine functions */
static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l);
@@ -60,6 +72,8 @@ static void (*proc_req[])(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) = {
proc_req_active
};

+static void mcap_cache_mcl(struct mcap_mcl *mcl);
+
static void default_mdl_connected_cb(struct mcap_mdl *mdl, gpointer data)
{
DBG("MCAP Unmanaged mdl connection");
@@ -110,6 +124,67 @@ static void set_default_cb(struct mcap_mcl *mcl)
mcl->cb->mdl_reconn_req = default_mdl_reconn_req_cb;
}

+static void mcap_send_std_opcode(struct mcap_mcl *mcl, uint8_t *cmd,
+ uint32_t size, GError **err)
+{
+ if (mcl->state == MCL_IDLE) {
+ g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
+ "MCL is not connected");
+ return;
+ }
+
+ if (mcl->req != MCL_AVAILABLE) {
+ g_set_error(err, MCAP_ERROR, MCAP_ERROR_RESOURCE_UNAVAILABLE,
+ "Pending request");
+ return;
+ }
+
+ if (!(mcl->ctrl & MCAP_CTRL_STD_OP)) {
+ g_set_error(err, MCAP_ERROR, MCAP_ERROR_REQUEST_NOT_SUPPORTED,
+ "Remote does not support standard opcodes");
+ return;
+ }
+
+ if (mcl->state == MCL_PENDING) {
+ g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_OPERATION,
+ "Not Std Op. Codes can be sent in PENDING State");
+ return;
+ }
+
+ if (mcap_send_data(g_io_channel_unix_get_fd(mcl->cc), cmd, size) < 0) {
+ g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
+ "Command can't be sent, write error");
+ return;
+ }
+
+ mcl->lcmd = cmd;
+ mcl->req = MCL_WAITING_RSP;
+}
+
+static void mcap_notify_error(struct mcap_mcl *mcl, GError *err)
+{
+ struct mcap_mdl_op_cb *con = mcl->priv_data;
+
+ if (!con || !mcl->lcmd)
+ return;
+
+ switch (mcl->lcmd[0]){
+ case MCAP_MD_CREATE_MDL_REQ:
+ con->cb.op_conf(NULL, 0, err, con->user_data);
+ break;
+ case MCAP_MD_ABORT_MDL_REQ:
+ case MCAP_MD_DELETE_MDL_REQ:
+ con->cb.del(err, con->user_data);
+ break;
+ case MCAP_MD_RECONNECT_MDL_REQ:
+ con->cb.op(NULL, err, con->user_data);
+ break;
+ }
+
+ g_free(mcl->priv_data);
+ mcl->priv_data = NULL;
+}
+
int mcap_send_data(int sock, const uint8_t *buf, uint32_t size)
{
uint32_t sent = 0;
@@ -166,6 +241,42 @@ static int send5B_cmd(struct mcap_mcl *mcl, uint8_t oc, uint8_t rc,
return sent;
}

+static uint16_t generate_mdlid(struct mcap_mcl *mcl)
+{
+ uint16_t mdlid = MCAP_MDLID_INITIAL;
+ struct mcap_mdl *mdl;
+ GSList *l;
+
+ for (l = mcl->mdls; l; l = l->next) {
+ mdl = l->data;
+ if (mdlid < mdl->mdlid)
+ break;
+ else
+ mdlid = mdl->mdlid + 1;
+ }
+
+ if (mdlid > MCAP_MDLID_FINAL)
+ return 0;
+
+ return mdlid;
+}
+
+static uint8_t *create_mdl_req(uint16_t mdl_id, uint8_t mdep, uint8_t conf)
+{
+ uint8_t *req;
+ mcap_md_create_mdl_req *req_mdl;
+
+ req = g_malloc0(sizeof(mcap_md_create_mdl_req));
+
+ req_mdl = (mcap_md_create_mdl_req *)req;
+ req_mdl->op = MCAP_MD_CREATE_MDL_REQ;
+ req_mdl->mdl = htons(mdl_id);
+ req_mdl->mdep = mdep;
+ req_mdl->conf = conf;
+
+ return req;
+}
+
static gint compare_mdl(gconstpointer a, gconstpointer b)
{
const struct mcap_mdl *mdla = a;
@@ -179,6 +290,72 @@ static gint compare_mdl(gconstpointer a, gconstpointer b)
return 1;
}

+static gboolean wait_response_timer(gpointer data)
+{
+ struct mcap_mcl *mcl = data;
+
+ GError *gerr = NULL;
+
+ RELEASE_TIMER(mcl);
+
+ g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_FAILED,
+ "Timeout waiting response");
+
+ mcap_notify_error(mcl, gerr);
+
+ g_error_free(gerr);
+ mcl->ms->mcl_disconnected_cb(mcl, mcl->ms->user_data);
+ mcap_cache_mcl(mcl);
+ return FALSE;
+}
+
+void mcap_req_mdl_creation(struct mcap_mcl *mcl,
+ uint8_t mdepid,
+ uint8_t conf,
+ GError **err,
+ mcap_mdl_operation_conf_cb connect_cb,
+ gpointer user_data)
+{
+ struct mcap_mdl *mdl;
+ struct mcap_mdl_op_cb *con;
+ uint8_t *cmd = NULL;
+ uint16_t id;
+
+ id = generate_mdlid(mcl);
+ if (!id) {
+ g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
+ "Not more mdlids available");
+ return;
+ }
+
+ mdl = g_new0(struct mcap_mdl, 1);
+ mdl->mcl = mcl;
+ mdl->mdlid = id;
+ mdl->mdep_id = mdepid;
+ mdl->state = MDL_WAITING;
+
+ con = g_new0(struct mcap_mdl_op_cb, 1);
+ con->mdl = mdl;
+ con->cb.op_conf = connect_cb;
+ con->user_data = user_data;
+
+ cmd = create_mdl_req(id, mdepid, conf);
+ mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_create_mdl_req), err);
+ if (*err) {
+ g_free(mdl);
+ g_free(con);
+ g_free(cmd);
+ return;
+ }
+
+ mcl->state = MCL_ACTIVE;
+ mcl->priv_data = con;
+
+ mcl->mdls = g_slist_insert_sorted(mcl->mdls, mdl, compare_mdl);
+ mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
+ mcl);
+}
+
static void update_mcl_state(struct mcap_mcl *mcl)
{
GSList *l;
--
1.6.3.3


2010-07-22 08:52:12

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 17/60] Implement function to send md_delete_mdl_req

---
mcap/mcap.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 112 insertions(+), 0 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index a0f00af..5419d54 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -124,6 +124,38 @@ static void set_default_cb(struct mcap_mcl *mcl)
mcl->cb->mdl_reconn_req = default_mdl_reconn_req_cb;
}

+static char *error2str(uint8_t rc)
+{
+ switch (rc) {
+ case MCAP_SUCCESS:
+ return "Success";
+ case MCAP_INVALID_OP_CODE:
+ return "Invalid Op Code";
+ case MCAP_INVALID_PARAM_VALUE:
+ return "Invalid Parameter Value";
+ case MCAP_INVALID_MDEP:
+ return "Invalid MDEP";
+ case MCAP_MDEP_BUSY:
+ return "MDEP Busy";
+ case MCAP_INVALID_MDL:
+ return "Invalid MDL";
+ case MCAP_MDL_BUSY:
+ return "MDL Busy";
+ case MCAP_INVALID_OPERATION:
+ return "Invalid Operation";
+ case MCAP_RESOURCE_UNAVAILABLE:
+ return "Resource Unavailable";
+ case MCAP_UNSPECIFIED_ERROR:
+ return "Unspecified Error";
+ case MCAP_REQUEST_NOT_SUPPORTED:
+ return "Request Not Supported";
+ case MCAP_CONFIGURATION_REJECTED:
+ return "Configuration Rejected";
+ default:
+ return "Unknown Response Code";
+ }
+}
+
static void mcap_send_std_opcode(struct mcap_mcl *mcl, uint8_t *cmd,
uint32_t size, GError **err)
{
@@ -407,6 +439,86 @@ void mcap_req_mdl_reconnect(struct mcap_mdl *mdl,
mcl);
}

+static void send_delete_req(GError **err, struct mcap_mcl *mcl,
+ struct mcap_mdl_op_cb *con, uint16_t mdlid)
+{
+ uint8_t *cmd;
+
+ cmd = create_req(MCAP_MD_DELETE_MDL_REQ, mdlid);
+ mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_req), err);
+ if (*err) {
+ g_free(cmd);
+ return;
+ }
+
+ mcl->priv_data = con;
+
+ mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
+ mcl);
+}
+
+void mcap_req_mdl_delete_all(struct mcap_mcl *mcl, GError **err,
+ mcap_mdl_del_cb delete_cb, gpointer user_data)
+{
+ GSList *l;
+ struct mcap_mdl *mdl;
+ struct mcap_mdl_op_cb *con;
+
+ DBG("MCL in state: %d", mcl->state);
+ if (!mcl->mdls) {
+ g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
+ "There are not MDLs created");
+ return;
+ }
+
+ for (l = mcl->mdls; l; l = l->next) {
+ mdl = l->data;
+ if (mdl->state != MDL_WAITING)
+ mdl->state = MDL_DELETING;
+ }
+
+ con = g_new0(struct mcap_mdl_op_cb, 1);
+ con->mdl = NULL;
+ con->cb.del = delete_cb;
+ con->user_data = user_data;
+
+ send_delete_req(err, mcl, con, MCAP_ALL_MDLIDS);
+ if (*err)
+ g_free(con);
+}
+
+void mcap_req_mdl_deletion(struct mcap_mdl *mdl, GError **err,
+ mcap_mdl_del_cb delete_cb, gpointer user_data)
+{
+ struct mcap_mcl *mcl= mdl->mcl;
+ struct mcap_mdl_op_cb *con;
+ GSList *l;
+
+ l = g_slist_find(mcl->mdls, mdl);
+
+ if (!l) {
+ g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_MDL,
+ "%s" , error2str(MCAP_INVALID_MDEP));
+ return;
+ }
+
+ if (mdl->state == MDL_WAITING) {
+ g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
+ "Mdl is not created");
+ return;
+ }
+ mdl->state = MDL_DELETING;
+
+ con = g_new0(struct mcap_mdl_op_cb, 1);
+ con->mdl = mdl;
+ con->cb.del = delete_cb;
+ con->user_data = user_data;
+
+ send_delete_req(err, mcl, con, mdl->mdlid);
+ if (*err)
+ g_free(con);
+}
+
static void update_mcl_state(struct mcap_mcl *mcl)
{
GSList *l;
--
1.6.3.3


2010-07-22 08:52:13

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 18/60] Implement function to send md_abort_mdl_req

---
mcap/mcap.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 48 insertions(+), 0 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 5419d54..6f6e08a 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -519,6 +519,38 @@ void mcap_req_mdl_deletion(struct mcap_mdl *mdl, GError **err,
g_free(con);
}

+void mcap_mdl_abort(struct mcap_mdl *mdl, GError **err,
+ mcap_mdl_del_cb abort_cb, gpointer user_data)
+{
+ struct mcap_mdl_op_cb *con;
+ struct mcap_mcl *mcl = mdl->mcl;
+ uint8_t *cmd;
+
+ if (mdl->state != MDL_WAITING) {
+ g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
+ "Mdl in invalid state");
+ return;
+ }
+
+ con = g_new0(struct mcap_mdl_op_cb, 1);
+ cmd = create_req(MCAP_MD_ABORT_MDL_REQ, mdl->mdlid);
+ mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_req), err);
+ if (*err) {
+ g_free(con);
+ g_free(cmd);
+ return;
+ }
+
+ con->mdl = mdl;
+ con->cb.del = abort_cb;
+ con->user_data = user_data;
+
+ mcl->priv_data = con;
+
+ mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
+ mcl);
+}
+
static void update_mcl_state(struct mcap_mcl *mcl)
{
GSList *l;
@@ -554,6 +586,22 @@ static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr)
return NULL;
}

+int mcap_mdl_get_fd(struct mcap_mdl *mdl)
+{
+ if ((!mdl) || (mdl->state != MDL_CONNECTED))
+ return -1;
+
+ return g_io_channel_unix_get_fd(mdl->dc);
+}
+
+uint16_t mcap_mdl_get_mdlid(struct mcap_mdl *mdl)
+{
+ if (!mdl)
+ return MCAP_MDLID_RESERVED;
+
+ return mdl->mdlid;
+}
+
static void shutdown_mdl(struct mcap_mdl *mdl)
{
mdl->state = MDL_CLOSED;
--
1.6.3.3


2010-07-22 08:52:11

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 16/60] Implement function to send md_reconnect_mdl_req

---
mcap/mcap.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 51 insertions(+), 0 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index dc55cda..a0f00af 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -261,6 +261,20 @@ static uint16_t generate_mdlid(struct mcap_mcl *mcl)
return mdlid;
}

+static uint8_t *create_req(uint8_t op, uint16_t mdl_id)
+{
+ uint8_t *req;
+ mcap_md_req *req_cmd;
+
+ req = g_malloc0(sizeof(mcap_md_req));
+
+ req_cmd = (mcap_md_req *)req;
+ req_cmd->op = op;
+ req_cmd->mdl = htons(mdl_id);
+
+ return req;
+}
+
static uint8_t *create_mdl_req(uint16_t mdl_id, uint8_t mdep, uint8_t conf)
{
uint8_t *req;
@@ -356,6 +370,43 @@ void mcap_req_mdl_creation(struct mcap_mcl *mcl,
mcl);
}

+void mcap_req_mdl_reconnect(struct mcap_mdl *mdl,
+ GError **err,
+ mcap_mdl_operation_cb reconnect_cb,
+ gpointer user_data)
+{
+ struct mcap_mdl_op_cb *con;
+ struct mcap_mcl *mcl = mdl->mcl;
+ uint8_t *cmd;
+
+ if (mdl->state != MDL_CLOSED) {
+ g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
+ "MDL is not closed");
+ return;
+ }
+ con = g_new0(struct mcap_mdl_op_cb, 1);
+
+ cmd = create_req(MCAP_MD_RECONNECT_MDL_REQ, mdl->mdlid);
+ mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_req), err);
+ if (*err) {
+ g_free(con);
+ g_free(cmd);
+ return;
+ }
+
+ mdl->state = MDL_WAITING;
+
+ con->mdl = mdl;
+ con->cb.op = reconnect_cb;
+ con->user_data = user_data;
+
+ mcl->state = MCL_ACTIVE;
+ mcl->priv_data = con;
+
+ mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
+ mcl);
+}
+
static void update_mcl_state(struct mcap_mcl *mcl)
{
GSList *l;
--
1.6.3.3


2010-07-22 08:52:09

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 14/60] Implement set callbacks operation over MCLs

---
mcap/mcap.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 82 insertions(+), 0 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 201f42c..aaac709 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -397,6 +397,88 @@ void mcap_mcl_unref(struct mcap_mcl *mcl)
mcap_mcl_release(mcl);
}

+static gboolean parse_set_opts(struct mcap_mdl_cb *mdl_cb, GError **err,
+ McapMclCb cb1, va_list args)
+{
+ McapMclCb cb = cb1;
+ struct mcap_mdl_cb *c;
+
+ c = g_new0(struct mcap_mdl_cb, 1);
+
+ while (cb != MCAP_MDL_CB_INVALID) {
+ switch (cb) {
+ case MCAP_MDL_CB_CONNECTED:
+ c->mdl_connected = va_arg(args,
+ mcap_mdl_event_cb);
+ break;
+ case MCAP_MDL_CB_CLOSED:
+ c->mdl_closed = va_arg(args,
+ mcap_mdl_event_cb);
+ break;
+ case MCAP_MDL_CB_DELETED:
+ c->mdl_deleted = va_arg(args,
+ mcap_mdl_event_cb);
+ break;
+ case MCAP_MDL_CB_ABORTED:
+ c->mdl_aborted = va_arg(args,
+ mcap_mdl_event_cb);
+ break;
+ case MCAP_MDL_CB_REMOTE_CONN_REQ:
+ c->mdl_conn_req = va_arg(args,
+ mcap_remote_mdl_conn_req_cb);
+ break;
+ case MCAP_MDL_CB_REMOTE_RECONN_REQ:
+ c->mdl_reconn_req = va_arg(args,
+ mcap_remote_mdl_reconn_req_cb);
+ break;
+ default:
+ g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS,
+ "Unknown option %d", cb);
+ return FALSE;
+ }
+ cb = va_arg(args, int);
+ }
+
+ /* Set new callbacks */
+ if (c->mdl_connected)
+ mdl_cb->mdl_connected = c->mdl_connected;
+ if (c->mdl_closed)
+ mdl_cb->mdl_closed = c->mdl_closed;
+ if (c->mdl_deleted)
+ mdl_cb->mdl_deleted = c->mdl_deleted;
+ if (c->mdl_aborted)
+ mdl_cb->mdl_aborted = c->mdl_aborted;
+ if (c->mdl_conn_req)
+ mdl_cb->mdl_conn_req = c->mdl_conn_req;
+ if (c->mdl_reconn_req)
+ mdl_cb->mdl_reconn_req = c->mdl_reconn_req;
+
+ g_free(c);
+ return TRUE;
+}
+
+void mcap_mcl_set_cb(struct mcap_mcl *mcl, GError **gerr,
+ gpointer user_data, McapMclCb cb1, ...)
+{
+ va_list args;
+ gboolean ret;
+
+ va_start(args, cb1);
+ ret = parse_set_opts(mcl->cb, gerr, cb1, args);
+ va_end(args);
+
+ if (!ret)
+ return;
+
+ mcl->cb->user_data = user_data;
+ return;
+}
+
+bdaddr_t mcap_mcl_get_addr(struct mcap_mcl *mcl)
+{
+ return mcl->addr;
+}
+
static void error_cmd_rsp(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
{
uint16_t mdlr;
--
1.6.3.3


2010-07-22 08:52:08

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 13/60] Enable connect operation to a remote MCAP instances

---
mcap/mcap.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 116 insertions(+), 0 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 1d86c51..201f42c 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -42,6 +42,12 @@
__mcl->tid = 0; \
} while(0)

+struct connect_mcl {
+ struct mcap_mcl *mcl; /* MCL for this operation */
+ mcap_mcl_connect_cb connect_cb; /* Connect callback */
+ gpointer user_data; /* Callback user data */
+};
+

/* MCAP finite state machine functions */
static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l);
@@ -800,6 +806,66 @@ fail:
return FALSE;
}

+static void mcap_connect_mcl_cb(GIOChannel *chan, GError *conn_err,
+ gpointer user_data)
+{
+ char dstaddr[18];
+ struct connect_mcl *con = user_data;
+ struct mcap_mcl *aux, *mcl = con->mcl;
+ mcap_mcl_connect_cb connect_cb = con->connect_cb;
+ gpointer data = con->user_data;
+ GError *gerr = NULL;
+
+ g_free(con);
+
+ mcl->ctrl &= ~MCAP_CTRL_CONN;
+
+ if (conn_err) {
+ if (mcl->ctrl & MCAP_CTRL_FREE)
+ mcl->ms->mcl_uncached_cb(mcl, mcl->ms->user_data);
+ mcap_mcl_check_del(mcl);
+ connect_cb(NULL, conn_err, data);
+ return;
+ }
+
+ ba2str(&mcl->addr, dstaddr);
+
+ aux = find_mcl(mcl->ms->mcls, &mcl->addr);
+ if (aux) {
+ /* Double MCL connection case */
+ if (aux != mcl) {
+ /* This MCL was not in cache */
+ mcap_mcl_unref(mcl);
+ }
+ error("MCL error: Device %s is already connected", dstaddr);
+ g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_ALREADY_EXISTS,
+ "MCL %s is already connected", dstaddr);
+ connect_cb(NULL, gerr, data);
+ g_error_free(gerr);
+ return;
+ }
+
+ mcl->state = MCL_CONNECTED;
+ mcl->role = MCL_INITIATOR;
+ mcl->req = MCL_AVAILABLE;
+ mcl->ctrl |= MCAP_CTRL_STD_OP;
+
+ if (mcl->ctrl & MCAP_CTRL_CACHED)
+ mcap_uncache_mcl(mcl);
+ else
+ mcl->ms->mcls = g_slist_prepend(mcl->ms->mcls, mcl);
+
+ mcl->wid = g_io_add_watch(mcl->cc,
+ G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ (GIOFunc) mcl_control_cb, mcl);
+ connect_cb(mcl, gerr, data);
+
+ if (mcl->ref == 1) {
+ mcl->ms->mcls = g_slist_remove(mcl->ms->mcls, mcl);
+ mcap_mcl_unref(mcl);
+ }
+}
+
static void connect_dc_event_cb(GIOChannel *chan, GError *err,
gpointer user_data)
{
@@ -815,6 +881,56 @@ static void connect_dc_event_cb(GIOChannel *chan, GError *err,
mcl->cb->mdl_connected(mdl, mcl->cb->user_data);
}

+void mcap_create_mcl(struct mcap_instance *ms,
+ const bdaddr_t *addr,
+ uint16_t ccpsm,
+ GError **err,
+ mcap_mcl_connect_cb connect_cb,
+ gpointer user_data)
+{
+ struct mcap_mcl *mcl;
+ struct connect_mcl *con;
+
+ mcl = find_mcl(ms->mcls, addr);
+ if (mcl) {
+ g_set_error(err, MCAP_ERROR, MCAP_ERROR_ALREADY_EXISTS,
+ "MCL is already connected.");
+ return;
+ }
+
+ mcl = find_mcl(ms->cached, addr);
+ if (!mcl) {
+ mcl = g_new0(struct mcap_mcl, 1);
+ mcl->ms = ms;
+ mcl->state = MCL_IDLE;
+ bacpy(&mcl->addr, addr);
+ set_default_cb(mcl);
+ mcl = mcap_mcl_ref(mcl);
+ } else
+ mcl->ctrl |= MCAP_CTRL_CONN;
+
+ con = g_new0(struct connect_mcl, 1);
+ con->mcl = mcl;
+ con->connect_cb = connect_cb;
+ con->user_data = user_data;
+
+ mcl->cc = bt_io_connect(BT_IO_L2CAP, mcap_connect_mcl_cb, con,
+ NULL, err,
+ BT_IO_OPT_SOURCE_BDADDR, &ms->src,
+ BT_IO_OPT_DEST_BDADDR, addr,
+ BT_IO_OPT_PSM, ccpsm,
+ BT_IO_OPT_MTU, MCAP_CC_MTU,
+ BT_IO_OPT_SEC_LEVEL, ms->sec,
+ BT_IO_OPT_INVALID);
+ if (*err) {
+ g_free(con);
+ mcl->ctrl &= ~MCAP_CTRL_CONN;
+ if (mcl->ctrl & MCAP_CTRL_FREE)
+ mcl->ms->mcl_uncached_cb(mcl, mcl->ms->user_data);
+ mcap_mcl_check_del(mcl);
+ }
+}
+
static void confirm_dc_event_cb(GIOChannel *chan, gpointer user_data)
{
struct mcap_instance *ms = user_data;
--
1.6.3.3


2010-07-22 08:52:07

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 12/60] Managing connection of Data Channels

---
mcap/mcap.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 70 insertions(+), 1 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index cf44472..1d86c51 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -754,6 +754,27 @@ static void proc_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
proc_req[mcl->state](mcl, cmd, len);
}

+static gboolean mdl_event_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
+{
+
+ struct mcap_mdl *mdl = data;
+ gboolean notify;
+
+ DBG("Close MDL %d", mdl->mdlid);
+
+ notify = (mdl->state == MDL_CONNECTED);
+ shutdown_mdl(mdl);
+
+ update_mcl_state(mdl->mcl);
+
+ if (notify) {
+ /*Callback to upper layer */
+ mdl->mcl->cb->mdl_closed(mdl, mdl->mcl->cb->user_data);
+ }
+
+ return FALSE;
+}
+
static gboolean mcl_control_cb(GIOChannel *chan, GIOCondition cond,
gpointer data)
{
@@ -779,9 +800,57 @@ fail:
return FALSE;
}

+static void connect_dc_event_cb(GIOChannel *chan, GError *err,
+ gpointer user_data)
+{
+ struct mcap_mdl *mdl = user_data;
+ struct mcap_mcl *mcl = mdl->mcl;
+
+ mdl->state = MDL_CONNECTED;
+ mdl->dc = g_io_channel_ref(chan);
+ mdl->wid = g_io_add_watch(mdl->dc, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ (GIOFunc) mdl_event_cb, mdl);
+
+ mcl->state = MCL_ACTIVE;
+ mcl->cb->mdl_connected(mdl, mcl->cb->user_data);
+}
+
static void confirm_dc_event_cb(GIOChannel *chan, gpointer user_data)
{
- /* TODO */
+ struct mcap_instance *ms = user_data;
+ struct mcap_mcl *mcl;
+ struct mcap_mdl *mdl;
+ GError *err = NULL;
+ bdaddr_t dst;
+ GSList *l;
+
+ bt_io_get(chan, BT_IO_L2CAP, &err,
+ BT_IO_OPT_DEST_BDADDR, &dst,
+ BT_IO_OPT_INVALID);
+ if (err) {
+ error("%s", err->message);
+ g_error_free(err);
+ goto drop;
+ }
+
+ mcl = find_mcl(ms->mcls, &dst);
+ if (!mcl || (mcl->state != MCL_PENDING))
+ goto drop;
+
+ for (l = mcl->mdls; l; l = l->next) {
+ mdl = l->data;
+ if (mdl->state == MDL_WAITING) {
+ if (!bt_io_accept(chan, connect_dc_event_cb, mdl, NULL,
+ &err)) {
+ error("MDL accept error %s", err->message);
+ g_error_free(err);
+ goto drop;
+ }
+ return;
+ }
+ }
+drop:
+ g_io_channel_shutdown(chan, TRUE, NULL);
}

static void connect_mcl_event_cb(GIOChannel *chan, GError *err,
--
1.6.3.3


2010-07-22 08:52:06

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 11/60] Process commands in ACTIVE state

---
mcap/mcap.c | 14 +++++++++++++-
1 files changed, 13 insertions(+), 1 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 9f41c6b..cf44472 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -679,7 +679,19 @@ static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)

static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
{
- /* TODO */
+ switch (cmd[0]) {
+ case MCAP_MD_CREATE_MDL_REQ:
+ process_md_create_mdl_req(mcl, cmd, len);
+ break;
+ case MCAP_MD_RECONNECT_MDL_REQ:
+ process_md_reconnect_mdl_req(mcl, cmd, len);
+ break;
+ case MCAP_MD_DELETE_MDL_REQ:
+ process_md_delete_mdl_req(mcl, cmd, len);
+ break;
+ default:
+ error_cmd_rsp(mcl, cmd, len);
+ }
}

static void proc_response(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
--
1.6.3.3


2010-07-22 08:52:05

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 10/60] Process md_abort_mdl_req in PENDING state

---
mcap/mcap.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 49 insertions(+), 1 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index d6a9760..9f41c6b 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -551,6 +551,51 @@ static void process_md_reconnect_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
send4B_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_SUCCESS, mdl_id);
}

+static void process_md_abort_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
+ uint32_t len)
+{
+ mcap_md_req *req;
+ GSList *l;
+ struct mcap_mdl *mdl, *del;
+ uint16_t mdl_id;
+
+ if (len != sizeof(mcap_md_req)) {
+ send4B_cmd(mcl, MCAP_MD_ABORT_MDL_RSP,
+ MCAP_INVALID_PARAM_VALUE, MCAP_MDLID_RESERVED);
+ return;
+ }
+
+ req = (mcap_md_req *)cmd;
+ mdl_id = ntohs(req->mdl);
+ mcl->state = MCL_CONNECTED;
+ for (l = mcl->mdls; l; l = l->next) {
+ mdl = l->data;
+ if ((mdl_id == mdl->mdlid) && (mdl->state == MDL_WAITING)) {
+ del = mdl;
+ if (mcl->state != MCL_CONNECTED)
+ break;
+ continue;
+ }
+ if ((mdl->state == MDL_CONNECTED) && (mcl->state != MCL_ACTIVE))
+ mcl->state = MCL_ACTIVE;
+
+ if ((del) && (mcl->state == MCL_ACTIVE))
+ break;
+ }
+
+ if (!del) {
+ send4B_cmd(mcl, MCAP_MD_ABORT_MDL_RSP, MCAP_INVALID_MDL,
+ mdl_id);
+ return;
+ }
+
+ mcl->cb->mdl_aborted(del, mcl->cb->user_data);
+
+ mcl->mdls = g_slist_remove(mcl->mdls, del);
+ g_free(del);
+ send4B_cmd(mcl, MCAP_MD_ABORT_MDL_RSP, MCAP_SUCCESS, mdl_id);
+}
+
static void process_md_delete_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
uint32_t len)
{
@@ -626,7 +671,10 @@ static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)

static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
{
- /* TODO */
+ if (cmd[0] == MCAP_MD_ABORT_MDL_REQ)
+ process_md_abort_mdl_req(mcl, cmd, len);
+ else
+ error_cmd_rsp(mcl, cmd, len);
}

static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
--
1.6.3.3


2010-07-22 08:52:01

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 06/60] Release MCAP instances

---
mcap/mcap.c | 31 ++++++++++++++++++++++++++++++-
1 files changed, 30 insertions(+), 1 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 8551ddf..0bc5035 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -603,5 +603,34 @@ struct mcap_instance *mcap_create_instance(struct btd_adapter *btd_adapter,

void mcap_release_instance(struct mcap_instance *ms)
{
- /* TODO */
+ GSList *l;
+
+ if (!ms)
+ return;
+
+ if (ms->ccio) {
+ g_io_channel_shutdown(ms->ccio, TRUE, NULL);
+ g_io_channel_unref(ms->ccio);
+ ms->ccio = NULL;
+ }
+
+ if (ms->dcio) {
+ g_io_channel_shutdown(ms->dcio, TRUE, NULL);
+ g_io_channel_unref(ms->dcio);
+ ms->dcio = NULL;
+ }
+
+ for (l = ms->mcls; l; l = l->next) {
+ mcap_mcl_shutdown(l->data);
+ mcap_mcl_unref(l->data);
+ }
+ g_slist_free(ms->mcls);
+ ms->mcls = NULL;
+
+ for (l = ms->cached; l; l = l->next)
+ mcap_mcl_unref(l->data);
+ g_slist_free(ms->cached);
+ ms->cached = NULL;
+
+ g_free(ms);
}
--
1.6.3.3


2010-07-22 08:52:04

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 09/60] Process md_delete_mdl_req in CONNECTED state

---
mcap/mcap.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 87 insertions(+), 1 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index da7edfb..d6a9760 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -173,6 +173,26 @@ static gint compare_mdl(gconstpointer a, gconstpointer b)
return 1;
}

+static void update_mcl_state(struct mcap_mcl *mcl)
+{
+ GSList *l;
+ struct mcap_mdl *mdl;
+
+ if (mcl->state == MCL_PENDING)
+ return;
+
+ for (l = mcl->mdls; l; l = l->next) {
+ mdl = l->data;
+
+ if (mdl->state == MDL_CONNECTED) {
+ mcl->state = MCL_ACTIVE;
+ return;
+ }
+ }
+
+ mcl->state = MCL_CONNECTED;
+}
+
static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr)
{
GSList *l;
@@ -406,6 +426,17 @@ static struct mcap_mdl *get_mdl(struct mcap_mcl *mcl, uint16_t mdlid)
return NULL;
}

+static void mcap_delete_mdl(gpointer elem, gpointer user_data)
+{
+ struct mcap_mdl *mdl = elem;
+ gboolean notify = *(gboolean *)user_data;
+
+ shutdown_mdl(mdl);
+ if (notify)
+ mdl->mcl->cb->mdl_deleted(mdl, mdl->mcl->cb->user_data);
+ g_free(mdl);
+}
+
static void process_md_create_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
uint32_t len)
{
@@ -520,6 +551,61 @@ static void process_md_reconnect_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
send4B_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_SUCCESS, mdl_id);
}

+static void process_md_delete_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
+ uint32_t len)
+{
+ mcap_md_req *req;
+ struct mcap_mdl *mdl, *aux;
+ uint16_t mdlid;
+ gboolean notify;
+ GSList *l;
+
+ if (len != sizeof(mcap_md_req)) {
+ send4B_cmd(mcl, MCAP_MD_ABORT_MDL_RSP,
+ MCAP_INVALID_PARAM_VALUE, MCAP_MDLID_RESERVED);
+ return;
+ }
+
+ req = (mcap_md_req *)cmd;
+ mdlid = ntohs(req->mdl);
+ if (mdlid == MCAP_ALL_MDLIDS) {
+ notify = FALSE;
+ g_slist_foreach(mcl->mdls, mcap_delete_mdl, &notify);
+ g_slist_free(mcl->mdls);
+ mcl->mdls = NULL;
+ mcl->state = MCL_CONNECTED;
+ /* NULL mdl means ALL_MDLS */
+ mcl->cb->mdl_deleted(NULL, mcl->cb->user_data);
+ goto resp;
+ }
+
+ if ((mdlid < MCAP_MDLID_INITIAL) || (mdlid > MCAP_MDLID_FINAL)) {
+ send4B_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_INVALID_MDL,
+ mdlid);
+ return;
+ }
+
+ for (l = mcl->mdls, mdl = NULL; l; l = l->next) {
+ aux = l->data;
+ if (aux->mdlid == mdlid) {
+ mdl = aux;
+ break;
+ }
+ }
+
+ if (!mdl || (mdl->state == MDL_WAITING)) {
+ send4B_cmd(mcl, MCAP_MD_DELETE_MDL_RSP, MCAP_INVALID_MDL,
+ mdlid);
+ return;
+ }
+ mcl->mdls = g_slist_remove(mcl->mdls, mdl);
+ update_mcl_state(mcl);
+ notify = TRUE;
+ mcap_delete_mdl(mdl, &notify);
+resp:
+ send4B_cmd(mcl, MCAP_MD_DELETE_MDL_RSP, MCAP_SUCCESS, mdlid);
+}
+
/* Function used to process commands depending of MCL state */
static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
{
@@ -531,7 +617,7 @@ static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
process_md_reconnect_mdl_req(mcl, cmd, len);
break;
case MCAP_MD_DELETE_MDL_REQ:
- /*process_md_delete_mdl_req(mcl, cmd, len);*/
+ process_md_delete_mdl_req(mcl, cmd, len);
break;
default:
error_cmd_rsp(mcl, cmd, len);
--
1.6.3.3


2010-07-22 08:52:03

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 08/60] Process md_reconnect_mdl_req in CONNECTED state

---
mcap/mcap.c | 44 +++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 43 insertions(+), 1 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index b2d1d86..da7edfb 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -478,6 +478,48 @@ static void process_md_create_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
send5B_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_SUCCESS, mdl_id, conf);
}

+static void process_md_reconnect_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
+ uint32_t len)
+{
+ mcap_md_req *req;
+ struct mcap_mdl *mdl;
+ uint16_t mdl_id;
+ uint8_t rsp;
+
+ if (len != sizeof(mcap_md_req)) {
+ send4B_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP,
+ MCAP_INVALID_PARAM_VALUE, MCAP_MDLID_RESERVED);
+ return;
+ }
+
+ req = (mcap_md_req *)cmd;
+ mdl_id = ntohs(req->mdl);
+
+ mdl = get_mdl(mcl, mdl_id);
+ if (!mdl) {
+ send4B_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP,
+ MCAP_INVALID_MDL, mdl_id);
+ return;
+ }
+
+ /* Callback to upper layer */
+ rsp = mcl->cb->mdl_reconn_req(mdl, mcl->cb->user_data);
+ if (mcl->state == MCL_IDLE)
+ return;
+
+ if (rsp != MCAP_SUCCESS) {
+ send4B_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, rsp, mdl_id);
+ return;
+ }
+
+ if (mdl->state == MDL_CONNECTED)
+ shutdown_mdl(mdl);
+
+ mdl->state = MDL_WAITING;
+ mcl->state = MCL_PENDING;
+ send4B_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_SUCCESS, mdl_id);
+}
+
/* Function used to process commands depending of MCL state */
static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
{
@@ -486,7 +528,7 @@ static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
process_md_create_mdl_req(mcl, cmd, len);
break;
case MCAP_MD_RECONNECT_MDL_REQ:
- /*process_md_reconnect_mdl_req(mcl, cmd, len);*/
+ process_md_reconnect_mdl_req(mcl, cmd, len);
break;
case MCAP_MD_DELETE_MDL_REQ:
/*process_md_delete_mdl_req(mcl, cmd, len);*/
--
1.6.3.3


2010-07-22 08:52:00

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 05/60] Save and restore state of MCLs

---
mcap/mcap.c | 158 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 154 insertions(+), 4 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 5197fde..8551ddf 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -33,8 +33,16 @@
#include "mcap_lib.h"
#include "mcap_internal.h"

+#define MAX_CACHED 10 /* 10 devices */
+
#define MCAP_ERROR g_quark_from_static_string("mcap-error-quark")

+#define RELEASE_TIMER(__mcl) do { \
+ g_source_remove(__mcl->tid); \
+ __mcl->tid = 0; \
+} while(0)
+
+
/* MCAP finite state machine functions */
static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l);
static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l);
@@ -146,24 +154,166 @@ static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr)
return NULL;
}

+static void shutdown_mdl(struct mcap_mdl *mdl)
+{
+ mdl->state = MDL_CLOSED;
+
+ g_source_remove(mdl->wid);
+
+ if (mdl->dc) {
+ g_io_channel_shutdown(mdl->dc, TRUE, NULL);
+ g_io_channel_unref(mdl->dc);
+ mdl->dc = NULL;
+ }
+}
+
+static void mcap_free_mdls(struct mcap_mcl *mcl, gboolean save)
+{
+ GSList *l;
+ struct mcap_mdl *mdl;
+
+ if (!mcl->mdls)
+ return;
+
+ for (l = mcl->mdls; l; l = l->next) {
+ mdl = l->data;
+ shutdown_mdl(mdl);
+ if (!save)
+ g_free(mdl);
+ }
+
+ if (!save) {
+ g_slist_free(mcl->mdls);
+ mcl->mdls = NULL;
+ }
+}
+
+static void close_mcl(struct mcap_mcl *mcl, gboolean save)
+{
+ gboolean store = ((!(mcl->ctrl & MCAP_CTRL_FREE)) && save);
+
+ if (mcl->tid) {
+ RELEASE_TIMER(mcl);
+ }
+
+ if (mcl->cc) {
+ g_io_channel_shutdown(mcl->cc, TRUE, NULL);
+ g_io_channel_unref(mcl->cc);
+ mcl->cc = NULL;
+ }
+
+ g_source_remove(mcl->wid);
+ if (mcl->lcmd) {
+ g_free(mcl->lcmd);
+ mcl->lcmd = NULL;
+ }
+
+ if (mcl->priv_data) {
+ g_free(mcl->priv_data);
+ mcl->priv_data = NULL;
+ }
+
+ mcap_free_mdls(mcl, store);
+
+ if (mcl->cb && !store) {
+ g_free(mcl->cb);
+ mcl->cb = NULL;
+ }
+
+ mcl->state = MCL_IDLE;
+
+ if (store)
+ return;
+
+ g_free(mcl);
+}
+
+static void mcap_mcl_shutdown(struct mcap_mcl *mcl)
+{
+ close_mcl(mcl, TRUE);
+}
+
static void mcap_mcl_release(struct mcap_mcl *mcl)
{
- /* TODO */
+ close_mcl(mcl, FALSE);
}

static void mcap_mcl_check_del(struct mcap_mcl *mcl)
{
- /* TODO */
+ if (mcl->ctrl & MCAP_CTRL_CACHED)
+ mcap_mcl_shutdown(mcl);
+ else
+ mcap_mcl_unref(mcl);
}

static void mcap_cache_mcl(struct mcap_mcl *mcl)
{
- /* TODO */
+ GSList *l;
+ struct mcap_mcl *last;
+ int len;
+
+ if (mcl->ctrl & MCAP_CTRL_CACHED)
+ return;
+
+ mcl->ms->mcls = g_slist_remove(mcl->ms->mcls, mcl);
+
+ if ((mcl->ctrl & MCAP_CTRL_NOCACHE) || (mcl->ref < 2)) {
+ mcap_mcl_unref(mcl);
+ return;
+ }
+
+ DBG("Caching MCL");
+
+ len = g_slist_length(mcl->ms->cached);
+ if (len == MAX_CACHED) {
+ /* Remove the latest cached mcl */
+ l = g_slist_last(mcl->ms->cached);
+ last = l->data;
+ mcl->ms->cached = g_slist_remove(mcl->ms->cached, last);
+ last->ctrl &= ~MCAP_CTRL_CACHED;
+ if (last->ctrl & MCAP_CTRL_CONN) {
+ /* If connection process is not success this MCL will be
+ * freed next time that close_mcl is invoked */
+ last->ctrl |= MCAP_CTRL_FREE;
+ } else {
+ last->ms->mcl_uncached_cb(last, last->ms->user_data);
+ mcap_mcl_unref(last);
+ }
+ }
+
+ mcl->ms->cached = g_slist_prepend(mcl->ms->cached, mcl);
+ mcl->ctrl |= MCAP_CTRL_CACHED;
+ mcap_mcl_shutdown(mcl);
}

static void mcap_uncache_mcl(struct mcap_mcl *mcl)
{
- /* TODO */
+ if (!(mcl->ctrl & MCAP_CTRL_CACHED))
+ return;
+
+ DBG("Got MCL from cache");
+
+ mcl->ms->cached = g_slist_remove(mcl->ms->cached, mcl);
+ mcl->ms->mcls = g_slist_prepend(mcl->ms->mcls, mcl);
+ mcl->ctrl &= ~MCAP_CTRL_CACHED;
+ mcl->ctrl &= ~MCAP_CTRL_FREE;
+}
+
+void mcap_close_mcl(struct mcap_mcl *mcl, gboolean cache)
+{
+ if (!mcl)
+ return;
+
+ if (mcl->cc) {
+ g_io_channel_shutdown(mcl->cc, TRUE, NULL);
+ g_io_channel_unref(mcl->cc);
+ mcl->cc = NULL;
+ }
+
+ mcl->state = MCL_IDLE;
+
+ if (!cache)
+ mcl->ctrl |= MCAP_CTRL_NOCACHE;
}

struct mcap_mcl *mcap_mcl_ref(struct mcap_mcl *mcl)
--
1.6.3.3


2010-07-22 08:51:58

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 03/60] Initial work to process incomming connection of MCLs

---
mcap/mcap.c | 193 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 192 insertions(+), 1 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index d47b451..ea00d73 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -35,14 +35,205 @@

#define MCAP_ERROR g_quark_from_static_string("mcap-error-quark")

+static void default_mdl_connected_cb(struct mcap_mdl *mdl, gpointer data)
+{
+ DBG("MCAP Unmanaged mdl connection");
+}
+
+static void default_mdl_closed_cb(struct mcap_mdl *mdl, gpointer data)
+{
+ DBG("MCAP Unmanaged mdl closed");
+}
+
+static void default_mdl_deleted_cb(struct mcap_mdl *mdl, gpointer data)
+{
+ DBG("MCAP Unmanaged mdl deleted");
+}
+
+static void default_mdl_aborted_cb(struct mcap_mdl *mdl, gpointer data)
+{
+ DBG("MCAP Unmanaged mdl aborted");
+}
+
+static uint8_t default_mdl_conn_req_cb(struct mcap_mcl *mcl,
+ uint8_t mdepid, uint16_t mdlid,
+ uint8_t *conf, gpointer data)
+{
+ DBG("MCAP mdl remote connection aborted");
+ /* Due to this callback isn't managed this request won't be supported */
+ return MCAP_REQUEST_NOT_SUPPORTED;
+}
+
+static uint8_t default_mdl_reconn_req_cb(struct mcap_mdl *mdl,
+ gpointer data)
+{
+ DBG("MCAP mdl remote reconnection aborted");
+ /* Due to this callback isn't managed this request won't be supported */
+ return MCAP_REQUEST_NOT_SUPPORTED;
+}
+
+static void set_default_cb(struct mcap_mcl *mcl)
+{
+ if (!mcl->cb)
+ mcl->cb = g_new0(struct mcap_mdl_cb, 1);
+
+ mcl->cb->mdl_connected = default_mdl_connected_cb;
+ mcl->cb->mdl_closed = default_mdl_closed_cb;
+ mcl->cb->mdl_deleted = default_mdl_deleted_cb;
+ mcl->cb->mdl_aborted = default_mdl_aborted_cb;
+ mcl->cb->mdl_conn_req = default_mdl_conn_req_cb;
+ mcl->cb->mdl_reconn_req = default_mdl_reconn_req_cb;
+}
+
+static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr)
+{
+ GSList *l;
+ struct mcap_mcl *mcl;
+
+ for (l = list; l; l = l->next) {
+ mcl = l->data;
+
+ if (!bacmp(&mcl->addr, addr))
+ return mcl;
+ }
+
+ return NULL;
+}
+
+static void mcap_mcl_release(struct mcap_mcl *mcl)
+{
+ /* TODO */
+}
+
+static void mcap_mcl_check_del(struct mcap_mcl *mcl)
+{
+ /* TODO */
+}
+
+static void mcap_uncache_mcl(struct mcap_mcl *mcl)
+{
+ /* TODO */
+}
+
+struct mcap_mcl *mcap_mcl_ref(struct mcap_mcl *mcl)
+{
+ mcl->ref++;
+
+ DBG("mcap_mcl_ref(%p): ref=%d", mcl, mcl->ref);
+
+ return mcl;
+}
+
+void mcap_mcl_unref(struct mcap_mcl *mcl)
+{
+ mcl->ref--;
+
+ DBG("mcap_mcl_unref(%p): ref=%d", mcl, mcl->ref);
+
+ if (mcl->ref > 0)
+ return;
+
+ mcap_mcl_release(mcl);
+}
+
+static gboolean mcl_control_cb(GIOChannel *chan, GIOCondition cond,
+ gpointer data)
+{
+
+ /* TODO */
+ return FALSE;
+}
+
static void confirm_dc_event_cb(GIOChannel *chan, gpointer user_data)
{
/* TODO */
}

+static void connect_mcl_event_cb(GIOChannel *chan, GError *err,
+ gpointer user_data)
+{
+ struct mcap_mcl *mcl = user_data;
+ gboolean reconn;
+
+ if (err) {
+ mcap_mcl_check_del(mcl);
+ return;
+ }
+
+ mcl->state = MCL_CONNECTED;
+ mcl->role = MCL_ACCEPTOR;
+ mcl->req = MCL_AVAILABLE;
+ mcl->cc = g_io_channel_ref(chan);
+ mcl->ctrl |= MCAP_CTRL_STD_OP;
+
+ reconn = (mcl->ctrl & MCAP_CTRL_CACHED);
+ if (reconn)
+ mcap_uncache_mcl(mcl);
+ else
+ mcl->ms->mcls = g_slist_prepend(mcl->ms->mcls, mcl);
+
+ mcl->wid = g_io_add_watch(mcl->cc,
+ G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ (GIOFunc) mcl_control_cb, mcl);
+
+ /* Callback to report new MCL */
+ if (reconn)
+ mcl->ms->mcl_reconnected_cb(mcl, mcl->ms->user_data);
+ else
+ mcl->ms->mcl_connected_cb(mcl, mcl->ms->user_data);
+
+ if (mcl->ref == 1) {
+ mcl->ms->mcls = g_slist_remove(mcl->ms->mcls, mcl);
+ mcap_mcl_unref(mcl);
+ }
+}
+
static void confirm_mcl_event_cb(GIOChannel *chan, gpointer user_data)
{
- /* TODO */
+ struct mcap_instance *ms = user_data;
+ struct mcap_mcl *mcl;
+ bdaddr_t dst;
+ char address[18], srcstr[18];
+ GError *err = NULL;
+
+ bt_io_get(chan, BT_IO_L2CAP, &err,
+ BT_IO_OPT_DEST_BDADDR, &dst,
+ BT_IO_OPT_DEST, address,
+ BT_IO_OPT_INVALID);
+ if (err) {
+ error("%s", err->message);
+ g_error_free(err);
+ goto drop;
+ }
+
+ ba2str(&ms->src, srcstr);
+ mcl = find_mcl(ms->mcls, &dst);
+ if (mcl) {
+ error("Control channel already created with %s on adapter %s",
+ address, srcstr);
+ goto drop;
+ }
+
+ mcl = find_mcl(ms->cached, &dst);
+ if (!mcl) {
+ mcl = g_new0(struct mcap_mcl, 1);
+ mcl->ms = ms;
+ bacpy(&mcl->addr, &dst);
+ set_default_cb(mcl);
+ mcl = mcap_mcl_ref(mcl);
+ }
+
+ if (!bt_io_accept(chan, connect_mcl_event_cb, mcl, NULL, &err)) {
+ error("mcap accept error: %s", err->message);
+ if (!(mcl->ctrl & MCAP_CTRL_CACHED))
+ mcap_mcl_unref(mcl);
+ g_error_free(err);
+ goto drop;
+ }
+
+ return;
+drop:
+ g_io_channel_shutdown(chan, TRUE, NULL);
}

struct mcap_instance *mcap_create_instance(struct btd_adapter *btd_adapter,
--
1.6.3.3


2010-07-22 08:51:57

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 02/60] Initial work to create MCAP instances

---
mcap/mcap.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 71 insertions(+), 2 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 8bd2ad2..d47b451 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -33,6 +33,18 @@
#include "mcap_lib.h"
#include "mcap_internal.h"

+#define MCAP_ERROR g_quark_from_static_string("mcap-error-quark")
+
+static void confirm_dc_event_cb(GIOChannel *chan, gpointer user_data)
+{
+ /* TODO */
+}
+
+static void confirm_mcl_event_cb(GIOChannel *chan, gpointer user_data)
+{
+ /* TODO */
+}
+
struct mcap_instance *mcap_create_instance(struct btd_adapter *btd_adapter,
BtIOSecLevel sec,
uint16_t ccpsm,
@@ -44,8 +56,65 @@ struct mcap_instance *mcap_create_instance(struct btd_adapter *btd_adapter,
mcap_mcl_event_cb mcl_uncached,
gpointer user_data)
{
- /* TODO */
- return NULL;
+ struct mcap_instance *ms;
+
+ if (sec < BT_IO_SEC_MEDIUM) {
+ g_set_error(gerr, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS,
+ "Security level can't be minor of %d",
+ BT_IO_SEC_MEDIUM);
+ return NULL;
+ }
+
+ if (!(mcl_connected && mcl_reconnected &&
+ mcl_disconnected && mcl_uncached)) {
+ g_set_error(gerr, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS,
+ "The callbacks can't be null");
+ return NULL;
+ }
+
+ ms = g_new0(struct mcap_instance, 1);
+
+ adapter_get_address(btd_adapter, &ms->src);
+
+ ms->sec = sec;
+ ms->mcl_connected_cb = mcl_connected;
+ ms->mcl_reconnected_cb = mcl_reconnected;
+ ms->mcl_disconnected_cb = mcl_disconnected;
+ ms->mcl_uncached_cb = mcl_uncached;
+ ms->user_data = user_data;
+
+ /* Listen incoming connections in control channel */
+ ms->ccio = bt_io_listen(BT_IO_L2CAP, NULL, confirm_mcl_event_cb, ms,
+ NULL, gerr,
+ BT_IO_OPT_SOURCE_BDADDR, &ms->src,
+ BT_IO_OPT_PSM, ccpsm,
+ BT_IO_OPT_MTU, MCAP_CC_MTU,
+ BT_IO_OPT_SEC_LEVEL, sec,
+ BT_IO_OPT_INVALID);
+ if (!ms->ccio) {
+ error("%s", (*gerr)->message);
+ g_free(ms);
+ return NULL;
+ }
+
+ /* Listen incoming connections in data channels */
+ ms->dcio = bt_io_listen(BT_IO_L2CAP, NULL, confirm_dc_event_cb, ms,
+ NULL, gerr,
+ BT_IO_OPT_SOURCE_BDADDR, &ms->src,
+ BT_IO_OPT_PSM, dcpsm,
+ BT_IO_OPT_MTU, MCAP_DC_MTU,
+ BT_IO_OPT_SEC_LEVEL, sec,
+ BT_IO_OPT_INVALID);
+ if (!ms->dcio) {
+ g_io_channel_shutdown(ms->ccio, TRUE, NULL);
+ g_io_channel_unref(ms->ccio);
+ ms->ccio = NULL;
+ error("%s", (*gerr)->message);
+ g_free(ms);
+ return NULL;
+ }
+
+ return ms;
}

void mcap_release_instance(struct mcap_instance *ms)
--
1.6.3.3


2010-07-22 08:51:59

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 04/60] Process events over Control Channels

---
mcap/mcap.c | 145 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 144 insertions(+), 1 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index ea00d73..5197fde 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -35,6 +35,17 @@

#define MCAP_ERROR g_quark_from_static_string("mcap-error-quark")

+/* MCAP finite state machine functions */
+static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l);
+static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l);
+static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l);
+
+static void (*proc_req[])(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) = {
+ proc_req_connected,
+ proc_req_pending,
+ proc_req_active
+};
+
static void default_mdl_connected_cb(struct mcap_mdl *mdl, gpointer data)
{
DBG("MCAP Unmanaged mdl connection");
@@ -85,6 +96,41 @@ static void set_default_cb(struct mcap_mcl *mcl)
mcl->cb->mdl_reconn_req = default_mdl_reconn_req_cb;
}

+int mcap_send_data(int sock, const uint8_t *buf, uint32_t size)
+{
+ uint32_t sent = 0;
+
+ while (sent < size) {
+ int n = send(sock, buf + sent, size - sent, 0);
+ if (n < 0)
+ return -1;
+ sent += n;
+ }
+ return 0;
+}
+
+static int send4B_cmd(struct mcap_mcl *mcl, uint8_t oc, uint8_t rc,
+ uint16_t mdl)
+{
+ uint8_t *rsp;
+ mcap4B_rsp *rsp_err;
+ int sent;
+
+
+ rsp = g_malloc0(sizeof(mcap4B_rsp));
+
+ rsp_err = (mcap4B_rsp *)rsp;
+ rsp_err->op = oc;
+ rsp_err->rc = rc;
+ rsp_err->mdl = htons (mdl);
+
+ sent = mcap_send_data(g_io_channel_unix_get_fd(mcl->cc),
+ rsp,
+ sizeof(mcap4B_rsp));
+ g_free(rsp);
+ return sent;
+}
+
static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr)
{
GSList *l;
@@ -110,6 +156,11 @@ static void mcap_mcl_check_del(struct mcap_mcl *mcl)
/* TODO */
}

+static void mcap_cache_mcl(struct mcap_mcl *mcl)
+{
+ /* TODO */
+}
+
static void mcap_uncache_mcl(struct mcap_mcl *mcl)
{
/* TODO */
@@ -136,11 +187,103 @@ void mcap_mcl_unref(struct mcap_mcl *mcl)
mcap_mcl_release(mcl);
}

+static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
+{
+ /* TODO */
+}
+
+static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
+{
+ /* TODO */
+}
+
+static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
+{
+ /* TODO */
+}
+
+static void proc_response(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
+{
+ /* TODO */
+}
+
+static void rsend_req(struct mcap_mcl *mcl)
+{
+ uint8_t *cmd = mcl->lcmd;
+ int len;
+
+ if (!cmd)
+ return;
+
+ switch (cmd[0]) {
+ case MCAP_MD_RECONNECT_MDL_REQ:
+ case MCAP_MD_ABORT_MDL_REQ:
+ case MCAP_MD_DELETE_MDL_REQ:
+ len = 3;
+ break;
+ case MCAP_MD_CREATE_MDL_REQ:
+ len = 5;
+ break;
+ default:
+ return;
+ }
+
+ mcap_send_data(g_io_channel_unix_get_fd(mcl->cc), cmd, len);
+}
+
+static void proc_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
+{
+ if ((cmd[0] >= MCAP_MD_SYNC_CAP_REQ) &&
+ (cmd[0] <= MCAP_MD_SYNC_INFO_IND)) {
+ send4B_cmd(mcl, cmd[0], MCAP_REQUEST_NOT_SUPPORTED,
+ MCAP_MDLID_RESERVED);
+ return;
+ }
+
+ if (!(mcl->ctrl & MCAP_CTRL_STD_OP)) {
+ /* In case the remote device doesn't work correctly */
+ error("Remote device does not support opcodes, cmd ignored");
+ return;
+ }
+
+ if (mcl->req == MCL_WAITING_RSP) {
+ if (cmd[0] & 0x01) {
+ /* Request arrived when a response is expected */
+ if (mcl->role == MCL_INITIATOR)
+ /* ignore */
+ return;
+ proc_req[mcl->state](mcl, cmd, len);
+ /* Initiator will ignore our last request => re-send */
+ rsend_req(mcl);
+ return;
+ }
+ proc_response(mcl, cmd, len);
+ } else if (cmd[0] & 0x01)
+ proc_req[mcl->state](mcl, cmd, len);
+}
+
static gboolean mcl_control_cb(GIOChannel *chan, GIOCondition cond,
gpointer data)
{

- /* TODO */
+ struct mcap_mcl *mcl = data;
+ int sk, len;
+ uint8_t buf[MCAP_CC_MTU];
+
+ if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
+ goto fail;
+
+ sk = g_io_channel_unix_get_fd(chan);
+ len = recv(sk, buf, sizeof(buf), 0);
+ if (len < 0)
+ goto fail;
+
+ proc_cmd(mcl, buf, (uint32_t)len);
+ return TRUE;
+fail:
+ if (mcl->state != MCL_IDLE)
+ mcl->ms->mcl_disconnected_cb(mcl, mcl->ms->user_data);
+ mcap_cache_mcl(mcl);
return FALSE;
}

--
1.6.3.3


2010-07-22 08:51:56

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 01/60] Initial support for MCAP

---
Makefile.am | 13 ++++-
acinclude.m4 | 6 ++
mcap/mcap.c | 54 ++++++++++++++++
mcap/mcap.h | 165 ++++++++++++++++++++++++++++++++++++++++++++++++++
mcap/mcap_internal.h | 118 +++++++++++++++++++++++++++++++++++
mcap/mcap_lib.h | 161 ++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 516 insertions(+), 1 deletions(-)
create mode 100644 mcap/mcap.c
create mode 100644 mcap/mcap.h
create mode 100644 mcap/mcap_internal.h
create mode 100644 mcap/mcap_lib.h

diff --git a/Makefile.am b/Makefile.am
index f4bf87d..d1e6b0e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -102,6 +102,7 @@ gdbus_sources = gdbus/gdbus.h gdbus/mainloop.c gdbus/object.c gdbus/watch.c
builtin_modules =
builtin_sources =
builtin_nodist =
+mcap_sources =

if PNATPLUGIN
builtin_modules += pnat
@@ -168,6 +169,12 @@ builtin_modules += service
builtin_sources += plugins/service.c
endif

+if MCAP
+mcap_sources += mcap/mcap_internal.h \
+ mcap/mcap_lib.h \
+ mcap/mcap.h mcap/mcap.c
+endif
+
builtin_modules += hciops
builtin_sources += plugins/hciops.c

@@ -201,7 +208,8 @@ src_bluetoothd_SOURCES = $(gdbus_sources) $(builtin_sources) \
src/adapter.h src/adapter.c \
src/device.h src/device.c \
src/dbus-common.c src/dbus-common.h \
- src/dbus-hci.h src/dbus-hci.c
+ src/dbus-hci.h src/dbus-hci.c \
+ $(mcap_sources)
src_bluetoothd_LDADD = lib/libbluetooth.la @GLIB_LIBS@ @DBUS_LIBS@ \
@CAPNG_LIBS@ -ldl
src_bluetoothd_LDFLAGS = -Wl,--export-dynamic \
@@ -323,6 +331,9 @@ AM_CFLAGS = @DBUS_CFLAGS@ @GLIB_CFLAGS@ @CAPNG_CFLAGS@ \
INCLUDES = -I$(builddir)/lib -I$(builddir)/src -I$(srcdir)/src \
-I$(srcdir)/audio -I$(srcdir)/sbc -I$(srcdir)/gdbus

+if MCAP
+INCLUDES += -I$(builddir)/mcap
+endif

pkgconfigdir = $(libdir)/pkgconfig

diff --git a/acinclude.m4 b/acinclude.m4
index f5fdd66..db71da3 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -167,6 +167,7 @@ AC_DEFUN([AC_ARG_BLUEZ], [
serial_enable=yes
network_enable=yes
service_enable=yes
+ mcap_enable=no
pnat_enable=no
tracer_enable=no
tools_enable=yes
@@ -216,6 +217,10 @@ AC_DEFUN([AC_ARG_BLUEZ], [
service_enable=${enableval}
])

+ AC_ARG_ENABLE(mcap, AC_HELP_STRING([--enable-mcap], [enable mcap support]), [
+ mcap_enable=${enableval}
+ ])
+
AC_ARG_ENABLE(pnat, AC_HELP_STRING([--enable-pnat], [enable pnat plugin]), [
pnat_enable=${enableval}
])
@@ -330,6 +335,7 @@ AC_DEFUN([AC_ARG_BLUEZ], [
AM_CONDITIONAL(SERIALPLUGIN, test "${serial_enable}" = "yes")
AM_CONDITIONAL(NETWORKPLUGIN, test "${network_enable}" = "yes")
AM_CONDITIONAL(SERVICEPLUGIN, test "${service_enable}" = "yes")
+ AM_CONDITIONAL(MCAP, test "${mcap_enable}" = "yes")
AM_CONDITIONAL(ECHOPLUGIN, test "no" = "yes")
AM_CONDITIONAL(PNATPLUGIN, test "${pnat_enable}" = "yes")
AM_CONDITIONAL(TRACER, test "${tracer_enable}" = "yes")
diff --git a/mcap/mcap.c b/mcap/mcap.c
new file mode 100644
index 0000000..8bd2ad2
--- /dev/null
+++ b/mcap/mcap.c
@@ -0,0 +1,54 @@
+/*
+ *
+ * MCAP for BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ *
+ * Authors:
+ * Santiago Carot-Nemesio <sancane at gmail.com>
+ * Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "log.h"
+#include "error.h"
+
+#include <netinet/in.h>
+
+#include "mcap.h"
+#include "mcap_lib.h"
+#include "mcap_internal.h"
+
+struct mcap_instance *mcap_create_instance(struct btd_adapter *btd_adapter,
+ BtIOSecLevel sec,
+ uint16_t ccpsm,
+ uint16_t dcpsm,
+ GError **gerr,
+ mcap_mcl_event_cb mcl_connected,
+ mcap_mcl_event_cb mcl_reconnected,
+ mcap_mcl_event_cb mcl_disconnected,
+ mcap_mcl_event_cb mcl_uncached,
+ gpointer user_data)
+{
+ /* TODO */
+ return NULL;
+}
+
+void mcap_release_instance(struct mcap_instance *ms)
+{
+ /* TODO */
+}
diff --git a/mcap/mcap.h b/mcap/mcap.h
new file mode 100644
index 0000000..0299f42
--- /dev/null
+++ b/mcap/mcap.h
@@ -0,0 +1,165 @@
+/*
+ *
+ * MCAP for BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ *
+ * Authors:
+ * Santiago Carot-Nemesio <sancane at gmail.com>
+ * Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __MCAP_H
+#define __MCAP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MCAP_VERSION 0x0100 /* current version 01.00 */
+
+/* bytes to get MCAP Supported Procedures */
+#define MCAP_SUP_PROC 0x06
+
+/* maximum transmission unit for channels */
+#define MCAP_CC_MTU 48
+#define MCAP_DC_MTU L2CAP_DEFAULT_MTU
+
+
+/* MCAP Standard Op Codes */
+#define MCAP_ERROR_RSP 0x00
+#define MCAP_MD_CREATE_MDL_REQ 0x01
+#define MCAP_MD_CREATE_MDL_RSP 0x02
+#define MCAP_MD_RECONNECT_MDL_REQ 0x03
+#define MCAP_MD_RECONNECT_MDL_RSP 0x04
+#define MCAP_MD_ABORT_MDL_REQ 0x05
+#define MCAP_MD_ABORT_MDL_RSP 0x06
+#define MCAP_MD_DELETE_MDL_REQ 0x07
+#define MCAP_MD_DELETE_MDL_RSP 0x08
+
+/* MCAP Clock Sync Op Codes */
+#define MCAP_MD_SYNC_CAP_REQ 0x11
+#define MCAP_MD_SYNC_CAP_RSP 0x12
+#define MCAP_MD_SYNC_SET_REQ 0x13
+#define MCAP_MD_SYNC_SET_RSP 0x14
+#define MCAP_MD_SYNC_INFO_IND 0x15
+
+/* MCAP Response codes */
+#define MCAP_SUCCESS 0x00
+#define MCAP_INVALID_OP_CODE 0x01
+#define MCAP_INVALID_PARAM_VALUE 0x02
+#define MCAP_INVALID_MDEP 0x03
+#define MCAP_MDEP_BUSY 0x04
+#define MCAP_INVALID_MDL 0x05
+#define MCAP_MDL_BUSY 0x06
+#define MCAP_INVALID_OPERATION 0x07
+#define MCAP_RESOURCE_UNAVAILABLE 0x08
+#define MCAP_UNSPECIFIED_ERROR 0x09
+#define MCAP_REQUEST_NOT_SUPPORTED 0x0A
+#define MCAP_CONFIGURATION_REJECTED 0x0B
+
+/* MDL IDs */
+#define MCAP_MDLID_RESERVED 0x0000
+#define MCAP_MDLID_INITIAL 0x0001
+#define MCAP_MDLID_FINAL 0xFEFF
+#define MCAP_ALL_MDLIDS 0xFFFF
+
+/* MDEP IDs */
+#define MCAP_MDEPID_INITIAL 0x00
+#define MCAP_MDEPID_FINAL 0x7F
+
+
+/*
+ * MCAP Request Packet Format
+ */
+
+typedef struct {
+ uint8_t op;
+ uint16_t mdl;
+ uint8_t mdep;
+ uint8_t conf;
+} __attribute__ ((packed)) mcap_md_create_mdl_req;
+
+typedef struct {
+ uint8_t op;
+ uint16_t mdl;
+} __attribute__ ((packed)) mcap_md_req;
+
+
+/*
+ * MCAP Response Packet Format
+ */
+
+typedef struct {
+ uint8_t op;
+ uint8_t rc;
+ uint16_t mdl;
+} __attribute__ ((packed)) mcap4B_rsp;
+
+typedef struct {
+ uint8_t op;
+ uint8_t rc;
+ uint16_t mdl;
+ uint8_t param;
+} __attribute__ ((packed)) mcap5B_rsp;
+
+
+/*
+ * MCAP Clock Synchronization Protocol
+ */
+typedef struct {
+ uint8_t op;
+ uint16_t timest;
+} __attribute__ ((packed)) mcap_md_sync_cap_req;
+
+typedef struct {
+ uint8_t op;
+ uint8_t rc;
+ uint8_t btclock;
+ uint16_t sltime;
+ uint16_t timestnr;
+ uint16_t timestna;
+} __attribute__ ((packed)) mcap_md_sync_cap_rsp;
+
+typedef struct {
+ uint8_t op;
+ uint8_t timestui;
+ uint32_t btclock;
+ uint64_t timestst;
+} __attribute__ ((packed)) mcap_md_sync_set_req;
+
+typedef struct {
+ uint8_t op;
+ uint8_t rc;
+ uint32_t btclock;
+ uint64_t timestst;
+ uint16_t timestsa;
+} __attribute__ ((packed)) mcap_md_sync_set_rsp;
+
+typedef struct {
+ uint8_t op;
+ uint32_t btclock;
+ uint64_t timestst;
+ uint16_t timestsa;
+} __attribute__ ((packed)) mcap_md_sync_info_ind;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MCAP_H */
diff --git a/mcap/mcap_internal.h b/mcap/mcap_internal.h
new file mode 100644
index 0000000..3aaeed5
--- /dev/null
+++ b/mcap/mcap_internal.h
@@ -0,0 +1,118 @@
+/*
+ *
+ * MCAP for BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ *
+ * Authors:
+ * Santiago Carot-Nemesio <sancane at gmail.com>
+ * Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __MCAP_INTERNAL_H
+#define __MCAP_INTERNAL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ MCL_CONNECTED,
+ MCL_PENDING,
+ MCL_ACTIVE,
+ MCL_IDLE
+} MCLState;
+
+typedef enum {
+ MCL_ACCEPTOR,
+ MCL_INITIATOR
+} MCLRole;
+
+typedef enum {
+ MCL_AVAILABLE,
+ MCL_WAITING_RSP
+} MCAPCtrl;
+
+typedef enum {
+ MDL_WAITING,
+ MDL_CONNECTED,
+ MDL_DELETING,
+ MDL_CLOSED
+} MDLState;
+
+struct mcap_mdl_cb {
+ mcap_mdl_event_cb mdl_connected; /* Remote device has created a MDL */
+ mcap_mdl_event_cb mdl_closed; /* Remote device has closed a MDL */
+ mcap_mdl_event_cb mdl_deleted; /* Remote device requested deleting a MDL */
+ mcap_mdl_event_cb mdl_aborted; /* Remote device aborted the mdl creation */
+ mcap_remote_mdl_conn_req_cb mdl_conn_req; /* Remote device requested creating a MDL */
+ mcap_remote_mdl_reconn_req_cb mdl_reconn_req; /* Remote device requested reconnecting a MDL */
+ gpointer user_data; /* User data */
+};
+
+struct mcap_instance {
+ bdaddr_t src; /* Source address */
+ GIOChannel *ccio; /* Control Channel IO */
+ GIOChannel *dcio; /* Data Channel IO */
+ GSList *mcls; /* MCAP instance list */
+ GSList *cached; /* List with all cached MCLs (MAX_CACHED macro) */
+ BtIOSecLevel sec; /* Security level */
+ mcap_mcl_event_cb mcl_connected_cb; /* New MCL connected */
+ mcap_mcl_event_cb mcl_reconnected_cb; /* Old MCL has been reconnected */
+ mcap_mcl_event_cb mcl_disconnected_cb; /* MCL disconnected */
+ mcap_mcl_event_cb mcl_uncached_cb; /* MCL has been removed from MCAP cache */
+ gpointer user_data; /* Data to be provided in callbacks */
+};
+
+struct mcap_mcl {
+ struct mcap_instance *ms; /* MCAP instance where this MCL belongs */
+ bdaddr_t addr; /* Device address */
+ GIOChannel *cc; /* MCAP Control Channel IO */
+ guint wid; /* MCL Watcher id */
+ GSList *mdls; /* List of Data Channels shorted by mdlid */
+ MCLState state; /* Current MCL State */
+ MCLRole role; /* Initiator or acceptor of this MCL */
+ MCAPCtrl req; /* Request control flag */
+ void *priv_data; /* Temporal data to manage in responses */
+ struct mcap_mdl_cb *cb; /* MDL callbacks */
+ guint tid; /* Timer id for waiting for a response */
+ uint8_t *lcmd; /* Last command sent */
+ guint ref; /* References counter */
+ uint8_t ctrl; /* MCL control flag */
+};
+
+#define MCAP_CTRL_CACHED 0x01 /* MCL is cached */
+#define MCAP_CTRL_STD_OP 0x02 /* Support for standard op codes */
+#define MCAP_CTRL_SYNC_OP 0x04 /* Support for synchronization commands */
+#define MCAP_CTRL_CONN 0x08 /* MCL is in connecting process */
+#define MCAP_CTRL_FREE 0x10 /* MCL is marked as releasable */
+#define MCAP_CTRL_NOCACHE 0x20 /* MCL is marked as not cacheable */
+
+struct mcap_mdl {
+ struct mcap_mcl *mcl; /* MCL where this MDL belongs */
+ GIOChannel *dc; /* MCAP Data Channel IO */
+ guint wid; /* MDL Watcher id */
+ uint16_t mdlid; /* MDL id */
+ uint8_t mdep_id; /* MCAP Data End Point */
+ MDLState state; /* MDL state */
+};
+
+int mcap_send_data(int sock, const uint8_t *buf, uint32_t size);
+void proc_sync_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len);
+
+#endif /* __MCAP_INTERNAL_H */
diff --git a/mcap/mcap_lib.h b/mcap/mcap_lib.h
new file mode 100644
index 0000000..2283dac
--- /dev/null
+++ b/mcap/mcap_lib.h
@@ -0,0 +1,161 @@
+/*
+ *
+ * MCAP for BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ *
+ * Authors:
+ * Santiago Carot-Nemesio <sancane at gmail.com>
+ * Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __MCAP_LIB_H
+#define __MCAP_LIB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "adapter.h"
+#include "btio.h"
+#include <bluetooth/l2cap.h>
+
+typedef enum {
+/* MCAP Error Response Codes */
+ MCAP_ERROR_INVALID_OP_CODE = 1,
+ MCAP_ERROR_INVALID_PARAM_VALUE,
+ MCAP_ERROR_INVALID_MDEP,
+ MCAP_ERROR_MDEP_BUSY,
+ MCAP_ERROR_INVALID_MDL,
+ MCAP_ERROR_MDL_BUSY,
+ MCAP_ERROR_INVALID_OPERATION,
+ MCAP_ERROR_RESOURCE_UNAVAILABLE,
+ MCAP_ERROR_UNSPECIFIED_ERROR,
+ MCAP_ERROR_REQUEST_NOT_SUPPORTED,
+ MCAP_ERROR_CONFIGURATION_REJECTED,
+/* MCAP Internal Errors */
+ MCAP_ERROR_INVALID_ARGS,
+ MCAP_ERROR_ALREADY_EXISTS,
+ MCAP_ERROR_FAILED
+} McapError;
+
+typedef enum {
+ MCAP_MDL_CB_INVALID,
+ MCAP_MDL_CB_CONNECTED, /* mcap_mdl_event_cb */
+ MCAP_MDL_CB_CLOSED, /* mcap_mdl_event_cb */
+ MCAP_MDL_CB_DELETED, /* mcap_mdl_event_cb */
+ MCAP_MDL_CB_ABORTED, /* mcap_mdl_event_cb */
+ MCAP_MDL_CB_REMOTE_CONN_REQ, /* mcap_remote_mdl_conn_req_cb */
+ MCAP_MDL_CB_REMOTE_RECONN_REQ /* mcap_remote_mdl_reconn_req_cb */
+} McapMclCb;
+
+struct mcap_instance;
+struct mcap_mcl;
+struct mcap_mdl;
+
+/************ Callbacks ************/
+
+/* mdl callbacks */
+
+typedef void (* mcap_mdl_event_cb) (struct mcap_mdl *mdl, gpointer data);
+typedef void (* mcap_mdl_operation_conf_cb) (struct mcap_mdl *mdl, uint8_t conf,
+ GError *err, gpointer data);
+typedef void (* mcap_mdl_operation_cb) (struct mcap_mdl *mdl, GError *err,
+ gpointer data);
+typedef void (* mcap_mdl_del_cb) (GError *err, gpointer data);
+
+/* Next function should return an MCAP appropriate response code */
+typedef uint8_t (* mcap_remote_mdl_conn_req_cb) (struct mcap_mcl *mcl,
+ uint8_t mdepid, uint16_t mdlid,
+ uint8_t *conf, gpointer data);
+typedef uint8_t (* mcap_remote_mdl_reconn_req_cb) (struct mcap_mdl *mdl,
+ gpointer data);
+
+/* mcl callbacks */
+
+typedef void (* mcap_mcl_event_cb) (struct mcap_mcl *mcl, gpointer data);
+typedef void (* mcap_mcl_connect_cb) (struct mcap_mcl *mcl, GError *err,
+ gpointer data);
+
+/************ Operations ************/
+
+/* Mdl operations*/
+
+void mcap_req_mdl_creation(struct mcap_mcl *mcl,
+ uint8_t mdepid,
+ uint8_t conf,
+ GError **err,
+ mcap_mdl_operation_conf_cb connect_cb,
+ gpointer user_data);
+void mcap_req_mdl_reconnect(struct mcap_mdl *mdl, GError **err,
+ mcap_mdl_operation_cb reconnect_cb,
+ gpointer user_data);
+void mcap_req_mdl_delete_all(struct mcap_mcl *mcl, GError **err,
+ mcap_mdl_del_cb delete_cb, gpointer user_data);
+void mcap_req_mdl_deletion(struct mcap_mdl *mdl, GError **err,
+ mcap_mdl_del_cb delete_cb, gpointer user_data);
+void mcap_mdl_connect(struct mcap_mdl *mdl,
+ BtIOType BtType,
+ uint16_t dcpsm,
+ GError **err,
+ mcap_mdl_operation_cb connect_cb,
+ gpointer user_data);
+void mcap_mdl_abort(struct mcap_mdl *mdl, GError **err,
+ mcap_mdl_del_cb abort_cb, gpointer user_data);
+
+int mcap_mdl_get_fd(struct mcap_mdl *mdl);
+uint16_t mcap_mdl_get_mdlid(struct mcap_mdl *mdl);
+
+/* Mcl operations*/
+
+void mcap_create_mcl(struct mcap_instance *ms,
+ const bdaddr_t *addr,
+ uint16_t ccpsm,
+ GError **err,
+ mcap_mcl_connect_cb connect_cb,
+ gpointer user_data);
+void mcap_close_mcl(struct mcap_mcl *mcl, gboolean cache);
+void mcap_mcl_set_cb(struct mcap_mcl *mcl, GError **gerr,
+ gpointer user_data, McapMclCb cb1, ...);
+bdaddr_t mcap_mcl_get_addr(struct mcap_mcl *mcl);
+
+struct mcap_mcl *mcap_mcl_ref(struct mcap_mcl *mcl);
+void mcap_mcl_unref(struct mcap_mcl *mcl);
+
+/* MCAP main operations */
+
+struct mcap_instance *mcap_create_instance(struct btd_adapter *btd_adapter,
+ BtIOSecLevel sec, uint16_t ccpsm,
+ uint16_t dcpsm,
+ GError **gerr,
+ mcap_mcl_event_cb mcl_connected,
+ mcap_mcl_event_cb mcl_reconnected,
+ mcap_mcl_event_cb mcl_disconnected,
+ mcap_mcl_event_cb mcl_uncached,
+ gpointer user_data);
+
+void mcap_release_instance(struct mcap_instance *ms);
+
+uint16_t mcap_get_ctrl_psm(struct mcap_instance *ms, GError **err);
+uint16_t mcap_get_data_psm(struct mcap_instance *ms, GError **err);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MCAP_LIB_H */
--
1.6.3.3