Linux bluetooth development
 help / color / mirror / Atom feed
* Headset problem
From: Josu Lazkano @ 2010-07-28 17:02 UTC (permalink / raw)
  To: linux-bluetooth

Hello, I have a Debian Squeeze laptop, I am using the same OS on other
laptop and I can use a bluetooth headset to speak with PulseAudio.
When I connect
(pairing) the headset I can select the bluetooth device on PulseAudio
and I can use it, but
not with the other laptop.

This is my bt device info:

# hciconfig features
hci0:   Type: BR/EDR  Bus: USB
       BD Address: 00:10:C6:xx:xx:xx  ACL MTU: 377:10  SCO MTU: 16:0
       UP RUNNING PSCAN ISCAN
       RX bytes:5691 acl:77 sco:51 events:125 errors:2
       TX bytes:2239 acl:81 sco:0 commands:43 errors:0

I use Gnome bluetooth preference to pair the devices. I don't know
what info put here, can you help with this?

This is the bluetooth device that works:

# hciconfig features
hci0:	Type: BR/EDR  Bus: USB
	BD Address: 00:21:85:xx:xx:xx  ACL MTU: 310:10  SCO MTU: 64:8
	UP RUNNING PSCAN
	RX bytes:312623 acl:19325 sco:0 events:302 errors:0
	TX bytes:2074 acl:11 sco:0 commands:41 errors:0


Thanks for all.

-- 
Josu Lazkano

^ permalink raw reply

* Re: add dbus api to set class of device?
From: Tim Renouf @ 2010-07-28 16:59 UTC (permalink / raw)
  To: Marcel Holtmann; +Cc: linux-bluetooth
In-Reply-To: <1280335558.2621.97.camel@localhost.localdomain>

Hi Marcel

> I did mention before that JSR82 is the most stupid Bluetooth API that I
> have seen so far, didn't I? Personally I wouldn't even bother with JSR82
> and give up right away. It is really a pointless API.

Unfortunately I have to bother with it as our customers are device
manufacturers who are willing to pay for MIDP with JSR82 support. :-(

> In BlueZ the services bits of the class of device settings are modified
> dynamically based on the registered SDP service records. So you don't
> have to do anything. Just register the right SDP service record with the
> proper UUID and it will take care of this automatically.

Yes, I saw that in update_adapter_svclass_list. I guess the problem is
that JSR82 lets an app decide to set the "wrong" bit, and the
conformance tests test that functionality.

So if I did a patch along the lines I was suggesting, and submitted it
here, would it be rejected on the grounds that it is not needed for any
"sensible" functionality ?

Thanks.

-tpr

^ permalink raw reply

* Re: add dbus api to set class of device?
From: Marcel Holtmann @ 2010-07-28 16:45 UTC (permalink / raw)
  To: Tim Renouf; +Cc: linux-bluetooth
In-Reply-To: <20100728153323.GA9410@aplixcorp.com>

Hi Tim,

> I am putting a JSR82 implementation on an Android device that uses
> BlueZ, accessing BlueZ via the dbus api.
> 
> JSR82 has an API where you can set service class bits for a particular
> service you have registered. So the JSR82 implementation needs to be
> able to set the class of device in some way. I would like to add a dbus
> method to do this, and I'd like to know the opinion of BlueZ developers
> on this:

I did mention before that JSR82 is the most stupid Bluetooth API that I
have seen so far, didn't I? Personally I wouldn't even bother with JSR82
and give up right away. It is really a pointless API.

In BlueZ the services bits of the class of device settings are modified
dynamically based on the registered SDP service records. So you don't
have to do anything. Just register the right SDP service record with the
proper UUID and it will take care of this automatically.

Regards

Marcel



^ permalink raw reply

* Re: [PATCH][RFC] Fix SDP resolving segfault
From: Manuel Naranjo @ 2010-07-28 16:17 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: Johan Hedberg, BlueZ
In-Reply-To: <AANLkTi=jzZScnCK6rFpKjBJesnw=71y5hNG3kDBhxv1u@mail.gmail.com>

Hi Luiz,
> Can you try the patch attached to this email?
>    
I give it a try and let you know how it goes.

Manuel


^ permalink raw reply

* add dbus api to set class of device?
From: Tim Renouf @ 2010-07-28 15:33 UTC (permalink / raw)
  To: linux-bluetooth

Hi all

I am putting a JSR82 implementation on an Android device that uses
BlueZ, accessing BlueZ via the dbus api.

JSR82 has an API where you can set service class bits for a particular
service you have registered. So the JSR82 implementation needs to be
able to set the class of device in some way. I would like to add a dbus
method to do this, and I'd like to know the opinion of BlueZ developers
on this:

1. Is this a reasonable thing to do and submit a patch for ?

2. What would be a good approach, out of the following (or any other
possibility I have missed) ?

2a. Add a dbus method to set service class bits for a registered
service. This would set a new field in sdp_record_t. The existing
function update_adapter_svclass_list in sdpd-service.c would read this
new field in every service record when determining the service class
bits to set. The setting gets cleared automatically when the service is
removed. This seems like the cleanest solution.

2b. Add a dbus method to set service class bits, or all device class
bits, globally for the dbus connection. There would have to be a list of
dbus connections, each storing the connection's requested class.
manager_update_svc would scan that list. The setting gets cleared
automatically when the dbus connection is lost.

2c. Add a dbus method to set service class bits, or all device class
bits, globally. This can just call the BlueZ internal method directly.
The problems with this are (i) it doesn't work if multiple apps are
trying to use it; (ii) the setting gets lost next time a service gets
registered or removed, so the app needs to be aware of this and reapply
its setting, and (iii) the setting remains if the app exits or crashes
without removing it.

I note that Bluecove-on-BlueZ does not implement this, therefore it
fails the same conformance test that I am looking at.

Thanks.

-tpr

^ permalink raw reply

* Re: [PATCH][RFC] Fix SDP resolving segfault
From: Luiz Augusto von Dentz @ 2010-07-28 14:55 UTC (permalink / raw)
  To: Manuel Naranjo; +Cc: Johan Hedberg, BlueZ
In-Reply-To: <AANLkTi=8=BUThjVdc4EN_8uupGKmdgHQzGOe560Cv+pm@mail.gmail.com>

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

Hi Manuel,

On Fri, Jul 23, 2010 at 11:37 PM, Luiz Augusto von Dentz
<luiz.dentz@gmail.com> wrote:
> Hi,
>
> On Wed, Jul 21, 2010 at 6:11 PM, Manuel Naranjo <manuel@aircable.net> wrote:
>> I think this is the one that really fix the problem. I see connect_watch
>> getting called and then getting into the crash. I have a nice log with the
>> tracing feature I sent the other day, here's the end of it (the hole thing
>> is almost 40 megs if someone wants just ask for it).
>
> I just figure out that our connect_watch in glib_helper.c is not quite
> right, it should be something similar as we have btio.c, specially
> this one is particular important:
>
>        /* If the user aborted this connect attempt */
>        if ((cond & G_IO_NVAL) || check_nval(io))
>                return FALSE;
>
> It is probably because of not having this check that the cb is still
> called after bt_cancel_discovery. Of course this doesn't invalidate
> your fix to bt_cancel_discovery itself, but I guess this should also
> be included to safe that the callback is not called after cancelling
> the discovery.

Can you try the patch attached to this email?


-- 
Luiz Augusto von Dentz
Computer Engineer

[-- Attachment #2: 0001-core-fix-not-handling-sdp-connection-errors-properly.patch --]
[-- Type: text/x-patch, Size: 5659 bytes --]

From 28953f5b419693d8281f057055a34d9bc3e4442e Mon Sep 17 00:00:00 2001
From: Luiz Augusto von Dentz <luiz.dentz-von@nokia.com>
Date: Wed, 28 Jul 2010 16:41:12 +0300
Subject: [PATCH] core: fix not handling sdp connection errors properly

---
 src/glib-helper.c |  145 +++++++++++++++++++++++++++++++++++++----------------
 1 files changed, 101 insertions(+), 44 deletions(-)

diff --git a/src/glib-helper.c b/src/glib-helper.c
index 41f5e3c..afd664e 100644
--- a/src/glib-helper.c
+++ b/src/glib-helper.c
@@ -44,6 +44,8 @@
 #include <glib.h>
 
 #include "glib-helper.h"
+#include "btio.h"
+#include "log.h"
 
 /* Number of seconds to keep a sdp_session_t in the cache */
 #define CACHE_TIMEOUT 2
@@ -98,7 +100,7 @@ static sdp_session_t *get_sdp_session(const bdaddr_t *src, const bdaddr_t *dst)
 		return session;
 	}
 
