Linux bluetooth development
 help / color / mirror / Atom feed
* Re: Software caused connection abort (103 )
From: john michelle @ 2010-05-15 11:52 UTC (permalink / raw)
  To: Gustavo F. Padovan; +Cc: linux-bluetooth
In-Reply-To: <AANLkTilSynGNcpdq8h5YJQVD8e5MMyUDq55WzsB05AA2@mail.gmail.com>

Hi all,

It seems that i am not the only one who is reporting this problem
below is other reporters

http://www.mp3car.com/vbulletin/linux/125997-hfp-linux-bluetooth-hands-free-5.html

even an older post show this bug

http://osdir.com/ml/linux.bluez.user/2004-04/msg00016.html

I hope we got someone attention.


John

On Fri, May 14, 2010 at 12:39 AM, john michelle <jhnmichelle@gmail.com> wrote:
> Hi Gustavo,
>
> Any update on the software caused connection abort issue, it's happenning more
> And more making bluez unstable for our application
>
> John
>
> On Fri, May 7, 2010 at 3:53 PM, Gustavo F. Padovan <gustavo@padovan.org> wrote:
>> * john michelle <jhnmichelle@gmail.com> [2010-05-07 15:49:05 -0400]:
>>
>>> Hi Bluetooth hackers,
>>>
>>> i am having this consistent problem with bluez , from time to time i
>>> get the error Software caused connection abort (103 )
>>> And the bluetooth stick seems to disconnect and reconnects. this
>>> happens during an sco connection and it occurs even
>>> More when i am having the voice stream comming through the internet
>>> rather than the lan.i don't know what exact
>>> Details you need to solve this problem please tell me and i will give
>>> you an immediate reply . i have linux kernel 2.6.33 and bluez 4.62
>>
>> I get the same problem sometimes when testing ERTM with l2test. So the
>> problem is on l2cap too. I didn't have time to debug this yet. Now that
>> someone else have confirmed it too, I'll to take a look at the problem.
>>
>>>
>>> John
>>> --
>>> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
>>> the body of a message to majordomo@vger.kernel.org
>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>
>> --
>> Gustavo F. Padovan
>> http://padovan.org
>>
>

^ permalink raw reply

* Re: configure the range of the scanning of a dongle
From: Iain Hibbert @ 2010-05-15  6:42 UTC (permalink / raw)
  To: Lorenzo Brito Morales; +Cc: linux-bluetooth
In-Reply-To: <AANLkTiktTYVQoG6NfaGfosltKuYi1ANNIgWtfZQiRWq2@mail.gmail.com>

On Sat, 15 May 2010, Lorenzo Brito Morales wrote:

> i want to know if its possible to configure the range of the scanning
> of a dongle

Not really, but you could interpret the RSSI result field and pretend that
signal strength had a bearing on distance.

iain



^ permalink raw reply

* configure the range of the scanning of a dongle
From: Lorenzo Brito Morales @ 2010-05-15  5:36 UTC (permalink / raw)
  To: linux-bluetooth

i want to know if its possible to configure the range of the scanning
of a dongle

^ permalink raw reply

* Re: Bluetooth not working with linphone
From: Grant @ 2010-05-14 23:55 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <AANLkTilU5uaxHh0bxD5v3ZDbU1peyZXRR8RyYD_Viouh@mail.gmail.com>

> My bluetooth headset used to work in the voip client twinkle.
> Unfortunately twinkle has been removed from Gentoo's package tree so I
> can't test it to see if it's still working.  It works via 'aplay
> -Dbluetooth file.wav' but I can't get it to work in the voip client
> linphone at all, although others report their's working.
>
> # cat /etc/asound.conf
> pcm.bluetooth {
>        type bluetooth
>        device 00:11:22:33:44:55
>        profile "auto"
> }
>
> Does anyone know how I can troubleshoot this?  I'm on bluez-4.64.
>
> - Grant

The bluetooth headset still works with skype so it's not a bluetooth
issue.  Any suggestions for getting it working with linphone though?