-	return sdp_connect(src, dst, SDP_NON_BLOCKING);
+	return NULL;
 }
 
 static void cache_sdp_session(bdaddr_t *src, bdaddr_t *dst,
@@ -143,6 +145,7 @@ struct search_context {
 	bdaddr_t		src;
 	bdaddr_t		dst;
 	sdp_session_t		*session;
+	GIOChannel		*io;
 	bt_callback_t		cb;
 	bt_destroy_t		destroy;
 	gpointer		user_data;
@@ -245,56 +248,99 @@ failed:
 	return FALSE;
 }
 
-static gboolean connect_watch(GIOChannel *chan, GIOCondition cond, gpointer user_data)
+static int sdp_search(struct search_context *ctxt)
 {
-	struct search_context *ctxt = user_data;
+	GIOChannel *chan;
 	sdp_list_t *search, *attrids;
 	uint32_t range = 0x0000ffff;
-	socklen_t len;
-	int sk, err = 0;
-
-	sk = g_io_channel_unix_get_fd(chan);
-	ctxt->io_id = 0;
+	int err, sk;
 
-	len = sizeof(err);
-	if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
-		err = errno;
-		goto failed;
-	}
-
-	if (err != 0)
-		goto failed;
-
-	if (sdp_set_notify(ctxt->session, search_completed_cb, ctxt) < 0) {
-		err = EIO;
-		goto failed;
-	}
+	err = sdp_set_notify(ctxt->session, search_completed_cb, ctxt);
+	if (err < 0)
+		return err;
 
 	search = sdp_list_append(NULL, &ctxt->uuid);
 	attrids = sdp_list_append(NULL, &range);
-	if (sdp_service_search_attr_async(ctxt->session,
-				search, SDP_ATTR_REQ_RANGE, attrids) < 0) {
-		sdp_list_free(attrids, NULL);
-		sdp_list_free(search, NULL);
-		err = EIO;
-		goto failed;
-	}
 
+	err = sdp_service_search_attr_async(ctxt->session, search,
+						SDP_ATTR_REQ_RANGE, attrids);
 	sdp_list_free(attrids, NULL);
 	sdp_list_free(search, NULL);
+	if (err < 0)
+		return err;
+
+	sk = sdp_get_socket(ctxt->session);
+	chan = g_io_channel_unix_new(sk);
 
 	/* Set callback responsible for update the internal SDP transaction */
 	ctxt->io_id = g_io_add_watch(chan,
 				G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
 				search_process_cb, ctxt);
-	return FALSE;
+
+	return 0;
+}
+
+static void connect_watch(GIOChannel *chan, GError *gerr, gpointer user_data)
+{
+	struct search_context *ctxt = user_data;
+	int sk, err = 0;
+
+	if (gerr) {
+		err = -EHOSTDOWN;
+		goto failed;
+	}
+
+	g_io_channel_set_close_on_unref(ctxt->io, FALSE);
+	g_io_channel_unref(ctxt->io);
+	ctxt->io = NULL;
+
+	sk = g_io_channel_unix_get_fd(chan);
+	ctxt->session = sdp_create(sk, SDP_NON_BLOCKING);
+	if (ctxt->session == NULL) {
+		err = -ENOMEM;
+		goto failed;
+	}
+
+	err = sdp_search(ctxt);
+	if (err < 0)
+		goto failed;
+
+	return;
 
 failed:
+	if (ctxt->session) {
+		sdp_close(ctxt->session);
+		ctxt->session = NULL;
+	}
+
+	if (ctxt->io) {
+		g_io_channel_shutdown(ctxt->io, TRUE, NULL);
+		g_io_channel_unref(ctxt->io);
+		ctxt->io = NULL;
+	}
+
+	if (ctxt->cb)
+		ctxt->cb(NULL, err, ctxt->user_data);
+
+	search_context_cleanup(ctxt);
+}
+
+static gboolean sdp_resume(gpointer data)
+{
+	struct search_context *ctxt = data;
+	int err;
+
+	ctxt->io_id = 0;
+
+	err = sdp_search(ctxt);
+	if (err == 0)
+		return FALSE;
+
 	sdp_close(ctxt->session);
 	ctxt->session = NULL;
 
 	if (ctxt->cb)
-		ctxt->cb(NULL, -err, ctxt->user_data);
+		ctxt->cb(NULL, err, ctxt->user_data);
 
 	search_context_cleanup(ctxt);
 
@@ -306,15 +352,11 @@ static int create_search_context(struct search_context **ctxt,
 				uuid_t *uuid)
 {
 	sdp_session_t *s;
-	GIOChannel *chan;
+	GError *err = NULL;
 
 	if (!ctxt)
 		return -EINVAL;
 
-	s = get_sdp_session(src, dst);
-	if (!s)
-		return -errno;
-
 	*ctxt = g_try_malloc0(sizeof(struct search_context));
 	if (!*ctxt) {
 		sdp_close(s);
@@ -323,14 +365,27 @@ static int create_search_context(struct search_context **ctxt,
 
 	bacpy(&(*ctxt)->src, src);
 	bacpy(&(*ctxt)->dst, dst);
-	(*ctxt)->session = s;
 	(*ctxt)->uuid = *uuid;
 
-	chan = g_io_channel_unix_new(sdp_get_socket(s));
-	(*ctxt)->io_id = g_io_add_watch(chan,
-				G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
-				connect_watch, *ctxt);
-	g_io_channel_unref(chan);
+	s = get_sdp_session(src, dst);
+	if (s != NULL) {
+		(*ctxt)->session = s;
+		(*ctxt)->io_id = g_idle_add(sdp_resume, *ctxt);
+		return 0;
+	}
+
+	(*ctxt)->io = bt_io_connect(BT_IO_L2CAP, connect_watch, *ctxt,
+					NULL, &err,
+					BT_IO_OPT_SOURCE_BDADDR, src,
+					BT_IO_OPT_DEST_BDADDR, dst,
+					BT_IO_OPT_PSM, SDP_PSM,
+					BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_SDP,
+					BT_IO_OPT_INVALID);
+	if ((*ctxt)->io == NULL) {
+		g_error_free(err);
+		search_context_cleanup(*ctxt);
+		return -EINVAL;
+	}
 
 	return 0;
 }
@@ -391,15 +446,17 @@ int bt_cancel_discovery(const bdaddr_t *src, const bdaddr_t *dst)
 		return -ENODATA;
 
 	ctxt = match->data;
-	if (!ctxt->session)
-		return -ENOTCONN;
-
 	if (ctxt->io_id)
 		g_source_remove(ctxt->io_id);
 
 	if (ctxt->session)
 		sdp_close(ctxt->session);
 
+	if (ctxt->io) {
+		g_io_channel_shutdown(ctxt->io, TRUE, NULL);
+		g_io_channel_unref(ctxt->io);
+	}
+
 	search_context_cleanup(ctxt);
 	return 0;
 }
-- 
1.7.0.4


^ permalink raw reply related

* Bluetooth for netbook Toshiba NB200 (under Debian Squeeze)
From: MamoMC @ 2010-07-28 14:28 UTC (permalink / raw)
  To: linux-bluetooth

Hi!
This is the first time for me to write in this list: if you think this
is the wrong place to look for the kind of help I'm looking for, plese
tell me and excuse me in advance.
If not, the subject tells almost everything about my problem.
I installed Debian Squeeze on my brand new Toshiba NB200 and it
currently runs Linux 2.6.32.
Under Gnome the system says that no BT adapter is available but I know
it is since it works under WinXP.
I've been looking for help for weeks in different lists/sites but so
far I couldn/t find anything useful.
Since the base for BT under Linux looks to be Bluez I decided to
subscribe to this list hoping it's the right place to look for help.
Let's keep on hoping so...
TIA for your kind help/suggestions.
Bye,
Maurizio.

^ permalink raw reply

* Re: How to past connect complete event status (page timeout) to apps
From: Ed Tsang @ 2010-07-28 14:04 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: Bluettooth Linux
In-Reply-To: <AANLkTinA-E6v157y0DOf2gBzKykvT22vEn=9TddSvgy7@mail.gmail.com>

Luiz, Got it working now EHOSTDOWN, ETIMEOUT... I could not fix the git, as my 
private branch out of 0.14. 

    What I did is inject  at some of the call back (service_callback, 
rfcomm_callback..).  

     if (cond & (G_IO_NVAL | G_IO_ERR)) {
        int err = 0, sock = g_io_channel_unix_get_fd(io);
        socklen_t len = sizeof(err);

        if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &len) < 0)
            err = errno;  /* then send it to the agent via a new method*/
        }

--------
  Basically I will see G_IO_ERR when it fail (for those test case that I am 
working on).
   One question that I hope you could help me is to how to tune the timing for 
ETIMEOUT, GW_OBEX_ERROR_TIMEOUT. I tried to search (timeout|TIMEOUT) and did not 
get too far.

Cheers
Ed




^ permalink raw reply

* Re: Any update on software caused connection abort issue??
From: Lukas Hetzenecker @ 2010-07-28 12:42 UTC (permalink / raw)
  To: Gustavo F. Padovan; +Cc: john michelle, linux-bluetooth
In-Reply-To: <20100723182027.GO2620@vigoh>

On Friday 23 July 2010 20:20:27 Gustavo F. Padovan wrote:
> Hi Lukas,
> 
> * Lukas Hetzenecker <LuHe@gmx.at> [2010-07-23 01:44:02 +0200]:
> > I also noticed these kernel messages during the disconnect in my
> > /var/log/messages log
> > 
> > Jul 22 23:52:35 erde kernel: btusb_intr_complete: hci0 urb
> > ffff88010d409540 failed to resubmit (1)
> > Jul 22 23:52:35 erde kernel: btusb_bulk_complete: hci0 urb
> > ffff88010d409900 failed to resubmit (1)
> > Jul 22 23:52:35 erde kernel: btusb_bulk_complete: hci0 urb
> > ffff88010d409b40 failed to resubmit (1)
> > 
> > [these messages are repeated for several times, even before the
> > disconnect]
> > 
> > Jul 22 23:52:36 erde kernel: usb 5-1: reset full speed USB device using
> > uhci_hcd and address 2
> > Jul 22 23:52:36 erde kernel: btusb 5-1:1.0: no reset_resume for driver
> > btusb? Jul 22 23:52:36 erde bluetoothd[1580]: HCI dev 0 down
> > Jul 22 23:52:36 erde bluetoothd[1580]: Adapter /org/bluez/1574/hci0 has
> > been disabled
> > Jul 22 23:52:36 erde bluetoothd[1580]: Stopping security manager 0
> > Jul 22 23:52:36 erde kernel: btusb 5-1:1.1: no reset_resume for driver
> > btusb? Jul 22 23:52:37 erde bluetoothd[1580]: HCI dev 0 unregistered
> > Jul 22 23:52:37 erde bluetoothd[1580]: Unregister path:
> > /org/bluez/1574/hci0 Jul 22 23:52:37 erde NetworkManager[1520]: <info>
> > BT device 00:1B:AF:84:FF:E2 removed
> > Jul 22 23:52:37 erde bluetoothd[1580]: HCI dev 0 registered
> > Jul 22 23:52:37 erde bluetoothd[1580]: HCI dev 0 up
> > Jul 22 23:52:37 erde bluetoothd[1580]: Starting security manager 0
> > Jul 22 23:52:37 erde bluetoothd[1580]: Parsing /etc/bluetooth/serial.conf
> > failed: No such file or directory
> > Jul 22 23:52:37 erde bluetoothd[1580]: probe failed with driver
> > input-headset for device /org/bluez/1574/hci0/dev_00_1B_AF_84_FF_E2
> > Jul 22 23:52:37 erde bluetoothd[1580]: Adapter /org/bluez/1574/hci0 has
> > been enabled
> > 
> > 
> > It is also strange that this error affects only my PC with an USB
> > bluetooth stick, not my notebook with an integrated Intel PRO Wireless
> > 4965AGN bluetooth module.
> 
> Is there any difference on the systems in both machines? And can you try
> reproduce this with another Bluetooth dongle, just to make sure that the
> problem is not the hardware.

I couldn't test it with another device yet, but I found a workaround here:
https://bugzilla.redhat.com/show_bug.cgi?id=583848#c6

When I use this workaround everything works again, so there doesn't seem to be 
a problem with the dongle.

> > Do you need any more informations for debugging?
> > 
> > On Thursday 22 July 2010 16:17:57 john michelle wrote:
> > > Hi Lukas,
> > > 
> > > > It would be great to see this problem fixed soon, because it's nearly
> > > > impossible to use bluetooth on my PC.
> > > 
> > > I think it's useless to get any reply from this mailing list, i have
> > > been reporting this
> > > Problem for a long time and no one simply cares.
> > > 
> > > John
> > > 
> > > On Wed, Jul 21, 2010 at 5:53 PM, Lukas <LuHe@gmx.at> wrote:
> > > > Hello,
> > > > 
> > > > On Wednesday 21 July 2010 17:35:15 john michelle wrote:
> > > >> Any update on software caused connection abort issue
> > > > 
> > > > I also noticed this error when I used the software suite
> > > > Series60-Remote to connect to my mobile phone.
> > > > 
> > > > Shortly after the connection establishment is completed I get the
> > > > error message "software caused connection abort" and the device gets
> > > > disconnected.
> > > > 
> > > > I also see the HCI reset, as described below, when I try to
> > > > investigate this error using hcidump.
> > > > 
> > > > The software uses the RFCOMM protocol for the connection.
> > > > I use an USB bluetooth adapter from Belkin, lsusb reports the
> > > > following device id:
> > > > ID 050d:0131 Belkin Components Bluetooth Device with trace filter
> > > > 
> > > > This bug happens with the following kernel:
> > > > root@erde ~  #  rpm -q kernel bluez
> > > > kernel-2.6.33.6-147.fc13.x86_64
> > > > bluez-4.64-1.fc13.x86_64
> > > > 
> > > > You can also look at this thread in my mailing list for further
> > > > informations:
> > > > https://sourceforge.net/mailarchive/forum.php?thread_name=20100719213
> > > > 6.2 7723.LuHe%40gmx.at&forum_name=series60- remote-devel
> > > > 
> > > > It would be great to see this problem fixed soon, because it's nearly
> > > > impossible to use bluetooth on my PC.
> > > > 
> > > > Thanks,
> > > > Lukas
> > > > 
> > > >> >>On Wed, Jun 23, 2010 at 12:48 AM, john michelle
> > > >> >><jhnmichelle@gmail.com>
> > > > 
> > > > wrote:
> > > >> >> Dear Bluetooth community,
> > > >> >> 
> > > >> >> You are committing version after version and have time to add new
> > > >> >> Features and the core stack have a major bug (software Caused
> > > >> >> connection abort) that i
> > > >> >> Have reported on the 7th of may the problem seems to be either in
> > > >> >> the usb part of the
> > > >> >> Kernel or the bluez stack, i am no kernel engineer so i came
> > > >> >> directly to you for reporting
> > > >> >> This problem and my requests to look into this problem are just
> > > >> >> ignored. this is a blocker
> > > >> >> Issue that would prevent and discourage any one from developing
> > > >> >> application that rely on
> > > >> >> Bluez sco capabilities, since during transmission the above
> > > >> >> mentioned error just occurs.
> > > >> >> I hope that my voice is heared and i would get a reply from the
> > > >> >> bluez community.
> > > >> >> 
> > > >> >> John
> > > >> >> 
> > > >> >> On Wed, Jun 16, 2010 at 3:11 PM, john michelle
> > > >> >> <jhnmichelle@gmail.com>
> > > > 
> > > > wrote:
> > > >> >>> On Sun, May 30, 2010 at 1:12 PM, john michelle
> > > >> >>> <jhnmichelle@gmail.com>
> > > > 
> > > > wrote:
> > > >> >>>> Hi Gustavo,
> > > >> >>>> 
> > > >> >>>>>> Please post the output of hcidump when the connection abort
> > > >> >>>>>> happens.
> > > >> >>>> 
> > > >> >>>> Below is the output of hcidump the moments the software caused
> > > >> >>>> connection abort
> > > >> >>>> 
> > > >> >>>> Dongle 1:
> > > >> >>>>> HCI Event: Number of Completed Packets (0x13) plen 5
> > > >> >>>>> 
> > > >> >>>>  . * . . .
> > > >> >>>> 
> > > >> >>>> < HCI Command: Reset (0x03|0x0003) plen 0
> > > >> >>>> device: disconnected
> > > >> >>>> 
> > > >> >>>> Dongle 2:
> > > >> >>>>> HCI Event: Number of Completed Packets (0x13) plen 5
> > > >> >>>>> 
> > > >> >>>>  . * . . .
> > > >> >>>> 
> > > >> >>>> < HCI Command: Reset (0x03|0x0003) plen 0
> > > >> >>>> device: disconnected
> > > >> >>>> 
> > > >> >>>> 
> > > >> >>>> I think something triggers hci reset which causes this problem,
> > > >> >>>> but what exactly Triggers it i don't know.
> > > >> >>>> 
> > > >> >>>> 
> > > >> >>>> John
> > > >> >>> 
> > > >> >>> Hi all,
> > > >> >>> 
> > > >> >>> Is anyone going to give this problem a try, it has been like a
> > > >> >>> month now This is a real problem in the bluez stack and someone
> > > >> >>> have to look in this Issue.
> > > >> >>> 
> > > >> >>> John
> > > >> >>> 
> > > >> >>>> On Mon, May 17, 2010 at 5:21 PM, john michelle
> > > >> >>>> <jhnmichelle@gmail.com>
> > > > 
> > > > wrote:
> > > >> >>>>>> Hi Jonh,
> > > >> >>>>>> 
> > > >> >>>>>> First of all, don't do top posting in this mailing list. ;)
> > > >> >>>>> 
> > > >> >>>>> Thanks for the advise , will keep that in mind for future
> > > >> >>>>> posts.
> > > >> >>>>> 
> > > >> >>>>>> In which bluez/kernel version the problem started? Any
> > > >> >>>>>> hardware update during this time? The problem happens when
> > > >> >>>>>> you are already tranfering SCO data?
> > > >> >>>>> 
> > > >> >>>>> I tried bluez versions 3.XX  and kernel 2.6.26(I think) the
> > > >> >>>>> problem occurs and the kernel panics with no core dumps.then i
> > > >> >>>>> tried with bluez 4.53-4.62 with
> > > >> >>>>> Kernel 2.6.31 and 2.6.32. the connection abort problem occurs
> > > >> >>>>> but the kernel doesn't
> > > >> >>>>> Panic. regarding the hardware update you mean the dongle or
> > > >> >>>>> the box.Anyway i changed both and tried different box's, this
> > > >> >>>>> even happens on a box with 2 giga ram
> > > >> >>>>> And core2 processor . as for the dongles i am using trust
> > > >> >>>>> 
> > > >> >>>>> http://www.twenga.co.uk/prices-Bluetooth-2-USB-Adapter-10m-BT-
> > > >> >>>>> 2250 p-T RUST-Wireless-network-card-adapter-176178-0
> > > >> >>>>> 
> > > >> >>>>>  and also using no name dongles all the same problem.
> > > >> >>>>>  
> > > >> >>>>>> Please post the output of hcidump when the connection abort
> > > >> >>>>>> happens.
> > > >> >>>>> 
> > > >> >>>>> well that is going to be a hard one since i have more than one
> > > >> >>>>> dongle in place And very hard to predict which one will
> > > >> >>>>> crash.i will work on this and update You as soon as i have
> > > >> >>>>> the hcidump log.
> > > >> >>>>> 
> > > >> >>>>>> I tried reproduce this issue in L2CAP but it is a bit hard,
> > > >> >>>>>> lets say it happen once in a thousand, so it's not easy to
> > > >> >>>>>> track it. I have to try reproduce that using the SCO, but
> > > >> >>>>>> I'm not used to that layer yet. ;)
> > > >> >>>>> 
> > > >> >>>>> I hoped that it happens 1 in 1000 in SCO , but it actually
> > > >> >>>>> happens 1 in 15
> > > >> >>>>> 
> > > >> >>>>> 
> > > >> >>>>> John
> > > >> >>>>> 
> > > >> >>>>>> Regards,
> > > >> >>>>>> 
> > > >> >>>>>>> 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.
> > > >> >>>>>> 
> > > >> >>>>>> --
> > > >> >>>>>> Gustavo F. Padovan
> > > >> >>>>>> http://padovan.org
> > > >> 
> > > >> --
> > > >> 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
> > > 
> > > --
> > > 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
> > 
> > --
> > 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] Bluetooth: Resend ConfigReq on unknown options failure
From: Ville Tervo @ 2010-07-28 12:21 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <20100728071631.GD22156@vigoh>

On 07/28/2010 10:16 AM, ext Gustavo F. Padovan wrote:
> Hi Ville,
>
> * Gustavo F. Padovan<gustavo@padovan.org>  [2010-07-28 04:11:20 -0300]:
>
>> From: Gustavo F. Padovan<padovan@profusion.mobi>
>>
>> If the remote device send a ConfigRsp with the unknown options failure we
>> should remove that option from the ConfigReq and send it again.
>> This patch only remove the RFC option in the case it is a unknown option.
>>
>> Signed-off-by: Gustavo F. Padovan<padovan@profusion.mobi>
>> ---
>>   include/net/bluetooth/l2cap.h |   17 +++++++++--------
>>   net/bluetooth/l2cap.c         |   28 ++++++++++++++++++++++++----
>>   2 files changed, 33 insertions(+), 12 deletions(-)
>
> Can you please test thi patch? I think it fix the unknown option
> problem.

No it didn't help. I'll try to find out why it still fails.

-- 
Ville

^ permalink raw reply

* [PATCH 2/2] ebook backend: return all TEL attribs from vcard in string
From: Marcel Mol @ 2010-07-28  8:11 UTC (permalink / raw)
  To: linux-bluetooth

evcard_to_string() only took one TEL attrib from a vcard. But
multiple TEL attribs are supported. This patch will convert
all TEL attribs to strings.
---
 plugins/phonebook-ebook.c |   24 +++++++++++++-----------
 1 files changed, 13 insertions(+), 11 deletions(-)

diff --git a/plugins/phonebook-ebook.c b/plugins/phonebook-ebook.c
index 089b956..04b7900 100644
--- a/plugins/phonebook-ebook.c
+++ b/plugins/phonebook-ebook.c
@@ -97,6 +97,7 @@ static char *evcard_to_string(EVCard *evcard, unsigned int format,
 							uint64_t filter)
 {
 	EVCard *evcard2;
+	GList *l;
 	char *vcard;
 	unsigned int i;
 
@@ -109,18 +110,19 @@ static char *evcard_to_string(EVCard *evcard, unsigned int format,
 	 */
 	filter = format == EVC_FORMAT_VCARD_30 ? filter | 0x87: filter | 0x85;
 
+	l = e_vcard_get_attributes(evcard);
 	evcard2 = e_vcard_new();
-	for (i = 0; i < 29; i++) {
-		EVCardAttribute *attrib;
-
-		if (!(filter & (1 << i)))
-			continue;
-
-		attrib = e_vcard_get_attribute(evcard, attribute_mask[i]);
-		if (!attrib)
-			continue;
-
-		e_vcard_add_attribute(evcard2, e_vcard_attribute_copy(attrib));
+	for (; l; l = g_list_next(l)) {
+		EVCardAttribute *attrib = l->data;
+		if (attrib) {
+			const char *name = e_vcard_attribute_get_name(attrib);
+			for (i = 0; i < 29; i++) {
+				if (!(filter & (1 << i)))
+					continue;
+				if (!strcmp(name, attribute_mask[i]))
+					e_vcard_add_attribute(evcard2, e_vcard_attribute_copy(attrib));
+			}
+		}
 	}
 
 	vcard = e_vcard_to_string(evcard2, format);
-- 
1.7.1.1


^ permalink raw reply related

* [PATCH 16/16] Add initial support for synchronization protocol
From: Santiago Carot-Nemesio @ 2010-07-28  8:07 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1280304453-9328-3-git-send-email-sancane@gmail.com>

---
 Makefile.am        |    3 +-
 health/mcap.c      |    2 +-
 health/mcap.h      |   38 +++++++++++++++++++++++++++++++
 health/mcap_sync.c |   62 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 103 insertions(+), 2 deletions(-)
 create mode 100644 health/mcap_sync.c

diff --git a/Makefile.am b/Makefile.am
index c8bd62a..084879b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -171,7 +171,8 @@ endif
 
 if MCAP
 mcap_sources += health/mcap_lib.h health/mcap_internal.h \
-		health/mcap.h health/mcap.c
+		health/mcap.h health/mcap.c \
+		health/mcap_sync.c
 endif
 
 builtin_modules += hciops
diff --git a/health/mcap.c b/health/mcap.c
index f5f60ee..f00a484 100644
--- a/health/mcap.c
+++ b/health/mcap.c
@@ -1513,7 +1513,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) {
-		/* TODO: proc_sync_cmd(mcl, cmd, len);*/
+		proc_sync_cmd(mcl, cmd, len);
 		return;
 	}
 
diff --git a/health/mcap.h b/health/mcap.h
index bb05969..9b95473 100644
--- a/health/mcap.h
+++ b/health/mcap.h
@@ -111,6 +111,44 @@ typedef struct {
 	uint16_t        mdl;
 } __attribute__ ((packed)) mcap_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
 }
diff --git a/health/mcap_sync.c b/health/mcap_sync.c
new file mode 100644
index 0000000..569a40a
--- /dev/null
+++ b/health/mcap_sync.c
@@ -0,0 +1,62 @@
+/*
+ *
+ *  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"
+
+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 */
+		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 */
+		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


^ permalink raw reply related

* [PATCH 15/16] Add version and supported procedures values
From: Santiago Carot-Nemesio @ 2010-07-28  8:07 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1280304453-9328-2-git-send-email-sancane@gmail.com>

---
 health/mcap.h |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/health/mcap.h b/health/mcap.h
index 1c72080..bb05969 100644
--- a/health/mcap.h
+++ b/health/mcap.h
@@ -31,6 +31,11 @@
 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
-- 
1.6.3.3


^ permalink raw reply related

* [PATCH 14/16] Response with invalid operation when an invalid request is received
From: Santiago Carot-Nemesio @ 2010-07-28  8:07 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1280304453-9328-1-git-send-email-sancane@gmail.com>

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

diff --git a/health/mcap.c b/health/mcap.c
index df75752..f5f60ee 100644
--- a/health/mcap.c
+++ b/health/mcap.c
@@ -1164,7 +1164,15 @@ resp:
 
 static void invalid_req_state(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
 {
-	/* TODO: Implements invalid_req_state */
+	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);
+	mcap_send_cmd(mcl, cmd[0]+1, MCAP_INVALID_OPERATION, mdlr, NULL, 0);
 }
 
 /* Function used to process commands depending of MCL state */
-- 
1.6.3.3


^ permalink raw reply related

* [PATCH 13/16] Add functions for getting mdl properties
From: Santiago Carot-Nemesio @ 2010-07-28  8:07 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1280304232-2939-6-git-send-email-santoscadenas@gmail.com>

---
 health/mcap.c     |   16 ++++++++++++++++
 health/mcap_lib.h |    3 +++
 2 files changed, 19 insertions(+), 0 deletions(-)

diff --git a/health/mcap.c b/health/mcap.c
index 050a896..df75752 100644
--- a/health/mcap.c
+++ b/health/mcap.c
@@ -635,6 +635,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 -ENOTCONN;
+
+	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 mcap_free_mdls(struct mcap_mcl *mcl, gboolean save)
 {
 	GSList *l;
diff --git a/health/mcap_lib.h b/health/mcap_lib.h
index b9fc9a5..b6286a1 100644
--- a/health/mcap_lib.h
+++ b/health/mcap_lib.h
@@ -127,6 +127,9 @@ void mcap_mdl_abort(struct mcap_mdl *mdl,
 				gpointer user_data,
 				GError **err);
 
+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,
-- 
1.6.3.3


^ permalink raw reply related

* [PATCH 12/16] Process MCAP process_md_delete_mdl request and response commands
From: Jose Antonio Santos Cadenas @ 2010-07-28  8:03 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jose Antonio Santos Cadenas
In-Reply-To: <1280304232-2939-5-git-send-email-santoscadenas@gmail.com>

---
 health/mcap.c     |  203 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 health/mcap_lib.h |    8 ++
 2 files changed, 208 insertions(+), 3 deletions(-)

diff --git a/health/mcap.c b/health/mcap.c
index 18749e3..050a896 100644
--- a/health/mcap.c
+++ b/health/mcap.c
@@ -508,6 +508,86 @@ void mcap_reconnect_mdl(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)
+{
+	mcap_md_req *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_delete_all_mdls(struct mcap_mcl *mcl, mcap_mdl_notify_cb delete_cb,
+					gpointer user_data, GError **err)
+{
+	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.notify = delete_cb;
+	con->user_data = user_data;
+
+	send_delete_req(err, mcl, con, MCAP_ALL_MDLIDS);
+	if (*err)
+		g_free(con);
+}
+
+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;
+	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.notify = delete_cb;
+	con->user_data = user_data;
+
+	send_delete_req(err, mcl, con, mdl->mdlid);
+	if (*err)
+		g_free(con);
+}
+
 void mcap_mdl_abort(struct mcap_mdl *mdl, mcap_mdl_notify_cb abort_cb,
 					gpointer user_data, GError **err)
 {
@@ -816,6 +896,18 @@ void mcap_mcl_get_addr(struct mcap_mcl *mcl, bdaddr_t *addr)
 	bacpy(addr, &mcl->addr);
 }
 
+static void mcap_del_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)
 {
@@ -1000,7 +1092,58 @@ static void process_md_abort_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
 static void process_md_delete_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
 								uint32_t len)
 {
-	/* TODO: Implement process_md_delete_mdl_req */
+	mcap_md_req *req;
+	struct mcap_mdl *mdl, *aux;
+	uint16_t mdlid;
+	gboolean notify;
+	GSList *l;
+
+	if (len != sizeof(mcap_md_req)) {
+		mcap_send_cmd(mcl, MCAP_MD_ABORT_MDL_RSP,
+			MCAP_INVALID_PARAM_VALUE, MCAP_MDLID_RESERVED, NULL, 0);
+		return;
+	}
+
+	req = (mcap_md_req *)cmd;
+	mdlid = ntohs(req->mdl);
+	if (mdlid == MCAP_ALL_MDLIDS) {
+		notify = FALSE;
+		g_slist_foreach(mcl->mdls, mcap_del_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) {
+		mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_INVALID_MDL,
+								mdlid, NULL, 0);
+		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) {
+		mcap_send_cmd(mcl, MCAP_MD_DELETE_MDL_RSP, MCAP_INVALID_MDL,
+								mdlid, NULL, 0);
+		return;
+	}
+	mcl->mdls = g_slist_remove(mcl->mdls, mdl);
+	update_mcl_state(mcl);
+	notify = TRUE;
+	mcap_del_mdl(mdl, &notify);
+
+resp:
+	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)
@@ -1240,11 +1383,65 @@ 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)
 {
-	/* TODO: Implement process_md_delete_mdl_rsp */
-	return TRUE;
+	struct mcap_mdl_op_cb *del = mcl->priv_data;
+	struct mcap_mdl *mdl = del->mdl;
+	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);
+	GError *gerr = NULL;
+	gboolean close = FALSE;
+	gboolean notify = FALSE;
+
+	g_free(mcl->priv_data);
+	mcl->priv_data = NULL;
+
+	close = check_err_rsp(mcl, cmd, len, sizeof(mcap_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_del_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_del_mdl(mdl, &notify);
+end:
+	deleted_cb(gerr, user_data);
+	return close;
 }
 
 static void proc_response(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
diff --git a/health/mcap_lib.h b/health/mcap_lib.h
index fbf97df..b9fc9a5 100644
--- a/health/mcap_lib.h
+++ b/health/mcap_lib.h
@@ -108,6 +108,14 @@ void mcap_reconnect_mdl(struct mcap_mdl *mdl,
 				mcap_mdl_operation_cb reconnect_cb,
 				gpointer user_data,
 				GError **err);
+void mcap_delete_all_mdls(struct mcap_mcl *mcl,
+				mcap_mdl_notify_cb delete_cb,
+				gpointer user_data,
+				GError **err);
+void mcap_delete_mdl(struct mcap_mdl *mdl,
+				mcap_mdl_notify_cb delete_cb,
+				gpointer user_data,
+				GError **err);
 void mcap_connect_mdl(struct mcap_mdl *mdl,
 				BtIOType BtType,
 				uint16_t dcpsm,
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 11/16] Process MCAP process_md_reconnect_mdl request and response commands
From: Jose Antonio Santos Cadenas @ 2010-07-28  8:03 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jose Antonio Santos Cadenas
In-Reply-To: <1280304232-2939-4-git-send-email-santoscadenas@gmail.com>

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

diff --git a/health/mcap.c b/health/mcap.c
index 6006c2a..18749e3 100644
--- a/health/mcap.c
+++ b/health/mcap.c
@@ -471,6 +471,43 @@ void mcap_create_mdl(struct mcap_mcl *mcl,
 									mcl);
 }
 
+void mcap_reconnect_mdl(struct mcap_mdl *mdl,
+				mcap_mdl_operation_cb reconnect_cb,
+				gpointer user_data,
+				GError **err)
+{
+	struct mcap_mdl_op_cb *con;
+	struct mcap_mcl *mcl = mdl->mcl;
+	mcap_md_req *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);
+}
+
 void mcap_mdl_abort(struct mcap_mdl *mdl, mcap_mdl_notify_cb abort_cb,
 					gpointer user_data, GError **err)
 {
@@ -867,7 +904,53 @@ static void process_md_create_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
 static void process_md_reconnect_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
 								uint32_t len)
 {
-	/* TODO: Implement process_md_reconnect_mdl_req */
+	mcap_md_req *req;
+	struct mcap_mdl *mdl;
+	uint16_t mdl_id;
+	uint8_t rsp;
+
+	if (len != sizeof(mcap_md_req)) {
+		mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP,
+						MCAP_INVALID_PARAM_VALUE,
+						MCAP_MDLID_RESERVED,
+						NULL, 0);
+		return;
+	}
+
+	req = (mcap_md_req *)cmd;
+	mdl_id = ntohs(req->mdl);
+
+	mdl = get_mdl(mcl, mdl_id);
+	if (!mdl) {
+		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 */
+		mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_MDL_BUSY,
+							mdl_id, NULL, 0);
+		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) {
+		mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, rsp, mdl_id,
+								NULL, 0);
+		return;
+	}
+
+	if (mdl->state == MDL_CONNECTED)
+		shutdown_mdl(mdl);
+
+	mdl->state = MDL_WAITING;
+	mcl->state = MCL_PENDING;
+	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,
@@ -1086,8 +1169,40 @@ fail:
 static gboolean process_md_reconnect_mdl_rsp(struct mcap_mcl *mcl,
 						uint8_t *cmd, uint32_t len)
 {
-	/* TODO: Implement process_md_reconnect_mdl_rsp */
-	return TRUE;
+	struct mcap_mdl_op_cb *reconn = mcl->priv_data;
+	mcap_mdl_operation_cb reconn_cb = reconn->cb.op;
+	gpointer user_data = reconn->user_data;
+	struct mcap_mdl *mdl = reconn->mdl;
+	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(mcap_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);
+	update_mcl_state(mcl);
+
+	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,
diff --git a/health/mcap_lib.h b/health/mcap_lib.h
index 106c1c7..fbf97df 100644
--- a/health/mcap_lib.h
+++ b/health/mcap_lib.h
@@ -104,6 +104,10 @@ void mcap_create_mdl(struct mcap_mcl *mcl,
 				mcap_mdl_operation_conf_cb connect_cb,
 				gpointer user_data,
 				GError **err);
+void mcap_reconnect_mdl(struct mcap_mdl *mdl,
+				mcap_mdl_operation_cb reconnect_cb,
+				gpointer user_data,
+				GError **err);
 void mcap_connect_mdl(struct mcap_mdl *mdl,
 				BtIOType BtType,
 				uint16_t dcpsm,
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 10/16] Process MCAP process_md_abort_mdl request and response commands
From: Jose Antonio Santos Cadenas @ 2010-07-28  8:03 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jose Antonio Santos Cadenas
In-Reply-To: <1280304232-2939-3-git-send-email-santoscadenas@gmail.com>

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

diff --git a/health/mcap.c b/health/mcap.c
index ecaa43f..6006c2a 100644
--- a/health/mcap.c
+++ b/health/mcap.c
@@ -365,6 +365,18 @@ static uint16_t generate_mdlid(struct mcap_mcl *mcl)
 	return 0;
 }
 
+static mcap_md_req *create_req(uint8_t op, uint16_t mdl_id)
+{
+	mcap_md_req *req_cmd;
+
+	req_cmd = g_malloc0(sizeof(mcap_md_req));
+
+	req_cmd->op = op;
+	req_cmd->mdl = htons(mdl_id);
+
+	return req_cmd;
+}
+
 static mcap_md_create_mdl_req *create_mdl_req(uint16_t mdl_id, uint8_t mdep,
 								uint8_t conf)
 {
@@ -459,6 +471,38 @@ void mcap_create_mdl(struct mcap_mcl *mcl,
 									mcl);
 }
 
+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;
+	mcap_md_req *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.notify = abort_cb;
+	con->user_data = user_data;
+
+	mcl->priv_data = con;
+
+	mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
+									mcl);
+}
+
 static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr)
 {
 	GSList *l;
@@ -829,7 +873,45 @@ static void process_md_reconnect_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
 static void process_md_abort_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
 								uint32_t len)
 {
-	/* TODO: Implement process_md_abort_mdl_req */
+	mcap_md_req *req;
+	GSList *l;
+	struct mcap_mdl *mdl, *abrt;
+	uint16_t mdl_id;
+
+	if (len != sizeof(mcap_md_req)) {
+		mcap_send_cmd(mcl, MCAP_MD_ABORT_MDL_RSP,
+			MCAP_INVALID_PARAM_VALUE, MCAP_MDLID_RESERVED, NULL, 0);
+		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) {
+			abrt = mdl;
+			if (mcl->state != MCL_CONNECTED)
+				break;
+			continue;
+		}
+		if (mdl->state == MDL_CONNECTED && mcl->state != MCL_ACTIVE)
+			mcl->state = MCL_ACTIVE;
+
+		if (abrt && mcl->state == MCL_ACTIVE)
+			break;
+	}
+
+	if (!abrt) {
+		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;
+	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,
@@ -1011,8 +1093,36 @@ 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)
 {
-	/* TODO: Implement process_md_abort_mdl_rsp */
-	return TRUE;
+	struct mcap_mdl_op_cb *abrt = mcl->priv_data;
+	mcap_mdl_notify_cb abrt_cb = abrt->cb.notify;
+	gpointer user_data = abrt->user_data;
+	struct mcap_mdl *mdl = abrt->mdl;
+	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(mcap_rsp), &gerr);
+
+	g_free(mcl->lcmd);
+	mcl->lcmd = NULL;
+	mcl->req = MCL_AVAILABLE;
+
+	abrt_cb(gerr, user_data);
+	shutdown_mdl(mdl);
+
+	if (len >= sizeof(mcap_rsp) && rsp->rc == MCAP_INVALID_MDL) {
+		mcl->mdls = g_slist_remove(mcl->mdls, mdl);
+		g_free(mdl);
+	}
+
+	if (!gerr)
+		g_error_free(gerr);
+
+	update_mcl_state(mcl);
+	return close;
 }
 
 static gboolean process_md_delete_mdl_rsp(struct mcap_mcl *mcl, uint8_t *cmd,
diff --git a/health/mcap_lib.h b/health/mcap_lib.h
index 7bdcbc5..106c1c7 100644
--- a/health/mcap_lib.h
+++ b/health/mcap_lib.h
@@ -110,6 +110,10 @@ void mcap_connect_mdl(struct mcap_mdl *mdl,
 				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);
 
 /* Mcl operations*/
 
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 09/16] Implement connection of MCAP data links (MDL's)
From: Jose Antonio Santos Cadenas @ 2010-07-28  8:03 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jose Antonio Santos Cadenas
In-Reply-To: <1280304232-2939-2-git-send-email-santoscadenas@gmail.com>

---
 health/mcap.c     |  132 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 health/mcap_lib.h |    6 ++
 2 files changed, 137 insertions(+), 1 deletions(-)

diff --git a/health/mcap.c b/health/mcap.c
index 734c6be..ecaa43f 100644
--- a/health/mcap.c
+++ b/health/mcap.c
@@ -1097,6 +1097,87 @@ 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 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_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;
+
+	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)
 {
@@ -1191,6 +1272,21 @@ static void mcap_connect_mcl_cb(GIOChannel *chan, GError *conn_err,
 	}
 }
 
+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);
+}
+
 void mcap_create_mcl(struct mcap_instance *ms,
 				const bdaddr_t *addr,
 				uint16_t ccpsm,
@@ -1244,7 +1340,41 @@ void mcap_create_mcl(struct mcap_instance *ms,
 
 static void confirm_dc_event_cb(GIOChannel *chan, gpointer user_data)
 {
-	/* TODO: implement confirm_dc_event_cb */
+	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);
+				mdl->state = MDL_CLOSED;
+				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,
diff --git a/health/mcap_lib.h b/health/mcap_lib.h
index d8fb863..7bdcbc5 100644
--- a/health/mcap_lib.h
+++ b/health/mcap_lib.h
@@ -104,6 +104,12 @@ void mcap_create_mdl(struct mcap_mcl *mcl,
 				mcap_mdl_operation_conf_cb connect_cb,
 				gpointer user_data,
 				GError **err);
+void mcap_connect_mdl(struct mcap_mdl *mdl,
+				BtIOType BtType,
+				uint16_t dcpsm,
+				mcap_mdl_operation_cb connect_cb,
+				gpointer user_data,
+				GError **err);
 
 /* Mcl operations*/
 
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 08/16] Process MCAP response mcap_md_create_mdl_rsp
From: Jose Antonio Santos Cadenas @ 2010-07-28  8:03 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jose Antonio Santos Cadenas
In-Reply-To: <1280304232-2939-1-git-send-email-santoscadenas@gmail.com>

---
 health/mcap.c |  195 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 health/mcap.h |    6 ++
 2 files changed, 200 insertions(+), 1 deletions(-)

diff --git a/health/mcap.c b/health/mcap.c
index 9bb81cf..734c6be 100644
--- a/health/mcap.c
+++ b/health/mcap.c
@@ -126,6 +126,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, void *cmd,
 						uint32_t size, GError **err)
 {
@@ -854,9 +886,170 @@ 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(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;
+	mcap_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 < sizeof(mcap_rsp) || (mcl->lcmd[0] + 1) != cmd[0]) {
+		msg = "Protocol error";
+		close = TRUE;
+		goto fail;
+	}
+
+	if (rlen < len) {
+		msg = "Protocol error";
+		close = TRUE;
+		goto fail;
+	}
+
+	rsp = (mcap_rsp *)cmd;
+	smdl = ntohs(cmdlast->mdl);
+	rmdl = ntohs(rsp->mdl);
+	if (rmdl != smdl) {
+		msg = "MDLID received doesn't match with MDLID sent";
+		close = TRUE;
+		goto fail;
+	}
+
+	if (rsp->rc == MCAP_REQUEST_NOT_SUPPORTED) {
+		msg = "Remote does not support opcodes";
+		mcl->ctrl &= ~MCAP_CTRL_STD_OP;
+		goto fail;
+	}
+
+	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;
+}
+
+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;
+	mcap_mdl_operation_conf_cb connect_cb = conn->cb.op_conf;
+	gpointer user_data = conn->user_data;
+	struct mcap_mdl *mdl = conn->mdl;
+	uint8_t conf = cmdlast->conf;
+	gboolean close = FALSE;
+	GError *gerr = NULL;
+	uint8_t *param;
+
+	g_free(mcl->priv_data);
+	mcl->priv_data = NULL;
+
+	close = check_err_rsp(mcl, cmd, len, sizeof(mcap_rsp) + 1, &gerr);
+	g_free(mcl->lcmd);
+	mcl->lcmd = NULL;
+	mcl->req = MCL_AVAILABLE;
+
+	if (gerr)
+		goto fail;
+
+	if (len < sizeof(mcap_rsp)) {
+		g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_FAILED,
+							"Protocol error");
+		close = TRUE;
+		goto fail;
+	}
+
+	param = cmd + sizeof(mcap_rsp);
+	/* Check if preferences changed */
+	if (conf != 0x00 && *param != conf) {
+		g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_FAILED,
+						"Configuration changed");
+		close = TRUE;
+		goto fail;
+	}
+
+	connect_cb(mdl, *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);
+	update_mcl_state(mcl);
+	return close;
+}
+
+static gboolean process_md_reconnect_mdl_rsp(struct mcap_mcl *mcl,
+						uint8_t *cmd, uint32_t len)
+{
+	/* TODO: Implement process_md_reconnect_mdl_rsp */
+	return TRUE;
+}
+
+static gboolean process_md_abort_mdl_rsp(struct mcap_mcl *mcl,
+						uint8_t *cmd, uint32_t len)
+{
+	/* TODO: Implement process_md_abort_mdl_rsp */
+	return TRUE;
+}
+
+static gboolean process_md_delete_mdl_rsp(struct mcap_mcl *mcl, uint8_t *cmd,
+								uint32_t len)
+{
+	/* TODO: Implement process_md_delete_mdl_rsp */
+	return TRUE;
+}
+
 static void proc_response(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
 {
-	/* TODO: Implement proc_response */
+	gboolean close;
+	RELEASE_TIMER(mcl);
+
+	switch (mcl->lcmd[0] + 1) {
+	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 proc_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
diff --git a/health/mcap.h b/health/mcap.h
index d0d552a..1c72080 100644
--- a/health/mcap.h
+++ b/health/mcap.h
@@ -90,6 +90,12 @@ typedef struct {
 	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
  */
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 07/16] Process MCAP request mcap_md_create_mdl_req
From: Jose Antonio Santos Cadenas @ 2010-07-28  8:03 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jose Antonio Santos Cadenas
In-Reply-To: <1280304015-9230-7-git-send-email-sancane@gmail.com>

---
 health/mcap.c |  255 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 health/mcap.h |    5 +
 2 files changed, 255 insertions(+), 5 deletions(-)

diff --git a/health/mcap.c b/health/mcap.c
index 7366c66..9bb81cf 100644
--- a/health/mcap.c
+++ b/health/mcap.c
@@ -163,9 +163,103 @@ static void mcap_send_std_opcode(struct mcap_mcl *mcl, void *cmd,
 	mcl->req = MCL_WAITING_RSP;
 }
 
+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)
 {
-	/* TODO: implement mcap_notify_error */
+	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:
+		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:
+		st = MDL_WAITING;
+		l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state);
+		shutdown_mdl(l->data);
+		update_mcl_state(mcl);
+		con->cb.notify(err, con->user_data);
+		break;
+	case MCAP_MD_DELETE_MDL_REQ:
+		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.notify(err, con->user_data);
+		break;
+	case MCAP_MD_RECONNECT_MDL_REQ:
+		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)
@@ -350,7 +444,23 @@ static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr)
 
 static void mcap_free_mdls(struct mcap_mcl *mcl, gboolean save)
 {
-	/* TODO: implement mcap_free_mdls */
+	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)
@@ -593,20 +703,155 @@ void mcap_mcl_get_addr(struct mcap_mcl *mcl, bdaddr_t *addr)
 	bacpy(addr, &mcl->addr);
 }
 
+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)) {
+		mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP,
+						MCAP_INVALID_PARAM_VALUE,
+						MCAP_MDLID_RESERVED,
+						NULL, 0);
+		return;
+	}
+
+	req = (mcap_md_create_mdl_req *)cmd;
+
+	mdl_id = ntohs(req->mdl);
+	if (mdl_id < MCAP_MDLID_INITIAL || mdl_id > MCAP_MDLID_FINAL) {
+		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) {
+		mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_INVALID_MDEP,
+							mdl_id, NULL, 0);
+		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 */
+		mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_MDL_BUSY,
+							mdl_id, NULL, 0);
+		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 */
+		mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP,
+				MCAP_UNSPECIFIED_ERROR, mdl_id, NULL, 0);
+		return;
+	}
+	if (rsp != MCAP_SUCCESS) {
+		mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, rsp, mdl_id,
+								NULL, 0);
+		return;
+	}
+
+	if (!mdl) {
+		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 */
+		shutdown_mdl(mdl);
+	}
+
+	mdl->mdep_id = mdep_id;
+	mdl->state = MDL_WAITING;
+
+	mcl->state = MCL_PENDING;
+	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,
+								uint32_t len)
+{
+	/* TODO: Implement process_md_reconnect_mdl_req */
+}
+
+static void process_md_abort_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
+								uint32_t len)
+{
+	/* TODO: Implement process_md_abort_mdl_req */
+}
+
+static void process_md_delete_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
+								uint32_t len)
+{
+	/* TODO: Implement process_md_delete_mdl_req */
+}
+
+static void invalid_req_state(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
+{
+	/* TODO: Implements invalid_req_state */
+}
+
 /* 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: Implement proc_req_connected */
+	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:
+		invalid_req_state(mcl, cmd, len);
+	}
 }
 
 static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
 {
-	/* TODO: Implement proc_req_pending */
+	if (cmd[0] == MCAP_MD_ABORT_MDL_REQ)
+		process_md_abort_mdl_req(mcl, cmd, len);
+	else
+		invalid_req_state(mcl, cmd, len);
 }
 
 static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
 {
-	/* TODO: Implement proc_req_active */
+	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:
+		invalid_req_state(mcl, cmd, len);
+	}
 }
 
 static void proc_response(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
diff --git a/health/mcap.h b/health/mcap.h
index 8c3679f..d0d552a 100644
--- a/health/mcap.h
+++ b/health/mcap.h
@@ -74,6 +74,11 @@ extern "C" {
 #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
  */
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 06/16] Send MCAP request mcap_md_create_mdl_req
From: Santiago Carot-Nemesio @ 2010-07-28  8:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1280304015-9230-6-git-send-email-sancane@gmail.com>

---
 health/mcap.c          |  178 ++++++++++++++++++++++++++++++++++++++++++++++++
 health/mcap.h          |   11 +++
 health/mcap_internal.h |   16 ++++
 health/mcap_lib.h      |    9 +++
 4 files changed, 214 insertions(+), 0 deletions(-)

diff --git a/health/mcap.c b/health/mcap.c
index 73562c3..7366c66 100644
--- a/health/mcap.c
+++ b/health/mcap.c
@@ -35,6 +35,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")
@@ -50,6 +51,18 @@ 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_notify_cb		notify;
+} 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);
 static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l);
@@ -61,6 +74,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");
@@ -111,6 +126,43 @@ 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, void *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)
 {
 	/* TODO: implement mcap_notify_error */
@@ -155,6 +207,132 @@ static int mcap_send_cmd(struct mcap_mcl *mcl, uint8_t oc, uint8_t rc,
 	return sent;
 }
 
+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 uint16_t generate_mdlid(struct mcap_mcl *mcl)
+{
+	uint16_t mdlid = mcl->next_mdl;
+	struct mcap_mdl *mdl;
+
+	do {
+		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 mcap_md_create_mdl_req *create_mdl_req(uint16_t mdl_id, uint8_t mdep,
+								uint8_t conf)
+{
+	mcap_md_create_mdl_req *req_mdl;
+
+	req_mdl = g_malloc0(sizeof(mcap_md_create_mdl_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_mdl;
+}
+
+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 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_create_mdl(struct mcap_mcl *mcl,
+				uint8_t mdepid,
+				uint8_t conf,
+				mcap_mdl_operation_conf_cb connect_cb,
+				gpointer user_data,
+				GError **err)
+{
+	struct mcap_mdl *mdl;
+	struct mcap_mdl_op_cb *con;
+	mcap_md_create_mdl_req *cmd;
+	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 struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr)
 {
 	GSList *l;
diff --git a/health/mcap.h b/health/mcap.h
index 523be90..8c3679f 100644
--- a/health/mcap.h
+++ b/health/mcap.h
@@ -75,6 +75,17 @@ extern "C" {
 #define MCAP_ALL_MDLIDS			0xFFFF
 
 /*
+ * 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;
+
+/*
  * MCAP Response Packet Format
  */
 
diff --git a/health/mcap_internal.h b/health/mcap_internal.h
index cc81692..d639cdb 100644
--- a/health/mcap_internal.h
+++ b/health/mcap_internal.h
@@ -48,6 +48,13 @@ typedef enum {
 	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 */
@@ -97,6 +104,15 @@ struct mcap_mcl {
 #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);
diff --git a/health/mcap_lib.h b/health/mcap_lib.h
index b4e9c16..d8fb863 100644
--- a/health/mcap_lib.h
+++ b/health/mcap_lib.h
@@ -96,6 +96,15 @@ typedef void (* mcap_mcl_connect_cb) (struct mcap_mcl *mcl, GError *err,
 
 /************ Operations ************/
 
+/* Mdl operations*/
+
+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);
+
 /* Mcl operations*/
 
 void mcap_create_mcl(struct mcap_instance *ms,
-- 
1.6.3.3


^ permalink raw reply related

* [PATCH 05/16] Prepare FSM functions for processing comands
From: Santiago Carot-Nemesio @ 2010-07-28  8:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1280304015-9230-5-git-send-email-sancane@gmail.com>

---
 health/mcap.c          |  192 +++++++++++++++++++++++++++++++++++++++++++++++-
 health/mcap.h          |   29 +++++++
 health/mcap_internal.h |    4 +
 3 files changed, 224 insertions(+), 1 deletions(-)

diff --git a/health/mcap.c b/health/mcap.c
index ba2b2ad..73562c3 100644
--- a/health/mcap.c
+++ b/health/mcap.c
@@ -35,6 +35,8 @@
 #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 {	\
@@ -48,6 +50,17 @@ struct connect_mcl {
 	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);
+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");
@@ -98,6 +111,50 @@ static void set_default_cb(struct mcap_mcl *mcl)
 	mcl->cb->mdl_reconn_req = default_mdl_reconn_req_cb;
 }
 
+static void mcap_notify_error(struct mcap_mcl *mcl, GError *err)
+{
+	/* TODO: implement mcap_notify_error */
+}
+
+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 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;
+	int sock, sent;
+
+	if (mcl->cc == NULL)
+		return -1;
+
+	sock = g_io_channel_unix_get_fd(mcl->cc);
+
+	rsp = g_malloc(sizeof(mcap_rsp) + len);
+	cmd = (mcap_rsp *)rsp;
+	cmd->op = oc;
+	cmd->rc = rc;
+	cmd->mdl = htons(mdl);
+
+	if (data && len > 0)
+		memcpy(rsp + sizeof(mcap_rsp), data, len);
+
+	sent = mcap_send_data(sock, rsp, sizeof(mcap_rsp) + len);
+	g_free(rsp);
+	return sent;
+}
+
 static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr)
 {
 	GSList *l;
@@ -176,6 +233,46 @@ static void mcap_mcl_check_del(struct mcap_mcl *mcl)
 		mcap_mcl_unref(mcl);
 }
 
+static void mcap_cache_mcl(struct mcap_mcl *mcl)
+{
+	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)
 {
 	if (!(mcl->ctrl & MCAP_CTRL_CACHED))
@@ -318,10 +415,103 @@ void mcap_mcl_get_addr(struct mcap_mcl *mcl, bdaddr_t *addr)
 	bacpy(addr, &mcl->addr);
 }
 
+/* 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: Implement proc_req_connected */
+}
+
+static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
+{
+	/* TODO: Implement proc_req_pending */
+}
+
+static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
+{
+	/* TODO: Implement proc_req_active */
+}
+
+static void proc_response(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
+{
+	/* TODO: Implement proc_response */
+}
+
+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]);
+		mcap_send_cmd(mcl, MCAP_ERROR_RSP, MCAP_INVALID_OP_CODE,
+						MCAP_MDLID_RESERVED, NULL, 0);
+		return;
+	}
+
+	if (cmd[0] >= MCAP_MD_SYNC_CAP_REQ &&
+					cmd[0] <= MCAP_MD_SYNC_INFO_IND) {
+		/* TODO: proc_sync_cmd(mcl, cmd, len);*/
+		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;
+			/* 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);
+			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: Create mcl_control_cb */
+	GError *gerr = NULL;
+
+	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) {
+		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);
+			g_error_free(gerr);
+		}
+		mcl->ms->mcl_disconnected_cb(mcl, mcl->ms->user_data);
+	}
+	mcap_cache_mcl(mcl);
 	return FALSE;
 }
 
diff --git a/health/mcap.h b/health/mcap.h
index a45cc8a..523be90 100644
--- a/health/mcap.h
+++ b/health/mcap.h
@@ -35,6 +35,25 @@ extern "C" {
 #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
@@ -55,6 +74,16 @@ extern "C" {
 #define MCAP_MDLID_FINAL		0xFEFF
 #define MCAP_ALL_MDLIDS			0xFFFF
 
+/*
+ * MCAP Response Packet Format
+ */
+
+typedef struct {
+	uint8_t         op;
+	uint8_t         rc;
+	uint16_t        mdl;
+} __attribute__ ((packed)) mcap_rsp;
+
 
 #ifdef __cplusplus
 }
diff --git a/health/mcap_internal.h b/health/mcap_internal.h
index aab9e06..cc81692 100644
--- a/health/mcap_internal.h
+++ b/health/mcap_internal.h
@@ -97,6 +97,10 @@ struct mcap_mcl {
 #define	MCAP_CTRL_FREE		0x10	/* MCL is marked as releasable */
 #define	MCAP_CTRL_NOCACHE	0x20	/* MCL is marked as not cacheable */
 
+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);
+
 #ifdef __cplusplus
 }
 #endif
-- 
1.6.3.3


^ permalink raw reply related

* [PATCH 04/16] Added function for MCAP control channel (MCL) management
From: Santiago Carot-Nemesio @ 2010-07-28  8:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1280304015-9230-4-git-send-email-sancane@gmail.com>

---
 health/mcap.c     |  270 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 health/mcap_lib.h |   30 ++++++
 2 files changed, 298 insertions(+), 2 deletions(-)

diff --git a/health/mcap.c b/health/mcap.c
index 282580d..ba2b2ad 100644
--- a/health/mcap.c
+++ b/health/mcap.c
@@ -37,6 +37,16 @@
 
 #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)
+
+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 */
+};
 
 static void default_mdl_connected_cb(struct mcap_mdl *mdl, gpointer data)
 {
@@ -103,14 +113,59 @@ static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr)
 	return NULL;
 }
 
+static void mcap_free_mdls(struct mcap_mcl *mcl, gboolean save)
+{
+	/* TODO: implement mcap_free_mdls */
+}
+
+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)
 {
-	/* TODO: implement mcap_mcl_shutdown */
+	close_mcl(mcl, TRUE);
 }
 
 static void mcap_mcl_release(struct mcap_mcl *mcl)
 {
-	/* TODO: implement mcap_mcl_release */
+	close_mcl(mcl, FALSE);
 }
 
 static void mcap_mcl_check_del(struct mcap_mcl *mcl)
@@ -134,6 +189,23 @@ static void mcap_uncache_mcl(struct mcap_mcl *mcl)
 	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)
 {
 	mcl->ref++;
@@ -164,12 +236,206 @@ 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, gpointer user_data, GError **gerr,
+							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;
+}
+
+void mcap_mcl_get_addr(struct mcap_mcl *mcl, bdaddr_t *addr)
+{
+	bacpy(addr, &mcl->addr);
+}
+
 static gboolean mcl_control_cb(GIOChannel *chan, GIOCondition cond,
 								gpointer data)
 {
 	/* TODO: Create mcl_control_cb */
 	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);
+	}
+}
+
+void mcap_create_mcl(struct mcap_instance *ms,
+				const bdaddr_t *addr,
+				uint16_t ccpsm,
+				mcap_mcl_connect_cb connect_cb,
+				gpointer user_data,
+				GError **err)
+{
+	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->next_mdl = (rand() % MCAP_MDLID_FINAL) + 1;
+		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)
 {
 	/* TODO: implement confirm_dc_event_cb */
diff --git a/health/mcap_lib.h b/health/mcap_lib.h
index fcf69ee..b4e9c16 100644
--- a/health/mcap_lib.h
+++ b/health/mcap_lib.h
@@ -56,6 +56,16 @@ typedef enum {
 	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;
@@ -65,6 +75,11 @@ struct mcap_mdl;
 /* 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_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,
@@ -76,9 +91,24 @@ typedef uint8_t (* mcap_remote_mdl_reconn_req_cb) (struct mcap_mdl *mdl,
 /* 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 ************/
 
+/* Mcl operations*/
+
+void mcap_create_mcl(struct mcap_instance *ms,
+				const bdaddr_t *addr,
+				uint16_t ccpsm,
+				mcap_mcl_connect_cb connect_cb,
+				gpointer user_data,
+				GError **err);
+void mcap_close_mcl(struct mcap_mcl *mcl, gboolean cache);
+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);
 void mcap_mcl_unref(struct mcap_mcl *mcl);
 
-- 
1.6.3.3


^ permalink raw reply related

* [PATCH 03/16] Receive MCAP mcl connections from remote devices
From: Santiago Carot-Nemesio @ 2010-07-28  8:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1280304015-9230-3-git-send-email-sancane@gmail.com>

---
 health/mcap.c          |  209 +++++++++++++++++++++++++++++++++++++++++++++++-
 health/mcap.h          |   21 +++++
 health/mcap_internal.h |   52 ++++++++++++
 health/mcap_lib.h      |   15 ++++
 4 files changed, 295 insertions(+), 2 deletions(-)

diff --git a/health/mcap.c b/health/mcap.c
index 54e6355..282580d 100644
--- a/health/mcap.c
+++ b/health/mcap.c
@@ -38,24 +38,229 @@
 #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_shutdown(struct mcap_mcl *mcl)
 {
 	/* TODO: implement mcap_mcl_shutdown */
 }
 
+static void mcap_mcl_release(struct mcap_mcl *mcl)
+{
+	/* TODO: implement mcap_mcl_release */
+}
+
+static void mcap_mcl_check_del(struct mcap_mcl *mcl)
+{
+	if (mcl->ctrl & MCAP_CTRL_CACHED)
+		mcap_mcl_shutdown(mcl);
+	else
+		mcap_mcl_unref(mcl);
+}
+
+static void mcap_uncache_mcl(struct mcap_mcl *mcl)
+{
+	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;
+}
+
+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)
 {
-	/* TODO: implement mcap_mcl_unref */
+	mcl->ref--;
+
+	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;
+
+	mcap_mcl_release(mcl);
 }
 
+static gboolean mcl_control_cb(GIOChannel *chan, GIOCondition cond,
+								gpointer data)
+{
+	/* TODO: Create mcl_control_cb */
+	return FALSE;
+}
 static void confirm_dc_event_cb(GIOChannel *chan, gpointer user_data)
 {
 	/* TODO: implement confirm_dc_event_cb */
 }
 
+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: implement confirm_mcl_event_cb */
+	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->next_mdl = (rand() % MCAP_MDLID_FINAL) + 1;
+		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,
diff --git a/health/mcap.h b/health/mcap.h
index 139b562..a45cc8a 100644
--- a/health/mcap.h
+++ b/health/mcap.h
@@ -35,6 +35,27 @@ extern "C" {
 #define MCAP_CC_MTU	48
 #define MCAP_DC_MTU	L2CAP_DEFAULT_MTU
 
+/* 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
+
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/health/mcap_internal.h b/health/mcap_internal.h
index ed4ed58..aab9e06 100644
--- a/health/mcap_internal.h
+++ b/health/mcap_internal.h
@@ -31,6 +31,33 @@
 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;
+
+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 */
@@ -45,6 +72,31 @@ struct mcap_instance {
 	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 */
+	uint16_t		next_mdl;	/* id used to create next MDL */
+};
+
+#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 */
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/health/mcap_lib.h b/health/mcap_lib.h
index 81d8b14..fcf69ee 100644
--- a/health/mcap_lib.h
+++ b/health/mcap_lib.h
@@ -58,15 +58,30 @@ typedef enum {
 
 struct mcap_instance;
 struct mcap_mcl;
+struct mcap_mdl;
 
 /************ Callbacks ************/
 
+/* mdl callbacks */
+
+typedef void (* mcap_mdl_event_cb) (struct mcap_mdl *mdl, 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);
 
 /************ Operations ************/
 
+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,
-- 
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