- Grant

^ permalink raw reply

* Re: MAC address change
From: Ahmed Ragab @ 2010-05-14 18:13 UTC (permalink / raw)
  To: Ed Tsang, linux-bluetooth
In-Reply-To: <AANLkTinUQ_ewXsBA-1Pm48cLcxmM1OCWasCOIumiZRaW@mail.gmail.com>

On 14 May 2010 21:10, Ahmed Ragab <elmasri.ahmed@gmail.com> wrote:
> Ed,
>
> Yes i tried and the situation is the same nothing changes, i even
> Tried the -r option in ./bdaddr and the problem is the same nothing
> Changes. i hope there is another way to change the address because
> In my country (egypt) all the bluetooth dongles have the same address :(
>
> Ahmed
>
> On 14 May 2010 18:20, Ed Tsang <netdesign_98@yahoo.com> wrote:
>> Ahmed,
>>   Did you try "hciconfig -a hci0 reset" after the address change.
>>
>> Ed
>>
>>
>>
>>
>

^ permalink raw reply

* Re: MAC address change
From: Ahmed Ragab @ 2010-05-14 18:10 UTC (permalink / raw)
  To: Ed Tsang, linux-bluetooth
In-Reply-To: <81252.27318.qm@web52603.mail.re2.yahoo.com>

Ed,

Yes i tried and the situation is the same nothing changes, i even
Tried the -r option in ./bdaddr and the problem is the same nothing
Changes. i hope there is another way to change the address because
In my country (egypt) all the bluetooth dongles have the sa

Ahmed

On 14 May 2010 18:20, Ed Tsang <netdesign_98@yahoo.com> wrote:
> Ahmed,
>   Did you try "hciconfig -a hci0 reset" after the address change.
>
> Ed
>
>
>
>

^ permalink raw reply

* Bluetooth not working with linphone
From: Grant @ 2010-05-14 17:01 UTC (permalink / raw)
  To: linux-bluetooth

My bluetooth headset used to work in the voip client twinkle.
Unfortunately twinkle has been removed from Gentoo's package tree so I
can't test it to see if it's still working.  It works via 'aplay
-Dbluetooth file.wav' but I can't get it to work in the voip client
linphone at all, although others report their's working.

# cat /etc/asound.conf
pcm.bluetooth {
	type bluetooth
	device 00:11:22:33:44:55
	profile "auto"
}

Does anyone know how I can troubleshoot this?  I'm on bluez-4.64.

- Grant

^ permalink raw reply

* [PATCH] Kernel crash when krfcomm is preempted by l2cap tasklet
From: Andrei Emeltchenko @ 2010-05-14 15:39 UTC (permalink / raw)
  To: Bluettooth Linux

[-- Attachment #1: Type: text/plain, Size: 1781 bytes --]

Hi all,

We have a bug with race condition between l2cap tasklet and krfcomm process.

When sending following sequence:

...
No.     Time        Source                Destination           Protocol Info
     89 1.951202            RFCOMM   Rcvd DISC DLCI=20
     90 1.951324            RFCOMM   Sent UA DLCI=20
     91 1.959381            HCI_EVT   Number of Completed Packets
     92 1.966461            RFCOMM   Rcvd DISC DLCI=0
     93 1.966492            L2CAP    Rcvd Disconnect Request
     94 1.972595            L2CAP    Sent Disconnect Response

...

krfcommd kernel thread is preempted with l2cap tasklet which remove l2cap_conn
(L2CAP connection handler structure). Then rfcomm thread tries to send RFCOMM
UA which is reply to RFCOMM DISC and when de-referencing l2cap_conn crash
happens.

...
[  694.175933] Unable to handle kernel NULL pointer dereference at
virtual address 00000000
[  694.184936] pgd = c0004000
[  694.187683] [00000000] *pgd=00000000
[  694.191711] Internal error: Oops: 5 [#1] PREEMPT
[  694.196350] last sysfs file:
/sys/devices/platform/hci_h4p/firmware/hci_h4p/loading
[  694.260375] CPU: 0    Not tainted  (2.6.32.10 #1)
[  694.265106] PC is at l2cap_sock_sendmsg+0x43c/0x73c [l2cap]
[  694.270721] LR is at 0xd7017303
...
[  694.525085] Backtrace:
[  694.527587] [<bf266be0>] (l2cap_sock_sendmsg+0x0/0x73c [l2cap])
from [<c02f2cc8>] (sock_sendmsg+0xb8
[  694.537292] [<c02f2c10>] (sock_sendmsg+0x0/0xd8) from [<c02f3044>]
(kernel_sendmsg+0x48/0x80)
...

I have a patch which fixes the issue but not sure that there is no
better way. Waiting for comments.

Currently I am investigating possibility to:
- implement l2cap_conn reference counting
- use socket backlog queue to process l2cap packets later when socket is not
owned by the process.

[-- Attachment #2: 0001-Bluetooth-Check-sk-is-not-used-before-freeing.patch --]
[-- Type: text/x-patch, Size: 2044 bytes --]

From 955a821e1ee66cd6f9717ea4a2e9b3dfdafdc22a Mon Sep 17 00:00:00 2001
From: Andrei Emeltchenko <andrei.emeltchenko@nokia.com>
Date: Fri, 14 May 2010 17:56:39 +0300
Subject: [PATCH] Bluetooth: Check sk is not used before freeing

Check that socket sk is not locked in user process before removing
l2cap connection handler and sk.

rfcomm kernel thread may be preempted with l2cap tasklet which remove l2cap_conn
(L2CAP connection handler structure). Then rfcomm thread tries to send RFCOMM
UA which is reply to RFCOMM DISC and when de-referencing l2cap_conn crash
can happen.

...
[  694.175933] Unable to handle kernel NULL pointer dereference at virtual address 00000000
[  694.184936] pgd = c0004000
[  694.187683] [00000000] *pgd=00000000
[  694.191711] Internal error: Oops: 5 [#1] PREEMPT
[  694.196350] last sysfs file: /sys/devices/platform/hci_h4p/firmware/hci_h4p/loading
[  694.260375] CPU: 0    Not tainted  (2.6.32.10 #1)
[  694.265106] PC is at l2cap_sock_sendmsg+0x43c/0x73c [l2cap]
[  694.270721] LR is at 0xd7017303

...

[  694.525085] Backtrace:
[  694.527587] [<bf266be0>] (l2cap_sock_sendmsg+0x0/0x73c [l2cap]) from [<c02f2cc8>] (sock_sendmsg+0xb8/0xd8)
[  694.537292] [<c02f2c10>] (sock_sendmsg+0x0/0xd8) from [<c02f3044>] (kernel_sendmsg+0x48/0x80)
...

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@nokia.com>
---
 net/bluetooth/l2cap.c |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index bb00015..7eb9a58 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -3119,6 +3119,13 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
 	if (!sk)
 		return 0;
 
+	/* sk is locked in krfcomm process */
+	if (sock_owned_by_user(sk)) {
+		BT_DBG("sk %p is owned by user", sk);
+		bh_unlock_sock(sk);
+		return 0;
+	}
+
 	rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
 	rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid);
 	l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
-- 
1.7.0.4


^ permalink raw reply related

* Re: HDP proposed API (ver 0.4)
From: José Antonio Santos Cadenas @ 2010-05-14 15:00 UTC (permalink / raw)
  To: Elvis Pfützenreuter; +Cc: linux-bluetooth
In-Reply-To: <0F7F554B-D04C-46C1-8EE9-7AC3C6B72B5A@signove.com>

Hi Elvis,

El Friday 14 May 2010 14:46:46 Elvis Pfützenreuter escribió:
> Just some points,
> 
> > Health Device Profile hierarchy
> > ===============================
> > 
> > Service		org.bluez
> > Interface	org.bluez.HealthAdapter
> > Object path	[variable prefix]/{hci0,hci1,...}
> > 
> > Methods		object CreateInstance(object path, dict config)
> 
> I guess that 'object path' parameter is redundant.

This object path is the path of the object "org.bluez.HealthAgent"
that the client should implement to receive callbacks.

> 
> > 
> > Service		org.bluez
> > Interface	org.bluez.HealthInstance
> > Object path	[variable prefix]/{hci0,hci1,...}/{hdp0,hdp1,...}
> > 
> > 		object Connect(remote_instance_id)
> > 
> > 			Connects with the remote instance and returns its object
> > 			path.
> 
> It is important to mention explicitly that this remote_instance_id was revealed via GetHealthInstances(). 
> 
> And mention that the object it returns implements the HealthLink interface.

I'll change this things in the next version.

> 
> > 		void Disconnect(object device, boolean delete)
> > 
> > 			Disconnect from the remote device. If delete is true,
> > 			any status will also be deleted. Otherwise, the status
> > 			will be kept for allowing future reconnections.
> 
> s/status/state/, and mention that state only survives while the respective adapter instance exists.

Ok, too.

> > 
> > 		uint16 OpenDataChannel(byte mdepid, byte config)
> > 
> > 			Creates a new data channel with the indicated config
> > 			to the remote MCAP Data End Point (MDEP).
> > 			The configuration should indicate the channel quality of
> > 			service.
> > 			Returns the data channel id.
> 
> Which is the actual format of 'byte config'?

Config  parameter represents the quality of service of the data channel
that is being requested. In the current specification of HDP only Reliable and
Streaming channels are used with values 0x01 and 0x02 (page 22).
I will explain this properly in the next version of the API.

> > 
> > 		void DeviceConnected(object path)
> > 
> > 			This method is called whenever a new device connection
> > 			has been established over the control channel of the
> > 			current HDP instance. The object path contains the
> > 			object path of the remote device.
> 
> "Remote device" is redundant, since it seems that BlueZ always calls "device" the remote thing, and "adapter" the local thing. I saw it first here, but it appears throughout the text.

Right, I wanted to emphasize this issue but you are right. It's redundant.
Will fix this issue too.

> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

^ permalink raw reply

* Re: [PATCH 1/1] Fixes sdp_get_supp_feat function
From: José Antonio Santos Cadenas @ 2010-05-14 14:50 UTC (permalink / raw)
  To: Elvis Pfützenreuter; +Cc: linux-bluetooth
In-Reply-To: <0F09DA9A-2357-4B3D-989E-5ECCEEDD5092@signove.com>

Hi, 

El Friday 14 May 2010 14:58:00 Elvis Pfützenreuter escribió:
> 
> On 14/05/2010, at 04:02, José Antonio Santos Cadenas wrote:
> 
> > Hi Elvis,
> > 
> > El Friday 14 May 2010 05:13:30 Elvis Pfützenreuter escribió:
> >> In case of string data items, value is a pointer by itself.
> >> ---
> >> lib/sdp.c |    7 ++++++-
> >> 1 files changed, 6 insertions(+), 1 deletions(-)
> >> 
> >> diff --git a/lib/sdp.c b/lib/sdp.c
> >> index fb8ccdc..c75a000 100644
> >> --- a/lib/sdp.c
> >> +++ b/lib/sdp.c
> >> @@ -4801,10 +4801,15 @@ int sdp_get_supp_feat(const sdp_record_t *rec,
> >> sdp_list_t **seqp) subseq = NULL;
> >> 		for (dd = d->val.dataseq; dd; dd = dd->next) {
> >> 			sdp_data_t *data;
> >> +			void *val;
> >> 			if (dd->dtd != SDP_UINT8 && dd->dtd != SDP_UINT16 &&
> >> 						dd->dtd != SDP_TEXT_STR8)
> >> 				goto fail;
> >> -			data = sdp_data_alloc(dd->dtd, &dd->val);
> >> +			if (dd->dtd == SDP_TEXT_STR8)
> >> +				val = dd->val.str;
> >> +			else
> >> +				val = &dd->val;
> >> +			data = sdp_data_alloc(dd->dtd, val);
> > 
> > No only strings are pointers, if you see this patch:
> > http://git.kernel.org/?p=bluetooth/bluez.git;a=commit;h=1d1154156df28660e41031df5c3f1ffe91c01aae
> > 
> > that I sent few days ago for fixing the set function, also sequences are 
> > pointers and should be treated in a different way. Also strings can be formed 
> > by other types not only SDP_TEXT_STR8. I think a switch will fix this better.
> 
> That would be nice for completeness, but the if .. goto fail just before the patch guarantees that data type will be UINT8, UINT16 or an STR8. (Am I missing something here?)

Of course, the code seems to work fine. I just suggested to modify it at once, because a 
"bug"/non completeness is still there and another patch will be required. It's a little
bit more of work and the code will work in all the cases.



^ permalink raw reply

* Re: [PATCH 1/1] Fixes sdp_get_supp_feat function
From: Elvis Pfützenreuter @ 2010-05-14 12:58 UTC (permalink / raw)
  To: jcaden; +Cc: linux-bluetooth
In-Reply-To: <201005140902.23338.jcaden@libresoft.es>



On 14/05/2010, at 04:02, José Antonio Santos Cadenas wrote:

> Hi Elvis,
> 
> El Friday 14 May 2010 05:13:30 Elvis Pfützenreuter escribió:
>> In case of string data items, value is a pointer by itself.
>> ---
>> lib/sdp.c |    7 ++++++-
>> 1 files changed, 6 insertions(+), 1 deletions(-)
>> 
>> diff --git a/lib/sdp.c b/lib/sdp.c
>> index fb8ccdc..c75a000 100644
>> --- a/lib/sdp.c
>> +++ b/lib/sdp.c
>> @@ -4801,10 +4801,15 @@ int sdp_get_supp_feat(const sdp_record_t *rec,
>> sdp_list_t **seqp) subseq = NULL;
>> 		for (dd = d->val.dataseq; dd; dd = dd->next) {
>> 			sdp_data_t *data;
>> +			void *val;
>> 			if (dd->dtd != SDP_UINT8 && dd->dtd != SDP_UINT16 &&
>> 						dd->dtd != SDP_TEXT_STR8)
>> 				goto fail;
>> -			data = sdp_data_alloc(dd->dtd, &dd->val);
>> +			if (dd->dtd == SDP_TEXT_STR8)
>> +				val = dd->val.str;
>> +			else
>> +				val = &dd->val;
>> +			data = sdp_data_alloc(dd->dtd, val);
> 
> No only strings are pointers, if you see this patch:
> http://git.kernel.org/?p=bluetooth/bluez.git;a=commit;h=1d1154156df28660e41031df5c3f1ffe91c01aae
> 
> that I sent few days ago for fixing the set function, also sequences are 
> pointers and should be treated in a different way. Also strings can be formed 
> by other types not only SDP_TEXT_STR8. I think a switch will fix this better.

That would be nice for completeness, but the if .. goto fail just before the patch guarantees that data type will be UINT8, UINT16 or an STR8. (Am I missing something here?)

^ permalink raw reply

* Re: HDP proposed API (ver 0.4)
From: Elvis Pfützenreuter @ 2010-05-14 12:46 UTC (permalink / raw)
  To: jcaden; +Cc: linux-bluetooth
In-Reply-To: <201005141203.47929.jcaden@libresoft.es>

Just some points,

> Health Device Profile hierarchy
> ===============================
> 
> Service		org.bluez
> Interface	org.bluez.HealthAdapter
> Object path	[variable prefix]/{hci0,hci1,...}
> 
> Methods		object CreateInstance(object path, dict config)

I guess that 'object path' parameter is redundant.

> 
> Service		org.bluez
> Interface	org.bluez.HealthInstance
> Object path	[variable prefix]/{hci0,hci1,...}/{hdp0,hdp1,...}
> 
> 		object Connect(remote_instance_id)
> 
> 			Connects with the remote instance and returns its object
> 			path.

It is important to mention explicitly that this remote_instance_id was revealed via GetHealthInstances(). 

And mention that the object it returns implements the HealthLink interface.

> 		void Disconnect(object device, boolean delete)
> 
> 			Disconnect from the remote device. If delete is true,
> 			any status will also be deleted. Otherwise, the status
> 			will be kept for allowing future reconnections.

s/status/state/, and mention that state only survives while the respective adapter instance exists.
> 
> 		uint16 OpenDataChannel(byte mdepid, byte config)
> 
> 			Creates a new data channel with the indicated config
> 			to the remote MCAP Data End Point (MDEP).
> 			The configuration should indicate the channel quality of
> 			service.
> 			Returns the data channel id.

Which is the actual format of 'byte config'?
> 
> 		void DeviceConnected(object path)
> 
> 			This method is called whenever a new device connection
> 			has been established over the control channel of the
> 			current HDP instance. The object path contains the
> 			object path of the remote device.

"Remote device" is redundant, since it seems that BlueZ always calls "device" the remote thing, and "adapter" the local thing. I saw it first here, but it appears throughout the text.

^ permalink raw reply

* Re: HDP proposed API (ver 0.3)
From: Elvis Pfützenreuter @ 2010-05-14 12:20 UTC (permalink / raw)
  To: jcaden
  Cc: João Paulo Rechi Vita, linux-bluetooth, Santiago Carot,
	Raul Herbster
In-Reply-To: <201005141000.51935.jcaden@libresoft.es>

> 	- Giving this data to HDP is not only for registering a SDP record but 
> also for doing checks when a connection is received, so this data will be 
> finally passed to HDP.
> 	- The HDP client doesn't know all the data that should be published in 
> the SDP record, like PSM's where MCAP is waiting for connections or MCAP 
> supported features (note that MCAP is not exported by D-BUS).

Also, MCAP uses dynamic PSMs, one more reason to encapsulate the SDP record generation/parsing. If the application had to do this, it would have to find two free PSMs (ugly).


^ permalink raw reply

* [PATCH 25/25] Initial support for clock synchronization protocol
From: Santiago Carot-Nemesio @ 2010-05-14 10:19 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1273832392-18654-24-git-send-email-sancane@gmail.com>

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

diff --git a/Makefile.am b/Makefile.am
index 0c139a1..9ab5be2 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/sync.c \
 		mcap/mcap.h mcap/mcap.c
 endif
 
diff --git a/mcap/mcap.c b/mcap/mcap.c
index 6c98124..1c00769 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1511,8 +1511,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/sync.c b/mcap/sync.c
new file mode 100644
index 0000000..8fa3dbd
--- /dev/null
+++ b/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 "logging.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:
+		debug("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:
+		debug("TODO: received MCAP_MD_SYNC_CAP_RSP: %d",
+							MCAP_MD_SYNC_CAP_RSP);
+		break;
+	case MCAP_MD_SYNC_SET_REQ:
+		debug("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:
+		debug("TODO: received MCAP_MD_SYNC_SET_RSP: %d",
+							MCAP_MD_SYNC_SET_RSP);
+		break;
+	case MCAP_MD_SYNC_INFO_IND:
+		debug("TODO: received MCAP_MD_SYNC_INFO_IND :%d",
+							MCAP_MD_SYNC_INFO_IND);
+		break;
+	}
+}
-- 
1.6.3.3


^ permalink raw reply related

* [PATCH 24/25] Enable connection of Data Channel with remote MCAP instances
From: Santiago Carot-Nemesio @ 2010-05-14 10:19 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1273832392-18654-23-git-send-email-sancane@gmail.com>

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

diff --git a/mcap/mcap.c b/mcap/mcap.c
index a08e631..6c98124 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);
+	debug("mdl connect callback");
+
+	if (conn_err) {
+		debug("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) {
+		debug("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


^ permalink raw reply related

* [PATCH 23/25] Process md_delete_mdl_rsp
From: Santiago Carot-Nemesio @ 2010-05-14 10:19 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1273832392-18654-22-git-send-email-sancane@gmail.com>

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

diff --git a/mcap/mcap.c b/mcap/mcap.c
index eda8dd1..a08e631 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1335,10 +1335,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


^ permalink raw reply related

* [PATCH 22/25] Process md_abort_mdl_rsp
From: Santiago Carot-Nemesio @ 2010-05-14 10:19 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1273832392-18654-21-git-send-email-sancane@gmail.com>

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

diff --git a/mcap/mcap.c b/mcap/mcap.c
index d55da16..eda8dd1 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1301,7 +1301,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


^ permalink raw reply related

* [PATCH 21/25] Process md_reconnect_mdl_rsp
From: Santiago Carot-Nemesio @ 2010-05-14 10:19 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1273832392-18654-20-git-send-email-sancane@gmail.com>

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

diff --git a/mcap/mcap.c b/mcap/mcap.c
index b499219..d55da16 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1258,7 +1258,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


^ permalink raw reply related

* [PATCH 20/25] Process md_create_mdl_rsp
From: Santiago Carot-Nemesio @ 2010-05-14 10:19 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1273832392-18654-19-git-send-email-sancane@gmail.com>

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

diff --git a/mcap/mcap.c b/mcap/mcap.c
index efc512a..b499219 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1171,10 +1171,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


^ permalink raw reply related

* [PATCH 19/25] Process response to std. op. codes
From: Santiago Carot-Nemesio @ 2010-05-14 10:19 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1273832392-18654-18-git-send-email-sancane@gmail.com>

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

diff --git a/mcap/mcap.c b/mcap/mcap.c
index b0cf651..efc512a 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1171,9 +1171,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) {
+		debug("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:
+		debug("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)
@@ -1632,3 +1735,38 @@ 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


^ permalink raw reply related

* [PATCH 18/25] Implement function to send md_abort_mdl_req
From: Santiago Carot-Nemesio @ 2010-05-14 10:19 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1273832392-18654-17-git-send-email-sancane@gmail.com>

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

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 1fd8e43..b0cf651 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -520,6 +520,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;
@@ -555,6 +587,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


^ permalink raw reply related

* [PATCH 17/25] Implement function to send md_delete_mdl_req
From: Santiago Carot-Nemesio @ 2010-05-14 10:19 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1273832392-18654-16-git-send-email-sancane@gmail.com>

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

diff --git a/mcap/mcap.c b/mcap/mcap.c
index b4b8b09..1fd8e43 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -125,6 +125,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)
 {
@@ -408,6 +440,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;
+
+	debug("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


^ permalink raw reply related

* [PATCH 16/25] Implement function to send md_reconnect_mdl_req
From: Santiago Carot-Nemesio @ 2010-05-14 10:19 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1273832392-18654-15-git-send-email-sancane@gmail.com>

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

diff --git a/mcap/mcap.c b/mcap/mcap.c
index c7bbb94..b4b8b09 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -262,6 +262,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;
@@ -357,6 +371,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


^ permalink raw reply related

* [PATCH 15/25] Implement function to send md_create_mdl_req
From: Santiago Carot-Nemesio @ 2010-05-14 10:19 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1273832392-18654-14-git-send-email-sancane@gmail.com>

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

diff --git a/mcap/mcap.c b/mcap/mcap.c
index dfcce82..c7bbb94 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -34,6 +34,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")
@@ -49,6 +50,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);
@@ -61,6 +73,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)
 {
 	debug("MCAP Unmanaged mdl connection");
@@ -111,6 +125,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;
@@ -167,6 +242,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;
@@ -180,6 +291,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


^ permalink raw reply related

* [PATCH 14/25] Implement set callbacks operation over MCLs
From: Santiago Carot-Nemesio @ 2010-05-14 10:19 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1273832392-18654-13-git-send-email-sancane@gmail.com>

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

diff --git a/mcap/mcap.c b/mcap/mcap.c
index bbbcf2b..dfcce82 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -398,6 +398,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


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox