Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH v2 1/1] Makes extract_svclass_uuid function public
From: Elvis Pfützenreuter @ 2010-05-13 15:08 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: epx

This patch makes the extract_svclass_uuid function public,
so it may be used by applications that link to libbluetooth.
---
 lib/sdp.c     |    8 ++++----
 lib/sdp_lib.h |    1 +
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/lib/sdp.c b/lib/sdp.c
index aa22c63..fb8ccdc 100644
--- a/lib/sdp.c
+++ b/lib/sdp.c
@@ -591,7 +591,7 @@ sdp_data_t *sdp_seq_alloc(void **dtds, void **values, int len)
 	return sdp_data_alloc(SDP_SEQ8, seq);
 }
 
-static void extract_svclass_uuid(sdp_data_t *data, uuid_t *uuid)
+void sdp_extract_svclass_uuid(sdp_data_t *data, uuid_t *uuid)
 {
 	sdp_data_t *d;
 
@@ -619,7 +619,7 @@ int sdp_attr_add(sdp_record_t *rec, uint16_t attr, sdp_data_t *d)
 	rec->attrlist = sdp_list_insert_sorted(rec->attrlist, d, sdp_attrid_comp_func);
 
 	if (attr == SDP_ATTR_SVCLASS_ID_LIST)
-		extract_svclass_uuid(d, &rec->svclass);
+		sdp_extract_svclass_uuid(d, &rec->svclass);
 
 	return 0;
 }
@@ -978,7 +978,7 @@ void sdp_attr_replace(sdp_record_t *rec, uint16_t attr, sdp_data_t *d)
 	rec->attrlist = sdp_list_insert_sorted(rec->attrlist, d, sdp_attrid_comp_func);
 
 	if (attr == SDP_ATTR_SVCLASS_ID_LIST)
-		extract_svclass_uuid(d, &rec->svclass);
+		sdp_extract_svclass_uuid(d, &rec->svclass);
 }
 
 int sdp_attrid_comp_func(const void *key1, const void *key2)
@@ -1478,7 +1478,7 @@ sdp_record_t *sdp_extract_pdu(const uint8_t *buf, int bufsize, int *scanned)
 			rec->handle = data->val.uint32;
 
 		if (attr == SDP_ATTR_SVCLASS_ID_LIST)
-			extract_svclass_uuid(data, &rec->svclass);
+			sdp_extract_svclass_uuid(data, &rec->svclass);
 
 		extracted += n;
 		p += n;
diff --git a/lib/sdp_lib.h b/lib/sdp_lib.h
index e506ac1..3d70f0e 100644
--- a/lib/sdp_lib.h
+++ b/lib/sdp_lib.h
@@ -167,6 +167,7 @@ sdp_data_t *sdp_seq_alloc(void **dtds, void **values, int len);
 sdp_data_t *sdp_seq_alloc_with_length(void **dtds, void **values, int *length, int len);
 sdp_data_t *sdp_seq_append(sdp_data_t *seq, sdp_data_t *data);
 
+void sdp_extract_svclass_uuid(sdp_data_t *data, uuid_t *uuid);
 int sdp_attr_add(sdp_record_t *rec, uint16_t attr, sdp_data_t *data);
 void sdp_attr_remove(sdp_record_t *rec, uint16_t attr);
 void sdp_attr_replace(sdp_record_t *rec, uint16_t attr, sdp_data_t *data);
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 9/20] drivers/bluetooth: Use kzalloc
From: Julia Lawall @ 2010-05-13 20:02 UTC (permalink / raw)
  To: Marcel Holtmann, linux-bluetooth, linux-kernel, kernel-janitors

From: Julia Lawall <julia@diku.dk>

Use kzalloc rather than the combination of kmalloc and memset.

The semantic patch that makes this change is as follows:
(http://coccinelle.lip6.fr/)

// <smpl>
@@
expression x,size,flags;
statement S;
@@

-x = kmalloc(size,flags);
+x = kzalloc(size,flags);
 if (x == NULL) S
-memset(x, 0, size);
// </smpl>

Signed-off-by: Julia Lawall <julia@diku.dk>

---
 drivers/bluetooth/btmrvl_sdio.c |    8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff -u -p a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
--- a/drivers/bluetooth/btmrvl_sdio.c
+++ b/drivers/bluetooth/btmrvl_sdio.c
@@ -216,7 +216,7 @@ static int btmrvl_sdio_download_helper(s
 
 	tmphlprbufsz = ALIGN_SZ(BTM_UPLD_SIZE, BTSDIO_DMA_ALIGN);
 
-	tmphlprbuf = kmalloc(tmphlprbufsz, GFP_KERNEL);
+	tmphlprbuf = kzalloc(tmphlprbufsz, GFP_KERNEL);
 	if (!tmphlprbuf) {
 		BT_ERR("Unable to allocate buffer for helper."
 			" Terminating download");
@@ -224,8 +224,6 @@ static int btmrvl_sdio_download_helper(s
 		goto done;
 	}
 
-	memset(tmphlprbuf, 0, tmphlprbufsz);
-
 	helperbuf = (u8 *) ALIGN_ADDR(tmphlprbuf, BTSDIO_DMA_ALIGN);
 
 	/* Perform helper data transfer */
@@ -318,7 +316,7 @@ static int btmrvl_sdio_download_fw_w_hel
 	BT_DBG("Downloading FW image (%d bytes)", firmwarelen);
 
 	tmpfwbufsz = ALIGN_SZ(BTM_UPLD_SIZE, BTSDIO_DMA_ALIGN);
-	tmpfwbuf = kmalloc(tmpfwbufsz, GFP_KERNEL);
+	tmpfwbuf = kzalloc(tmpfwbufsz, GFP_KERNEL);
 	if (!tmpfwbuf) {
 		BT_ERR("Unable to allocate buffer for firmware."
 		       " Terminating download");
@@ -326,8 +324,6 @@ static int btmrvl_sdio_download_fw_w_hel
 		goto done;
 	}
 
-	memset(tmpfwbuf, 0, tmpfwbufsz);
-
 	/* Ensure aligned firmware buffer */
 	fwbuf = (u8 *) ALIGN_ADDR(tmpfwbuf, BTSDIO_DMA_ALIGN);
 

^ permalink raw reply

* Re: [PATCH 9/20] drivers/bluetooth: Use kzalloc
From: Gustavo F. Padovan @ 2010-05-13 20:23 UTC (permalink / raw)
  To: Julia Lawall
  Cc: Marcel Holtmann, linux-bluetooth, linux-kernel, kernel-janitors
In-Reply-To: <Pine.LNX.4.64.1005132201470.6282@ask.diku.dk>

* Julia Lawall <julia@diku.dk> [2010-05-13 22:02:03 +0200]:

> From: Julia Lawall <julia@diku.dk>
> 
> Use kzalloc rather than the combination of kmalloc and memset.
> 
> The semantic patch that makes this change is as follows:
> (http://coccinelle.lip6.fr/)
> 
> // <smpl>
> @@
> expression x,size,flags;
> statement S;
> @@
> 
> -x = kmalloc(size,flags);
> +x = kzalloc(size,flags);
>  if (x == NULL) S
> -memset(x, 0, size);
> // </smpl>
> 
> Signed-off-by: Julia Lawall <julia@diku.dk>
> 
> ---
>  drivers/bluetooth/btmrvl_sdio.c |    8 ++------
>  1 file changed, 2 insertions(+), 6 deletions(-)
> 
> diff -u -p a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
> --- a/drivers/bluetooth/btmrvl_sdio.c
> +++ b/drivers/bluetooth/btmrvl_sdio.c
> @@ -216,7 +216,7 @@ static int btmrvl_sdio_download_helper(s
>  
>  	tmphlprbufsz = ALIGN_SZ(BTM_UPLD_SIZE, BTSDIO_DMA_ALIGN);
>  
> -	tmphlprbuf = kmalloc(tmphlprbufsz, GFP_KERNEL);
> +	tmphlprbuf = kzalloc(tmphlprbufsz, GFP_KERNEL);
>  	if (!tmphlprbuf) {
>  		BT_ERR("Unable to allocate buffer for helper."
>  			" Terminating download");
> @@ -224,8 +224,6 @@ static int btmrvl_sdio_download_helper(s
>  		goto done;
>  	}
>  
> -	memset(tmphlprbuf, 0, tmphlprbufsz);
> -
>  	helperbuf = (u8 *) ALIGN_ADDR(tmphlprbuf, BTSDIO_DMA_ALIGN);
>  
>  	/* Perform helper data transfer */
> @@ -318,7 +316,7 @@ static int btmrvl_sdio_download_fw_w_hel
>  	BT_DBG("Downloading FW image (%d bytes)", firmwarelen);
>  
>  	tmpfwbufsz = ALIGN_SZ(BTM_UPLD_SIZE, BTSDIO_DMA_ALIGN);
> -	tmpfwbuf = kmalloc(tmpfwbufsz, GFP_KERNEL);
> +	tmpfwbuf = kzalloc(tmpfwbufsz, GFP_KERNEL);
>  	if (!tmpfwbuf) {
>  		BT_ERR("Unable to allocate buffer for firmware."
>  		       " Terminating download");
> @@ -326,8 +324,6 @@ static int btmrvl_sdio_download_fw_w_hel
>  		goto done;
>  	}
>  
> -	memset(tmpfwbuf, 0, tmpfwbufsz);
> -
>  	/* Ensure aligned firmware buffer */
>  	fwbuf = (u8 *) ALIGN_ADDR(tmpfwbuf, BTSDIO_DMA_ALIGN);
>  

Acked-by: Gustavo F. Padovan <padovan@profusion.mobi>

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

^ permalink raw reply

* Re: Software caused connection abort (103 )
From: john michelle @ 2010-05-13 21:39 UTC (permalink / raw)
  To: Gustavo F. Padovan; +Cc: linux-bluetooth
In-Reply-To: <20100507195325.GB4857@vigoh>

Hi Gustavo,

Any update on the software caused connection abort issue, it's happenning more
And more making bluez unstable for our application

John

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

^ permalink raw reply

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

Hello José!

Thank you very much for the explanation on the sessions abstraction.
Now I understood what you're trying to expose and I think the whole
confusion upraised from the nomenclature 'session', which is usually
used for defining a well-known slice of time (with known beginning and
end) in which some events are comprised. Wouldn't it be better to
change this to something like "Instance", to keep consistency with
MCAP spec?

For the sake of sanity, I'll keep using the Session nomenclature on
comments bellow, we can discuss interface names on a further review
round.

On Thu, May 13, 2010 at 05:02, José Antonio Santos Cadenas
<jcaden@libresoft.es> wrote:
> Hi João,
>
> Thank you very much for you comments :)
>
> El Thursday 13 May 2010 00:03:51 João Paulo Rechi Vita escribió:
>> Hello Jose!
>>
>> On Wed, May 12, 2010 at 06:26, José Antonio Santos Cadenas
>>
>> <jcaden@libresoft.es> wrote:
>> > This api is a clean up of the previous one the changes.
>> >
>> > We've added a new object that uses device path to get the sessions
>> > allocated on this device (as somebody recommended in other thread,
>> > I think Luiz, Elvis or both, but I can't find the exact email). The
>> > discovery of new remote session should be done using device drivers,
>> > which is compliant with the BlueZ style.
>> >
>> > Discussions still in progress:
>> >
>> > - Fd-passing issue: As Elvis, Santiago and I discussed yesterday on
>> > IRC we think that the best propose is as follows (please Elvis correct
>> > me if I misunderstood something yesterday):
>> >        Reconnections should be implicit and the data channel should
>> > be perceived by the application layer as connected all the time.
>> >        When the application tries to write in a closed data channel, HDP
>> > will perform the data channel reconnection and if it fails, then the
>> > channel will be present as closed.
>> >        The implementation for this this behaviour will use pipes. Each
>> > data channel will use 2 pipes to do fd-passing to the application. The
>> > upper layer will write in this pipes and HDP will redirect it through
>> > the l2cap socket, in this operation, HDP can reconnect if th l2cap
>> > socket is closed.
>> >
>> > - Sessions issues: We still think that session are necessary because they
>> > are mentioned in the standard and in the whitepaper and we think that
>> > bluez should follow the standards in order to pass PTS for allow
>> > Bluetooth SIG certifications. Any comment in this respect are welcome to
>> > improve the API usability and conformity with Bluez APIs.
>> >
>> > - Paths issues: It will be great to find names and paths that are good
>> > for everybody, comments and suggestion on this respect are also welcome.
>> >
>> > I hope we can fix this API asap. All comments or ideas are welcome.
>>
>> It would be much better if you could bring this API near to other
>> BlueZ APIs. All comments I'll do right now is regarding this matter.
>>
>> > Regards.
>> >
>> > --------------------------------------------------
>> >
>> > BlueZ D-Bus HDP API description
>> > ***********************************
>> >
>> >        Santiago Carot-Nemesio <sancane@gmail.com>
>> >        José Antonio Santos-Cadenas <santoscadenas@gmail.com>
>> >        Elvis Pfützenreuter <epx@signove.com>
>> >
>> > Health Device Profile hierarchy
>> > ===============================
>> >
>> > Service         org.bluez
>> > Interface       org.bluez.Hdp
>>
>> If you look on other profile interfaces you'll see that we never use
>> the profile acronym for interface names, but the content type (and
>> role, where applicable). So this will be better as org.bluez.Health.
>>
>> Moreover, I see you're using the same interface name to describe two
>> different interfaces. This is just wrong. An interface should be a
>> description of an unique group of methods and signals signatures. You
>> can refer to [0] for a description on interfaces.
>>
>> [0] http://dbus.freedesktop.org/doc/dbus-tutorial.html#interfaces
>
> Ok, regarding the above comments, this interface changes to:
>
> Interface       org.bluez.HealthAdapter
>
>>
>> > Object path     [variable prefix]/{hci0,hci1,...}
>> >
>> > Methods         object CreateSession(object path, dict config)
>> >
>> >                        Returns the object path for the new HDP session.
>> >                        The path parameter is the path of the remote
>> > object with the callbacks to notify events (see
>> >                        org.bluez.HdpAgent at the end of this document)
>> >                        This petition starts an mcap session and also
>> > register in the SDP is needed
>> >                        Dict is defined as bellow:
>> >                        { "data_spec" : The data_spec is the data exchange
>> >                                        specification (see section 5.2.10
>> > of the specification document) possible values:
>> >                                                0x00 = reserved,
>> >                                                0x01 [IEEE 11073-20601],
>> >                                                0x02..0xff reserved,
>> >                                        (optional)
>> >                          "end_points" : [{ (optional)
>> >                                "mdepid" : uint8, (optional)
>> >                                "role" : ("source" or "sink"), (mandatory)
>> >                                "specs" :[{ (mandatory)
>> >                                        "data_type" : uint16, (mandatory)
>> >                                        "description" : string, (optional)
>> >                                }]
>> >                          }]
>> >                        }
>>
>> Couldn't this be moved as properties on the session object? So after
>> creating a session you just go on it's object path and set the desired
>> properties with SetProperty(). This will be much more aligned with
>> other BlueZ APIs.
>
> We thought about doing something similar to this you propose, but we see some
> promen, that makes the API more difficult to use:
>        - Session will need another method in order to start it once you have
> configured it. With this method, configuration and session start are done in
> just one method call. This implies that the other methods (connect and
> disconnect to a remote session) could not be called until the session is
> started, this quite strange.
>        - As you can see, the dictionary has only two members, "data_spec" and
> "end_points". So, you will have to pass a dictionary to set end_points too.
>

By "starting the session" I guess you meant publishing the SDP record,
right? Couldn't this be done using the AddRecord() method on the
org.bluez.Service interface? Then you could have a property on the
session object path that says if it is published or not (calling the
other methods could also trigger a "session start" or return with an
error). Then this method would be used only for Agent registration,
maybe then making RegisterAgent() a more suitable name.

>>
>> >                        if "data_spec" is not set, no SDP record will be
>> >                        registered, so all the other data in the
>> > dictionary will be ignored
>> >
>> >                        Session will be closed by the call or implicitly
>> > when the programs leaves the bus.
>> >
>> >                        Possible errors: org.bluez.Error.InvalidArguments
>> >
>> >                void CloseSession(object path)
>> >
>> >                        Closes the HDP session identified by the object
>> > path. Also session will be closed if the process that started it is
>> > removed from the D-Bus.
>>
>> s/D-Bus/bus. Also, would be good to keep the description consistent
>> between methods. Previous description says "the programs leaves" and
>> here "process is removed". IMHO "the process leaves the bus" will be
>> the more accurate.
>
> Ok, I'll try to be more consistent in the next revision, using the text that
> you suggested.
>
>>
>> >                        Possible errors: org.bluez.Error.InvalidArguments
>> >                                         org.bluez.Error.NotFound
>> >
>> > -------------------------------------------------------------------------
>> > -------
>> >
>> > Service         org.bluez
>> > Interface       org.bluez.Hdp
>
> Chage this to:
>
> Interface org.bluez.HdpDevice
>
>> > Object path     [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
>> >
>> > Methods array GetSessions()
>>
>> It would be better if this method return the session object path, then
>> you can get this information with GetProperties() on the session
>> object.
>
> Do you mean creating a new object that holds the remote sessions?
> Right now the  org.bluez.HdpSession Objects holds only local sessions. Remote
> session will be a bit different. See below.
>

I've actually meant to return a list of object paths for each
RemoteSession object on the device. But thinking more on this,
wouldn't this fit better on the Service interface, since it's a SDP
related function? sdptool has a way to query records for a specific
service on a device, but it does so accessing libbluetooth sdp.h
directly. We would need to add a more generic method to query records
of a device filtering by service, but then we could use this instead
of defining a new interface only for that. Johan, Luiz, what do you
think?

>>
>> >                        Gets the information of the remote sessions
>> > present in this device and published on its SDP record. The returned
>> > data follows this format.
>> >
>> >                        [{"session_id": "a session identification as
>> > string", "data_spec" : session data spec,
>> >                         "end_points":
>> >                                 ["mdepid": uint8,
>> >                                  "role"  : "source" or "sink" ,
>> >                                  "specs" : [{
>> >                                          "dtype"       : uint16,
>> >                                          "description" : string,
>> > (optional) }]
>> >                                 ]
>> >                        }]
>> >
>> > -------------------------------------------------------------------------
>> > -------
>> >
>> > Service         org.bluez
>> > Interface       org.bluez.HdpSession
>> > Object path     [variable prefix]/{hci0,hci1,...}/{hdp0,hdp1,...}
>>
>> From the previous interface (the one that defines the GetSessions()
>> method) it seems that sessions are tied to a specific device. If so,
>> the session objects should be under the device object, not under the
>> adapter object.
>
> See below the Session explanation.

Right. But then, what if you move these two methods to the Remote
Session object (obviously adapting the parameters to address the local
session instead of the remote one)? Wouldn't they provide the same
function? Then we won't need separate interfaces here.

>>
>> >                object Connect(remote_session_id)
>> >
>> >                        Connects with the remote session and returns its
>> > object path.
>> >
>> >                        Possible errors: org.bluez.Error.InvalidArguments
>> >                                         org.bluez.Error.HdpError
>> >
>> >                void Disconnect(object device, boolean delete)
>> >
>> >                        Disconnect from the remote device. If delete is
>> > true, any status will also be deleted. Otherwise, the status will be
>> > kept for allowing future reconnections.
>> >
>> >                        Possible errors: org.bluez.Error.InvalidArguments
>> >                                         org.bluez.Error.NotFound
>> >                                         org.bluez.Error.HdpError
>> >
>> > -------------------------------------------------------------------------
>> > -------
>> >
>> > Service         org.bluez
>> > Interface       org.bluez.HdpRemoteSession
>> > Object path     [variable
>> > prefix]/{hci0,hci1,...}/{hdp0,hdp1,...}/rem_session_id
>>
>> Could you please elaborate more on what does HdpSession and
>> HdpRemoteSessions tries to abstract? It still not clear to me and
>> depending on this we may find a better name for it.
>
> I think that the most estrange part of the protocol is this and I failed with
> my explanations.
>
> HDP uses MCAP that uses what we called "sessions" in the MCAP standard the
> called them instances (refer to section 2.1.7 of the MCAP specification for
> more details).
>
> A MCAP session/instance is just a tuple of two PSM waiting for connections one
> for control channels (mcl) and the other for data channels (mdl) this session
> can connect to a remote MCAP session or be connected by them, this connections
> is called mcap control link (mcl). Just one connection between two instances
> can be established.
>
> As HDP uses MCAP, HDP inherits this "session" behaviour. Each HDP session
> starts a MCAP session and also could create a SDP record (mandatory for sinks)
> to anounce its attributes (mdeps, psms) to other devices.
>
> The thing that we called HdpSession is a MCAP session (PSM's waiting for
> connections) created locally and, optionally a SDP record. HdpSession can
> connect to other devices' sessions.
>
> The thing that we called HdpRemoteSession represents a connection between a
> local session and a session in other device, in other words is a extension of
> a MCAP mcl.
>
>>
>> >                boolean Echo(array{byte})
>> >
>> >                        Sends an echo petition to the remote session.
>> > Return True if response matches with the buffer sent. If some error is
>> > detected False value is returned and the associated MCL is closed.
>> >
>> >                uint16 OpenDataChannel(byte mdepid, byte config)
>> >
>> >                        Creates a new data channel with the indicated
>> > config to the remote MCAP Data End Point (MDEP). The configuration
>> > should indicate the channel quality of service.
>> >                        Returns the data channel id.
>> >
>> >                        Possible errors: org.bluez.Error.InvalidArguments
>> >                                         org.bluez.Error.HdpError
>> >
>> >                array GetDcFd(uint16 mdlid)
>> >
>> >                        Gets a file descriptor where data can be read or
>> >                        written for receive or sent by the data channel.
>> >                        Returns an array of file descriptors one for write
>> >                        and other for read.
>> >
>> >                        Possible errors: org.bluez.Error.InvalidArguments
>> >                                         org.bluez.Error.NotFound
>> >                                         org.bluez.Error.HdpError
>> >
>> >                void DeleteDataChannel(uint16 mdlid)
>> >
>> >                        Deletes a data channel so it will not be available
>> > for use.
>> >
>> >                        Possible errors: org.bluez.Error.InvalidArguments
>> >                                         org.bluez.Error.NotFound
>> >                                         org.bluez.Error.HdpError
>> >
>> >                void DeleteAllDataChannels()
>> >
>> >                        Deletes all data channels so it will not be
>> > available for use. Typically this function is called when the connection
>> > with the remote device will be closed permanently
>> >
>> >                        Possible errors: org.bluez.Error.HdpError
>> >
>> >                dict GetDataChannelStatus()
>> >
>> >                        Return a dictionary with all the data channels
>> > that can be used to send data right now. The dictionary is formed like
>> > follows:
>> >                        {
>> >                                "reliable": [id1, ..., idz],
>> >                                "best_effort" : [idx, ..., idy]
>> >                        }
>> >
>> >                        The fist reliable data channel will always be the
>> > first data channel in reliable array.
>> >
>> > HDPAgent hierarchy
>> > ==================
>> >
>> > (this object is implemented by the HDP client an receives notifications)
>> >
>> > Service         unique name
>> > Interface       org.bluez.HdpAgent
>> > Object path     freely definable
>> >
>> >                void DeviceConnected(object path)
>> >
>> >                        This method is called whenever a new device
>> > connection has been established over the control channel of the current
>> > HDP session. The object path contains the object path of the remote
>> > device.
>> >
>> >                void DeviceDisconnected(object path)
>> >
>> >                        This method is called when a remote device is
>> >                        disconnected definitively. Any future
>> > reconnections will fail. Also all data channels associated to this
>> > device will be closed.
>> >
>> >                void CreatedDataChannel(object path, uint16 mdlid)
>> >
>> >                        This method is called when a new data channel is
>> > created The path contains the object path of the device whith the new
>> > connection is created and the mdlid the data channel identificator.
>> >
>> >                void DeletedDataChannel(object path, uint16 mdlid)
>> >
>> >                        This method is called when a data channel is
>> > closed. After this call the data channel will not be valid and can be
>> > reused for future created data channels.
>
>



--
João Paulo Rechi Vita
http://jprvita.wordpress.com/

^ permalink raw reply

* [PATCH 1/1] Fixes sdp_get_supp_feat function
From: Elvis Pfützenreuter @ 2010-05-14  3:13 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: epx

In case of string data items, value is a pointer by itself.
---
 lib/sdp.c |    7 ++++++-
 1 files changed, 6 insertions(+), 1 deletions(-)

diff --git a/lib/sdp.c b/lib/sdp.c
index fb8ccdc..c75a000 100644
--- a/lib/sdp.c
+++ b/lib/sdp.c
@@ -4801,10 +4801,15 @@ int sdp_get_supp_feat(const sdp_record_t *rec, sdp_list_t **seqp)
 		subseq = NULL;
 		for (dd = d->val.dataseq; dd; dd = dd->next) {
 			sdp_data_t *data;
+			void *val;
 			if (dd->dtd != SDP_UINT8 && dd->dtd != SDP_UINT16 &&
 						dd->dtd != SDP_TEXT_STR8)
 				goto fail;
-			data = sdp_data_alloc(dd->dtd, &dd->val);
+			if (dd->dtd == SDP_TEXT_STR8)
+				val = dd->val.str;
+			else
+				val = &dd->val;
+			data = sdp_data_alloc(dd->dtd, val);
 			if (data)
 				subseq = sdp_list_append(subseq, data);
 		}
-- 
1.7.0.4


^ permalink raw reply related

* wiki.bluez.org down ?
From: Pavan Savoy @ 2010-05-14  6:42 UTC (permalink / raw)
  To: linux-bluetooth

Hi,

I am not sure the webmaster/maintainer of the cool wiki is on this list - but worth a try why does that site seem down for a few days now ?
It was really a very good wiki set of pages, even if it did not keep itself updated !!

regards,
Pavan



^ permalink raw reply

* Re: [PATCH 1/1] Fixes sdp_get_supp_feat function
From: José Antonio Santos Cadenas @ 2010-05-14  7:02 UTC (permalink / raw)
  To: Elvis Pfützenreuter; +Cc: linux-bluetooth
In-Reply-To: <1273806810-29602-1-git-send-email-epx@signove.com>

Hi Elvis,

El Friday 14 May 2010 05:13:30 Elvis Pfützenreuter escribió:
> In case of string data items, value is a pointer by itself.
> ---
>  lib/sdp.c |    7 ++++++-
>  1 files changed, 6 insertions(+), 1 deletions(-)
> 
> diff --git a/lib/sdp.c b/lib/sdp.c
> index fb8ccdc..c75a000 100644
> --- a/lib/sdp.c
> +++ b/lib/sdp.c
> @@ -4801,10 +4801,15 @@ int sdp_get_supp_feat(const sdp_record_t *rec,
> sdp_list_t **seqp) subseq = NULL;
>  		for (dd = d->val.dataseq; dd; dd = dd->next) {
>  			sdp_data_t *data;
> +			void *val;
>  			if (dd->dtd != SDP_UINT8 && dd->dtd != SDP_UINT16 &&
>  						dd->dtd != SDP_TEXT_STR8)
>  				goto fail;
> -			data = sdp_data_alloc(dd->dtd, &dd->val);
> +			if (dd->dtd == SDP_TEXT_STR8)
> +				val = dd->val.str;
> +			else
> +				val = &dd->val;
> +			data = sdp_data_alloc(dd->dtd, val);

No only strings are pointers, if you see this patch:
http://git.kernel.org/?p=bluetooth/bluez.git;a=commit;h=1d1154156df28660e41031df5c3f1ffe91c01aae

that I sent few days ago for fixing the set function, also sequences are 
pointers and should be treated in a different way. Also strings can be formed 
by other types not only SDP_TEXT_STR8. I think a switch will fix this better.

>  			if (data)
>  				subseq = sdp_list_append(subseq, data);
>  		}

Regards.

^ permalink raw reply

* Re: HDP proposed API (ver 0.3)
From: José Antonio Santos Cadenas @ 2010-05-14  8:00 UTC (permalink / raw)
  To: João Paulo Rechi Vita
  Cc: linux-bluetooth, Elvis Pfützenreuter, Santiago Carot,
	Raul Herbster
In-Reply-To: <AANLkTimjua-P8DgvGidKaIgRvCScuP4mGTi4Wm82-O-N@mail.gmail.com>

Hi João,

El Friday 14 May 2010 00:35:23 João Paulo Rechi Vita escribió:
> Hello José!
> 
> Thank you very much for the explanation on the sessions abstraction.
> Now I understood what you're trying to expose and I think the whole
> confusion upraised from the nomenclature 'session', which is usually
> used for defining a well-known slice of time (with known beginning and
> end) in which some events are comprised. Wouldn't it be better to
> change this to something like "Instance", to keep consistency with
> MCAP spec?

We are doing the changes in MCAP and this API will be also changed. I'm happy 
we are finally fixing a good API.

> 
> For the sake of sanity, I'll keep using the Session nomenclature on
> comments bellow, we can discuss interface names on a further review
> round.

Me too until it is changed :)

> 
> On Thu, May 13, 2010 at 05:02, José Antonio Santos Cadenas
> 
> <jcaden@libresoft.es> wrote:
> > Hi João,
> > 
> > Thank you very much for you comments :)
> > 
> > El Thursday 13 May 2010 00:03:51 João Paulo Rechi Vita escribió:
> >> Hello Jose!
> >> 
> >> On Wed, May 12, 2010 at 06:26, José Antonio Santos Cadenas
> >> 
> >> <jcaden@libresoft.es> wrote:
> >> > This api is a clean up of the previous one the changes.
> >> > 
> >> > We've added a new object that uses device path to get the sessions
> >> > allocated on this device (as somebody recommended in other thread,
> >> > I think Luiz, Elvis or both, but I can't find the exact email). The
> >> > discovery of new remote session should be done using device drivers,
> >> > which is compliant with the BlueZ style.
> >> > 
> >> > Discussions still in progress:
> >> > 
> >> > - Fd-passing issue: As Elvis, Santiago and I discussed yesterday on
> >> > IRC we think that the best propose is as follows (please Elvis correct
> >> > me if I misunderstood something yesterday):
> >> >        Reconnections should be implicit and the data channel should
> >> > be perceived by the application layer as connected all the time.
> >> >        When the application tries to write in a closed data channel,
> >> > HDP will perform the data channel reconnection and if it fails, then
> >> > the channel will be present as closed.
> >> >        The implementation for this this behaviour will use pipes. Each
> >> > data channel will use 2 pipes to do fd-passing to the application. The
> >> > upper layer will write in this pipes and HDP will redirect it through
> >> > the l2cap socket, in this operation, HDP can reconnect if th l2cap
> >> > socket is closed.
> >> > 
> >> > - Sessions issues: We still think that session are necessary because
> >> > they are mentioned in the standard and in the whitepaper and we think
> >> > that bluez should follow the standards in order to pass PTS for allow
> >> > Bluetooth SIG certifications. Any comment in this respect are welcome
> >> > to improve the API usability and conformity with Bluez APIs.
> >> > 
> >> > - Paths issues: It will be great to find names and paths that are good
> >> > for everybody, comments and suggestion on this respect are also
> >> > welcome.
> >> > 
> >> > I hope we can fix this API asap. All comments or ideas are welcome.
> >> 
> >> It would be much better if you could bring this API near to other
> >> BlueZ APIs. All comments I'll do right now is regarding this matter.
> >> 
> >> > Regards.
> >> > 
> >> > --------------------------------------------------
> >> > 
> >> > BlueZ D-Bus HDP API description
> >> > ***********************************
> >> > 
> >> >        Santiago Carot-Nemesio <sancane@gmail.com>
> >> >        José Antonio Santos-Cadenas <santoscadenas@gmail.com>
> >> >        Elvis Pfützenreuter <epx@signove.com>
> >> > 
> >> > Health Device Profile hierarchy
> >> > ===============================
> >> > 
> >> > Service         org.bluez
> >> > Interface       org.bluez.Hdp
> >> 
> >> If you look on other profile interfaces you'll see that we never use
> >> the profile acronym for interface names, but the content type (and
> >> role, where applicable). So this will be better as org.bluez.Health.
> >> 
> >> Moreover, I see you're using the same interface name to describe two
> >> different interfaces. This is just wrong. An interface should be a
> >> description of an unique group of methods and signals signatures. You
> >> can refer to [0] for a description on interfaces.
> >> 
> >> [0] http://dbus.freedesktop.org/doc/dbus-tutorial.html#interfaces
> > 
> > Ok, regarding the above comments, this interface changes to:
> > 
> > Interface       org.bluez.HealthAdapter
> > 
> >> > Object path     [variable prefix]/{hci0,hci1,...}
> >> > 
> >> > Methods         object CreateSession(object path, dict config)
> >> > 
> >> >                        Returns the object path for the new HDP
> >> > session. The path parameter is the path of the remote object with the
> >> > callbacks to notify events (see
> >> >                        org.bluez.HdpAgent at the end of this document)
> >> >                        This petition starts an mcap session and also
> >> > register in the SDP is needed
> >> >                        Dict is defined as bellow:
> >> >                        { "data_spec" : The data_spec is the data
> >> > exchange specification (see section 5.2.10 of the specification
> >> > document) possible values:
> >> >                                                0x00 = reserved,
> >> >                                                0x01 [IEEE
> >> > 11073-20601], 0x02..0xff reserved, (optional)
> >> >                          "end_points" : [{ (optional)
> >> >                                "mdepid" : uint8, (optional)
> >> >                                "role" : ("source" or "sink"),
> >> > (mandatory) "specs" :[{ (mandatory)
> >> >                                        "data_type" : uint16,
> >> > (mandatory) "description" : string, (optional) }]
> >> >                          }]
> >> >                        }
> >> 
> >> Couldn't this be moved as properties on the session object? So after
> >> creating a session you just go on it's object path and set the desired
> >> properties with SetProperty(). This will be much more aligned with
> >> other BlueZ APIs.
> > 
> > We thought about doing something similar to this you propose, but we see
> > some promen, that makes the API more difficult to use:
> >        - Session will need another method in order to start it once you
> > have configured it. With this method, configuration and session start
> > are done in just one method call. This implies that the other methods
> > (connect and disconnect to a remote session) could not be called until
> > the session is started, this quite strange.
> >        - As you can see, the dictionary has only two members, "data_spec"
> > and "end_points". So, you will have to pass a dictionary to set
> > end_points too.
> 
> By "starting the session" I guess you meant publishing the SDP record,
> right? 

Start a "session"  implies start a MCAP session, optionally you can register a 
SDP record (mandatory if you are sink).

> Couldn't this be done using the AddRecord() method on the
> org.bluez.Service interface? 

I think this is not a good option:
	- Doing this you are rely on the client a possible mandatory (in case of 
sinks) protocol requirement.
	- Giving this data to HDP is not only for registering a SDP record but 
also for doing checks when a connection is received, so this data will be 
finally passed to HDP.
	- The HDP client doesn't know all the data that should be published in 
the SDP record, like PSM's where MCAP is waiting for connections or MCAP 
supported features (note that MCAP is not exported by D-BUS).
	-  The SDP record shouldn't be created until the MCAP "session" is 
started and waiting for connections.

> Then you could have a property on the
> session object path that says if it is published or not (calling the
> other methods could also trigger a "session start" or return with an
> error). Then this method would be used only for Agent registration,
> maybe then making RegisterAgent() a more suitable name.

Sorry, but I don't understand this part.

> 
> >> >                        if "data_spec" is not set, no SDP record will
> >> > be registered, so all the other data in the dictionary will be
> >> > ignored
> >> > 
> >> >                        Session will be closed by the call or
> >> > implicitly when the programs leaves the bus.
> >> > 
> >> >                        Possible errors:
> >> > org.bluez.Error.InvalidArguments
> >> > 
> >> >                void CloseSession(object path)
> >> > 
> >> >                        Closes the HDP session identified by the object
> >> > path. Also session will be closed if the process that started it is
> >> > removed from the D-Bus.
> >> 
> >> s/D-Bus/bus. Also, would be good to keep the description consistent
> >> between methods. Previous description says "the programs leaves" and
> >> here "process is removed". IMHO "the process leaves the bus" will be
> >> the more accurate.
> > 
> > Ok, I'll try to be more consistent in the next revision, using the text
> > that you suggested.
> > 
> >> >                        Possible errors:
> >> > org.bluez.Error.InvalidArguments org.bluez.Error.NotFound
> >> > 
> >> > ----------------------------------------------------------------------
> >> > --- -------
> >> > 
> >> > Service         org.bluez
> >> > Interface       org.bluez.Hdp
> > 
> > Chage this to:
> > 
> > Interface org.bluez.HdpDevice
> > 
> >> > Object path     [variable
> >> > prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
> >> > 
> >> > Methods array GetSessions()
> >> 
> >> It would be better if this method return the session object path, then
> >> you can get this information with GetProperties() on the session
> >> object.
> > 
> > Do you mean creating a new object that holds the remote sessions?
> > Right now the  org.bluez.HdpSession Objects holds only local sessions.
> > Remote session will be a bit different. See below.
> 
> I've actually meant to return a list of object paths for each
> RemoteSession object on the device. But thinking more on this,
> wouldn't this fit better on the Service interface, since it's a SDP
> related function? sdptool has a way to query records for a specific
> service on a device, but it does so accessing libbluetooth sdp.h
> directly. We would need to add a more generic method to query records
> of a device filtering by service, but then we could use this instead
> of defining a new interface only for that. Johan, Luiz, what do you
> think?

For me it's OK but I still see two advantages doing this as I propose:
	- The HDP client should know how the SDP record is formed and also filter 
the useful information for them.
	- HDP needs the remote record too the PSM are variant and the standard 
explicitly says in section 3.3 (and again in section 3.4 for data channels): 
		- Control channels PSM's shall be dynamic PSM's
		- In order to avoid assumptions regarding the value of Control 
Channel PSMs, PSM values shall be retrieved from the SDP record.
	if you rely on HDP for getting the remote SDP record, it can cache it and 
not increment the delay when a connection is requested.

> 
> >> >                        Gets the information of the remote sessions
> >> > present in this device and published on its SDP record. The returned
> >> > data follows this format.
> >> > 
> >> >                        [{"session_id": "a session identification as
> >> > string", "data_spec" : session data spec,
> >> >                         "end_points":
> >> >                                 ["mdepid": uint8,
> >> >                                  "role"  : "source" or "sink" ,
> >> >                                  "specs" : [{
> >> >                                          "dtype"       : uint16,
> >> >                                          "description" : string,
> >> > (optional) }]
> >> >                                 ]
> >> >                        }]
> >> > 
> >> > ----------------------------------------------------------------------
> >> > --- -------
> >> > 
> >> > Service         org.bluez
> >> > Interface       org.bluez.HdpSession
> >> > Object path     [variable prefix]/{hci0,hci1,...}/{hdp0,hdp1,...}
> >> 
> >> From the previous interface (the one that defines the GetSessions()
> >> method) it seems that sessions are tied to a specific device. If so,
> >> the session objects should be under the device object, not under the
> >> adapter object.
> > 
> > See below the Session explanation.
> 
> Right. But then, what if you move these two methods to the Remote
> Session object (obviously adapting the parameters to address the local
> session instead of the remote one)? Wouldn't they provide the same
> function? Then we won't need separate interfaces here.

"RemoteSession" (very bad name) refers to a connection between a remote and a 
local "session", so the functionality is different. "RemoteSession" manages an 
already opened connection and and "HdpDevice" just represents a remote device 
(not connected) and provides a way to know the "sessions" on it.

> 
> >> >                object Connect(remote_session_id)
> >> > 
> >> >                        Connects with the remote session and returns
> >> > its object path.
> >> > 
> >> >                        Possible errors:
> >> > org.bluez.Error.InvalidArguments org.bluez.Error.HdpError
> >> > 
> >> >                void Disconnect(object device, boolean delete)
> >> > 
> >> >                        Disconnect from the remote device. If delete is
> >> > true, any status will also be deleted. Otherwise, the status will be
> >> > kept for allowing future reconnections.
> >> > 
> >> >                        Possible errors:
> >> > org.bluez.Error.InvalidArguments org.bluez.Error.NotFound
> >> > org.bluez.Error.HdpError
> >> > 
> >> > ----------------------------------------------------------------------
> >> > --- -------
> >> > 
> >> > Service         org.bluez
> >> > Interface       org.bluez.HdpRemoteSession
> >> > Object path     [variable
> >> > prefix]/{hci0,hci1,...}/{hdp0,hdp1,...}/rem_session_id
> >> 
> >> Could you please elaborate more on what does HdpSession and
> >> HdpRemoteSessions tries to abstract? It still not clear to me and
> >> depending on this we may find a better name for it.
> > 
> > I think that the most estrange part of the protocol is this and I failed
> > with my explanations.
> > 
> > HDP uses MCAP that uses what we called "sessions" in the MCAP standard
> > the called them instances (refer to section 2.1.7 of the MCAP
> > specification for more details).
> > 
> > A MCAP session/instance is just a tuple of two PSM waiting for
> > connections one for control channels (mcl) and the other for data
> > channels (mdl) this session can connect to a remote MCAP session or be
> > connected by them, this connections is called mcap control link (mcl).
> > Just one connection between two instances can be established.
> > 
> > As HDP uses MCAP, HDP inherits this "session" behaviour. Each HDP session
> > starts a MCAP session and also could create a SDP record (mandatory for
> > sinks) to anounce its attributes (mdeps, psms) to other devices.
> > 
> > The thing that we called HdpSession is a MCAP session (PSM's waiting for
> > connections) created locally and, optionally a SDP record. HdpSession can
> > connect to other devices' sessions.
> > 
> > The thing that we called HdpRemoteSession represents a connection between
> > a local session and a session in other device, in other words is a
> > extension of a MCAP mcl.
> > 
> >> >                boolean Echo(array{byte})
> >> > 
> >> >                        Sends an echo petition to the remote session.
> >> > Return True if response matches with the buffer sent. If some error is
> >> > detected False value is returned and the associated MCL is closed.
> >> > 
> >> >                uint16 OpenDataChannel(byte mdepid, byte config)
> >> > 
> >> >                        Creates a new data channel with the indicated
> >> > config to the remote MCAP Data End Point (MDEP). The configuration
> >> > should indicate the channel quality of service.
> >> >                        Returns the data channel id.
> >> > 
> >> >                        Possible errors:
> >> > org.bluez.Error.InvalidArguments org.bluez.Error.HdpError
> >> > 
> >> >                array GetDcFd(uint16 mdlid)
> >> > 
> >> >                        Gets a file descriptor where data can be read
> >> > or written for receive or sent by the data channel. Returns an array
> >> > of file descriptors one for write and other for read.
> >> > 
> >> >                        Possible errors:
> >> > org.bluez.Error.InvalidArguments org.bluez.Error.NotFound
> >> > org.bluez.Error.HdpError
> >> > 
> >> >                void DeleteDataChannel(uint16 mdlid)
> >> > 
> >> >                        Deletes a data channel so it will not be
> >> > available for use.
> >> > 
> >> >                        Possible errors:
> >> > org.bluez.Error.InvalidArguments org.bluez.Error.NotFound
> >> > org.bluez.Error.HdpError
> >> > 
> >> >                void DeleteAllDataChannels()
> >> > 
> >> >                        Deletes all data channels so it will not be
> >> > available for use. Typically this function is called when the
> >> > connection with the remote device will be closed permanently
> >> > 
> >> >                        Possible errors: org.bluez.Error.HdpError
> >> > 
> >> >                dict GetDataChannelStatus()
> >> > 
> >> >                        Return a dictionary with all the data channels
> >> > that can be used to send data right now. The dictionary is formed like
> >> > follows:
> >> >                        {
> >> >                                "reliable": [id1, ..., idz],
> >> >                                "best_effort" : [idx, ..., idy]
> >> >                        }
> >> > 
> >> >                        The fist reliable data channel will always be
> >> > the first data channel in reliable array.
> >> > 
> >> > HDPAgent hierarchy
> >> > ==================
> >> > 
> >> > (this object is implemented by the HDP client an receives
> >> > notifications)
> >> > 
> >> > Service         unique name
> >> > Interface       org.bluez.HdpAgent
> >> > Object path     freely definable
> >> > 
> >> >                void DeviceConnected(object path)
> >> > 
> >> >                        This method is called whenever a new device
> >> > connection has been established over the control channel of the
> >> > current HDP session. The object path contains the object path of the
> >> > remote device.
> >> > 
> >> >                void DeviceDisconnected(object path)
> >> > 
> >> >                        This method is called when a remote device is
> >> >                        disconnected definitively. Any future
> >> > reconnections will fail. Also all data channels associated to this
> >> > device will be closed.
> >> > 
> >> >                void CreatedDataChannel(object path, uint16 mdlid)
> >> > 
> >> >                        This method is called when a new data channel
> >> > is created The path contains the object path of the device whith the
> >> > new connection is created and the mdlid the data channel
> >> > identificator.
> >> > 
> >> >                void DeletedDataChannel(object path, uint16 mdlid)
> >> > 
> >> >                        This method is called when a data channel is
> >> > closed. After this call the data channel will not be valid and can be
> >> > reused for future created data channels.


^ permalink raw reply

* Re: HDP proposed API (ver 0.3)
From: José Antonio Santos Cadenas @ 2010-05-14  8:01 UTC (permalink / raw)
  To: Daniel Abraham
  Cc: linux-bluetooth, Elvis Pfützenreuter, Santiago Carot,
	Raul Herbster
In-Reply-To: <201005121325.26454.jcaden@libresoft.es>

Hi all,

El Wednesday 12 May 2010 13:25:26 José Antonio Santos Cadenas escribió:
> > > HDPAgent hierarchy
> > > ==================
> > >
> > > 
> > >
> > > (this object is implemented by the HDP client an receives
> > > notifications)
> > >
> > > 
> > >
> > > Service         unique name
> > > Interface       org.bluez.HdpAgent
> > > Object path     freely definable
> > >
> > > 
> > >                void DeviceConnected(object path)
> > > 
> > >                        This method is called whenever a new device
> > >
> > > connection has been established over the control channel of the current
> > > HDP session. The object path contains the object path of the remote
> > > device.
> > >
> > > 
> > >                void DeviceDisconnected(object path)
> > > 
> > >                        This method is called when a remote device is
> > >                        disconnected definitively. Any future
> > >
> > > reconnections will fail. Also all data channels associated to this
> > > device will be closed.
> > >
> > > 
> > >                void CreatedDataChannel(object path, uint16 mdlid)
> > > 
> > >                        This method is called when a new data channel is
> > >
> > > created The path contains the object path of the device whith the new
> > > connection is created and the mdlid the data channel identificator.
> > >
> > > 
> > >                void DeletedDataChannel(object path, uint16 mdlid)
> > > 
> > >                        This method is called when a data channel is
> > >
> > > closed. After this call the data channel will not be valid and can be
> > > reused for future created data channels.
> >
> > 
> >
> > Question from a user's perspective: why define an agent? Why not
> > define the above as signal callbacks in the relevant object? (same as
> > most APIs in "bluez/docs").
> 
> Because the this notifications are only relevant for the process that
> created  the session and this process should be the unique that receives
> this events. If you define signals, everybody in the bus can be subscribed
> to them, this is a problem in two ways:
>         - Noise in the bus
>         - "Privacy" issue because just the owner of the session should be
> notified  of the session events.
> 
> > 
> >
> > The only places I saw where agents are used are: BlueZ pairing (remote
> > device object doesn't necessarily exist yet, so no way to register for
> > its events, so an agent is required), and obexd (callback methods for
> > authroization of transactions return a significant value, i.e. not a
> > simple signal, so an agent is also required).
> >
> > 
> >
> > But none of these conditions apply in the HDP agent above. So is there
> > another reason?
> 
> I explained above.
> 
> If we are wrong and signals can be cached only by one process it is OK for
> us  to change this.
> 
> > 
> >
> > Also, why not add properties for
> > connected/disconnected/opened/closed/etc. states? (And then
> > "GetProperties()" method, and "PropertyChanged(name, value)" signal).
> > For example, see "bluez/docs/network-api.txt"...
> 
> Because this notifications concern to objects that are being created and 
> destroyed (in the case of devices) and created or closed data channels, so
> new  data channels ids are created or destroyed when this method are
> called. I can't see how properties can help here. The channel may exist or
> not I think that properties are not a good option in this case.
> 
> Regards.

Any comments about this issue. It will be great to receive a little bit more 
of feedback in order to decide one of this two options.


^ permalink raw reply

* HDP proposed API (ver 0.4)
From: José Antonio Santos Cadenas @ 2010-05-14 10:03 UTC (permalink / raw)
  To: linux-bluetooth

Hi all,

I need a new version just for having the correct names an also little corrections.

I changed the name of a connection between two instances to HealthLink. Because 
is an extension of a MCL (MCAP control link) so it we think that it's a better name.

Regards
----------------------------

BlueZ D-Bus Health API description
***********************************

	Santiago Carot-Nemesio <sancane@gmail.com>
	José Antonio Santos-Cadenas <santoscadenas@gmail.com>
	Elvis Pfützenreuter <epx@signove.com>

Health Device Profile hierarchy
===============================

Service		org.bluez
Interface	org.bluez.HealthAdapter
Object path	[variable prefix]/{hci0,hci1,...}

Methods		object CreateInstance(object path, dict config)

			Returns the object path for the new HDP instance.
			The path parameter is the path of the remote object
			with the callbacks to notify events (see
			org.bluez.HealthAgent at the end of this document)
			This petition starts an mcap instance and also register
			in the SDP is needed
			Dict is defined as bellow:
			{ "data_spec" : The data_spec is the data exchange
					specification (see section 5.2.10 of
					the specification document)
					possible values:
						0x00 = reserved,
						0x01 [IEEE 11073-20601],
						0x02..0xff reserved,
					(optional)
			  "end_points" : [{ (optional)
				"mdepid" : uint8, (optional)
				"role" : ("source" or "sink"), (mandatory)
				"specs" :[{ (mandatory)
					"data_type" : uint16, (mandatory)
					"description" : string, (optional)
				}]
			  }]
			}

			if "data_spec" is not set, no SDP record will be
			registered, so all the other data in the dictionary
			will be ignored

			Instance will be closed by the call or implicitly when
			the programs leaves the bus.

			Possible errors: org.bluez.Error.InvalidArguments

		void CloseInstance(object path)

			Closes the HDP instance identified by the object path.
			Also instance will be closed if the process that started
			leaves the bus.

			Possible errors: org.bluez.Error.InvalidArguments
					org.bluez.Error.NotFound

--------------------------------------------------------------------------------

Service		org.bluez
Interface	org.bluez.HealthDevice
Object path	[variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX

Methods		array GetHealthInstances()

			Gets the information of the remote instances present
			in this device and published on its SDP record. The
			returned data follows this format.

			[{"id": "an instance identification as string",
			 "data_spec" : data spec,
			 "end_points":
				["mdepid": uint8,
				 "role"  : "source" or "sink" ,
				 "specs" : [{
					"dtype"       : uint16,
					"description" : string, (optional)
				 }]
				]
			}]

--------------------------------------------------------------------------------

Service		org.bluez
Interface	org.bluez.HealthInstance
Object path	[variable prefix]/{hci0,hci1,...}/{hdp0,hdp1,...}

		object Connect(remote_instance_id)

			Connects with the remote instance and returns its object
			path.

			Possible errors: org.bluez.Error.InvalidArguments
					org.bluez.Error.HealthError

		void Disconnect(object device, boolean delete)

			Disconnect from the remote device. If delete is true,
			any status will also be deleted. Otherwise, the status
			will be kept for allowing future reconnections.

			Possible errors: org.bluez.Error.InvalidArguments
					org.bluez.Error.NotFound
					org.bluez.Error.HealthError

--------------------------------------------------------------------------------

Service		org.bluez
Interface	org.bluez.HealthLink
Object path	[variable prefix]/{hci0,hci1,...}/{hdp0,hdp1,...}/rem_inst_id

		boolean Echo(array{byte})

			Sends an echo petition to the remote intance. Returns
			True if response matches with the buffer sent. If some
			error is detected False value is returned and the
			associated MCL is closed.

		uint16 OpenDataChannel(byte mdepid, byte config)

			Creates a new data channel with the indicated config
			to the remote MCAP Data End Point (MDEP).
			The configuration should indicate the channel quality of
			service.
			Returns the data channel id.

			Possible errors: org.bluez.Error.InvalidArguments
					org.bluez.Error.HealthError

		array GetDataChannelFileDescriptor(uint16 mdlid)

			Gets a file descriptor where data can be read or
			written for receive or sent by the data channel.
			Returns an array of file descriptors one for write
			and other for read.

			Possible errors: org.bluez.Error.InvalidArguments
					org.bluez.Error.NotFound
					org.bluez.Error.HealthError

		void DeleteDataChannel(uint16 mdlid)

			Deletes a data channel so it will not be available for
			use.

			Possible errors: org.bluez.Error.InvalidArguments
					org.bluez.Error.NotFound
					org.bluez.Error.HealthError

		void DeleteAllDataChannels()

			Deletes all data channels so it will not be available
			for use. Typically this function is called when the
			connection with the remote device will be closed
			permanently

			Possible errors: org.bluez.Error.HealthError

		dict GetDataChannelStatus()

			Return a dictionary with all the data channels that
			can be used to send data right now. The dictionary
			is formed like follows:
			{
				"reliable": [id1, ..., idz],
				"best_effort" : [idx, ..., idy]
			}

			The fist reliable data channel will always be the first
			data channel in reliable array.

HealthAgent hierarchy
==================

(this object is implemented by the HDP client an receives notifications)

Service		unique name
Interface	org.bluez.HealthAgent
Object path	freely definable

		void DeviceConnected(object path)

			This method is called whenever a new device connection
			has been established over the control channel of the
			current HDP instance. The object path contains the
			object path of the remote device.

		void DeviceDisconnected(object path)

			This method is called when a remote device is
			disconnected definitively. Any future reconnections
			will fail. Also all data channels associated to this
			device will be closed.

		void CreatedDataChannel(object path, uint16 mdlid)

			This method is called when a new data channel is created
			The path contains the object path of the device whith
			the new connection is created and the mdlid the data
			channel identificator.

		void DeletedDataChannel(object path, uint16 mdlid)

			This method is called when a data channel is closed.
			After this call the data channel will not be valid and
			can be reused for future created data channels.

^ permalink raw reply

* [PATCH 01/25] Initial support for MCAP
From: Santiago Carot-Nemesio @ 2010-05-14 10:19 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio

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

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


^ permalink raw reply related

* [PATCH 02/25] Initial work to create MCAP instances
From: Santiago Carot-Nemesio @ 2010-05-14 10:19 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1273832392-18654-1-git-send-email-sancane@gmail.com>

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

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


^ permalink raw reply related

* [PATCH 03/25] Initial work to process incomming connection of MCLs
From: Santiago Carot-Nemesio @ 2010-05-14 10:19 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1273832392-18654-2-git-send-email-sancane@gmail.com>

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

diff --git a/mcap/mcap.c b/mcap/mcap.c
index ff8c9b5..dce1c61 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -36,14 +36,205 @@
 
 #define MCAP_ERROR g_quark_from_static_string("mcap-error-quark")
 
+static void default_mdl_connected_cb(struct mcap_mdl *mdl, gpointer data)
+{
+	debug("MCAP Unmanaged mdl connection");
+}
+
+static void default_mdl_closed_cb(struct mcap_mdl *mdl, gpointer data)
+{
+	debug("MCAP Unmanaged mdl closed");
+}
+
+static void default_mdl_deleted_cb(struct mcap_mdl *mdl, gpointer data)
+{
+	debug("MCAP Unmanaged mdl deleted");
+}
+
+static void default_mdl_aborted_cb(struct mcap_mdl *mdl, gpointer data)
+{
+	debug("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)
+{
+	debug("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)
+{
+	debug("MCAP mdl remote reconnection aborted");
+	/* Due to this callback isn't managed this request won't be supported */
+	return MCAP_REQUEST_NOT_SUPPORTED;
+}
+
+static void set_default_cb(struct mcap_mcl *mcl)
+{
+	if (!mcl->cb)
+		mcl->cb = g_new0(struct mcap_mdl_cb, 1);
+
+	mcl->cb->mdl_connected = default_mdl_connected_cb;
+	mcl->cb->mdl_closed = default_mdl_closed_cb;
+	mcl->cb->mdl_deleted = default_mdl_deleted_cb;
+	mcl->cb->mdl_aborted = default_mdl_aborted_cb;
+	mcl->cb->mdl_conn_req = default_mdl_conn_req_cb;
+	mcl->cb->mdl_reconn_req = default_mdl_reconn_req_cb;
+}
+
+static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr)
+{
+	GSList *l;
+	struct mcap_mcl *mcl;
+
+	for (l = list; l; l = l->next) {
+		mcl = l->data;
+
+		if (!bacmp(&mcl->addr, addr))
+			return mcl;
+	}
+
+	return NULL;
+}
+
+static void mcap_mcl_release(struct mcap_mcl *mcl)
+{
+	/* TODO */
+}
+
+static void mcap_mcl_check_del(struct mcap_mcl *mcl)
+{
+	/* TODO */
+}
+
+static void mcap_uncache_mcl(struct mcap_mcl *mcl)
+{
+	/* TODO */
+}
+
+struct mcap_mcl *mcap_mcl_ref(struct mcap_mcl *mcl)
+{
+	mcl->ref++;
+
+	debug("mcap_mcl_ref(%p): ref=%d", mcl, mcl->ref);
+
+	return mcl;
+}
+
+void mcap_mcl_unref(struct mcap_mcl *mcl)
+{
+	mcl->ref--;
+
+	debug("mcap_mcl_unref(%p): ref=%d", mcl, mcl->ref);
+
+	if (mcl->ref > 0)
+		return;
+
+	mcap_mcl_release(mcl);
+}
+
+static gboolean mcl_control_cb(GIOChannel *chan, GIOCondition cond,
+								gpointer data)
+{
+
+	/* TODO */
+	return FALSE;
+}
+
 static void confirm_dc_event_cb(GIOChannel *chan, gpointer user_data)
 {
 	/* TODO */
 }
 
+static void connect_mcl_event_cb(GIOChannel *chan, GError *err,
+							gpointer user_data)
+{
+	struct mcap_mcl *mcl = user_data;
+	gboolean reconn;
+
+	if (err) {
+		mcap_mcl_check_del(mcl);
+		return;
+	}
+
+	mcl->state = MCL_CONNECTED;
+	mcl->role = MCL_ACCEPTOR;
+	mcl->req = MCL_AVAILABLE;
+	mcl->cc = g_io_channel_ref(chan);
+	mcl->ctrl |= MCAP_CTRL_STD_OP;
+
+	reconn = (mcl->ctrl & MCAP_CTRL_CACHED);
+	if (reconn)
+		mcap_uncache_mcl(mcl);
+	else
+		mcl->ms->mcls = g_slist_prepend(mcl->ms->mcls, mcl);
+
+	mcl->wid = g_io_add_watch(mcl->cc,
+			G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+			(GIOFunc) mcl_control_cb, mcl);
+
+	/* Callback to report new MCL */
+	if (reconn)
+		mcl->ms->mcl_reconnected_cb(mcl, mcl->ms->user_data);
+	else
+		mcl->ms->mcl_connected_cb(mcl, mcl->ms->user_data);
+
+	if (mcl->ref == 1) {
+		mcl->ms->mcls = g_slist_remove(mcl->ms->mcls, mcl);
+		mcap_mcl_unref(mcl);
+	}
+}
+
 static void confirm_mcl_event_cb(GIOChannel *chan, gpointer user_data)
 {
-	/* TODO */
+	struct mcap_instance *ms = user_data;
+	struct mcap_mcl *mcl;
+	bdaddr_t dst;
+	char address[18], srcstr[18];
+	GError *err = NULL;
+
+	bt_io_get(chan, BT_IO_L2CAP, &err,
+			BT_IO_OPT_DEST_BDADDR, &dst,
+			BT_IO_OPT_DEST, address,
+			BT_IO_OPT_INVALID);
+	if (err) {
+		error("%s", err->message);
+		g_error_free(err);
+		goto drop;
+	}
+
+	ba2str(&ms->src, srcstr);
+	mcl = find_mcl(ms->mcls, &dst);
+	if (mcl) {
+		error("Control channel already created with %s on adapter %s",
+				address, srcstr);
+		goto drop;
+	}
+
+	mcl = find_mcl(ms->cached, &dst);
+	if (!mcl) {
+		mcl = g_new0(struct mcap_mcl, 1);
+		mcl->ms = ms;
+		bacpy(&mcl->addr, &dst);
+		set_default_cb(mcl);
+		mcl = mcap_mcl_ref(mcl);
+	}
+
+	if (!bt_io_accept(chan, connect_mcl_event_cb, mcl, NULL, &err)) {
+		error("mcap accept error: %s", err->message);
+		if (!(mcl->ctrl & MCAP_CTRL_CACHED))
+			mcap_mcl_unref(mcl);
+		g_error_free(err);
+		goto drop;
+	}
+
+	return;
+drop:
+	g_io_channel_shutdown(chan, TRUE, NULL);
 }
 
 struct mcap_instance *mcap_create_instance(struct btd_adapter *btd_adapter,
-- 
1.6.3.3


^ permalink raw reply related

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

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

diff --git a/mcap/mcap.c b/mcap/mcap.c
index dce1c61..90c5fa3 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -36,6 +36,17 @@
 
 #define MCAP_ERROR g_quark_from_static_string("mcap-error-quark")
 
+/* MCAP finite state machine functions */
+static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l);
+static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l);
+static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l);
+
+static void (*proc_req[])(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) = {
+	proc_req_connected,
+	proc_req_pending,
+	proc_req_active
+};
+
 static void default_mdl_connected_cb(struct mcap_mdl *mdl, gpointer data)
 {
 	debug("MCAP Unmanaged mdl connection");
@@ -86,6 +97,41 @@ static void set_default_cb(struct mcap_mcl *mcl)
 	mcl->cb->mdl_reconn_req = default_mdl_reconn_req_cb;
 }
 
+int mcap_send_data(int sock, const uint8_t *buf, uint32_t size)
+{
+	uint32_t sent = 0;
+
+	while (sent < size) {
+		int n = send(sock, buf + sent, size - sent, 0);
+		if (n < 0)
+			return -1;
+		sent += n;
+	}
+	return 0;
+}
+
+static int send4B_cmd(struct mcap_mcl *mcl, uint8_t oc, uint8_t rc,
+								uint16_t mdl)
+{
+	uint8_t *rsp;
+	mcap4B_rsp *rsp_err;
+	int sent;
+
+
+	rsp = g_malloc0(sizeof(mcap4B_rsp));
+
+	rsp_err = (mcap4B_rsp *)rsp;
+	rsp_err->op = oc;
+	rsp_err->rc = rc;
+	rsp_err->mdl = htons (mdl);
+
+	sent = mcap_send_data(g_io_channel_unix_get_fd(mcl->cc),
+					rsp,
+					sizeof(mcap4B_rsp));
+	g_free(rsp);
+	return sent;
+}
+
 static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr)
 {
 	GSList *l;
@@ -111,6 +157,11 @@ static void mcap_mcl_check_del(struct mcap_mcl *mcl)
 	/* TODO */
 }
 
+static void mcap_cache_mcl(struct mcap_mcl *mcl)
+{
+	/* TODO */
+}
+
 static void mcap_uncache_mcl(struct mcap_mcl *mcl)
 {
 	/* TODO */
@@ -137,11 +188,103 @@ void mcap_mcl_unref(struct mcap_mcl *mcl)
 	mcap_mcl_release(mcl);
 }
 
+static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
+{
+	/* TODO */
+}
+
+static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
+{
+	/* TODO */
+}
+
+static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
+{
+	/* TODO */
+}
+
+static void proc_response(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
+{
+	/* TODO */
+}
+
+static void rsend_req(struct mcap_mcl *mcl)
+{
+	uint8_t *cmd = mcl->lcmd;
+	int len;
+
+	if (!cmd)
+		return;
+
+	switch (cmd[0]) {
+	case MCAP_MD_RECONNECT_MDL_REQ:
+	case MCAP_MD_ABORT_MDL_REQ:
+	case MCAP_MD_DELETE_MDL_REQ:
+		len = 3;
+		break;
+	case MCAP_MD_CREATE_MDL_REQ:
+		len = 5;
+		break;
+	default:
+		return;
+	}
+
+	mcap_send_data(g_io_channel_unix_get_fd(mcl->cc), cmd, len);
+}
+
+static void proc_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
+{
+	if ((cmd[0] >= MCAP_MD_SYNC_CAP_REQ) &&
+					(cmd[0] <= MCAP_MD_SYNC_INFO_IND)) {
+		send4B_cmd(mcl, cmd[0], MCAP_REQUEST_NOT_SUPPORTED,
+							MCAP_MDLID_RESERVED);
+		return;
+	}
+
+	if (!(mcl->ctrl & MCAP_CTRL_STD_OP)) {
+		/* In case the remote device doesn't work correctly */
+		error("Remote device does not support opcodes, cmd ignored");
+		return;
+	}
+
+	if (mcl->req == MCL_WAITING_RSP) {
+		if (cmd[0] & 0x01) {
+			/* Request arrived when a response is expected */
+			if (mcl->role == MCL_INITIATOR)
+				/* ignore */
+				return;
+			proc_req[mcl->state](mcl, cmd, len);
+			/* Initiator will ignore our last request => re-send */
+			rsend_req(mcl);
+			return;
+		}
+		proc_response(mcl, cmd, len);
+	} else if (cmd[0] & 0x01)
+		proc_req[mcl->state](mcl, cmd, len);
+}
+
 static gboolean mcl_control_cb(GIOChannel *chan, GIOCondition cond,
 								gpointer data)
 {
 
-	/* TODO */
+	struct mcap_mcl *mcl = data;
+	int sk, len;
+	uint8_t buf[MCAP_CC_MTU];
+
+	if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
+		goto fail;
+
+	sk = g_io_channel_unix_get_fd(chan);
+	len = recv(sk, buf, sizeof(buf), 0);
+	if (len < 0)
+		goto fail;
+
+	proc_cmd(mcl, buf, (uint32_t)len);
+	return TRUE;
+fail:
+	if (mcl->state != MCL_IDLE)
+		mcl->ms->mcl_disconnected_cb(mcl, mcl->ms->user_data);
+	mcap_cache_mcl(mcl);
 	return FALSE;
 }
 
-- 
1.6.3.3


^ permalink raw reply related

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

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

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 90c5fa3..f8caa01 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -34,8 +34,16 @@
 #include "mcap_lib.h"
 #include "mcap_internal.h"
 
+#define MAX_CACHED	10	/* 10 devices */
+
 #define MCAP_ERROR g_quark_from_static_string("mcap-error-quark")
 
+#define RELEASE_TIMER(__mcl) do {	\
+	g_source_remove(__mcl->tid);	\
+	__mcl->tid = 0;			\
+} while(0)
+
+
 /* MCAP finite state machine functions */
 static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l);
 static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l);
@@ -147,24 +155,166 @@ static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr)
 	return NULL;
 }
 
+static void shutdown_mdl(struct mcap_mdl *mdl)
+{
+	mdl->state = MDL_CLOSED;
+
+	g_source_remove(mdl->wid);
+
+	if (mdl->dc) {
+		g_io_channel_shutdown(mdl->dc, TRUE, NULL);
+		g_io_channel_unref(mdl->dc);
+		mdl->dc = NULL;
+	}
+}
+
+static void mcap_free_mdls(struct mcap_mcl *mcl, gboolean save)
+{
+	GSList *l;
+	struct mcap_mdl *mdl;
+
+	if (!mcl->mdls)
+		return;
+
+	for (l = mcl->mdls; l; l = l->next) {
+		mdl = l->data;
+		shutdown_mdl(mdl);
+		if (!save)
+			g_free(mdl);
+	}
+
+	if (!save) {
+		g_slist_free(mcl->mdls);
+		mcl->mdls = NULL;
+	}
+}
+
+static void close_mcl(struct mcap_mcl *mcl, gboolean save)
+{
+	gboolean store = ((!(mcl->ctrl & MCAP_CTRL_FREE)) && save);
+
+	if (mcl->tid) {
+		RELEASE_TIMER(mcl);
+	}
+
+	if (mcl->cc) {
+		g_io_channel_shutdown(mcl->cc, TRUE, NULL);
+		g_io_channel_unref(mcl->cc);
+		mcl->cc = NULL;
+	}
+
+	g_source_remove(mcl->wid);
+	if (mcl->lcmd) {
+		g_free(mcl->lcmd);
+		mcl->lcmd = NULL;
+	}
+
+	if (mcl->priv_data) {
+		g_free(mcl->priv_data);
+		mcl->priv_data = NULL;
+	}
+
+	mcap_free_mdls(mcl, store);
+
+	if (mcl->cb && !store) {
+		g_free(mcl->cb);
+		mcl->cb = NULL;
+	}
+
+	mcl->state = MCL_IDLE;
+
+	if (store)
+		return;
+
+	g_free(mcl);
+}
+
+static void mcap_mcl_shutdown(struct mcap_mcl *mcl)
+{
+	close_mcl(mcl, TRUE);
+}
+
 static void mcap_mcl_release(struct mcap_mcl *mcl)
 {
-	/* TODO */
+	close_mcl(mcl, FALSE);
 }
 
 static void mcap_mcl_check_del(struct mcap_mcl *mcl)
 {
-	/* TODO */
+	if (mcl->ctrl & MCAP_CTRL_CACHED)
+		mcap_mcl_shutdown(mcl);
+	else
+		mcap_mcl_unref(mcl);
 }
 
 static void mcap_cache_mcl(struct mcap_mcl *mcl)
 {
-	/* TODO */
+	GSList *l;
+	struct mcap_mcl *last;
+	int len;
+
+	if (mcl->ctrl & MCAP_CTRL_CACHED)
+		return;
+
+	mcl->ms->mcls = g_slist_remove(mcl->ms->mcls, mcl);
+
+	if ((mcl->ctrl & MCAP_CTRL_NOCACHE) || (mcl->ref < 2)) {
+		mcap_mcl_unref(mcl);
+		return;
+	}
+
+	debug("Caching MCL");
+
+	len = g_slist_length(mcl->ms->cached);
+	if (len == MAX_CACHED) {
+		/* Remove the latest cached mcl */
+		l = g_slist_last(mcl->ms->cached);
+		last = l->data;
+		mcl->ms->cached = g_slist_remove(mcl->ms->cached, last);
+		last->ctrl &= ~MCAP_CTRL_CACHED;
+		if (last->ctrl & MCAP_CTRL_CONN) {
+			/* If connection process is not success this MCL will be
+			 * freed next time that close_mcl is invoked */
+			last->ctrl |= MCAP_CTRL_FREE;
+		} else {
+			last->ms->mcl_uncached_cb(last, last->ms->user_data);
+			mcap_mcl_unref(last);
+		}
+	}
+
+	mcl->ms->cached = g_slist_prepend(mcl->ms->cached, mcl);
+	mcl->ctrl |= MCAP_CTRL_CACHED;
+	mcap_mcl_shutdown(mcl);
 }
 
 static void mcap_uncache_mcl(struct mcap_mcl *mcl)
 {
-	/* TODO */
+	if (!(mcl->ctrl & MCAP_CTRL_CACHED))
+		return;
+
+	debug("Got MCL from cache");
+
+	mcl->ms->cached = g_slist_remove(mcl->ms->cached, mcl);
+	mcl->ms->mcls = g_slist_prepend(mcl->ms->mcls, mcl);
+	mcl->ctrl &= ~MCAP_CTRL_CACHED;
+	mcl->ctrl &= ~MCAP_CTRL_FREE;
+}
+
+void mcap_close_mcl(struct mcap_mcl *mcl, gboolean cache)
+{
+	if (!mcl)
+		return;
+
+	if (mcl->cc) {
+		g_io_channel_shutdown(mcl->cc, TRUE, NULL);
+		g_io_channel_unref(mcl->cc);
+		mcl->cc = NULL;
+	}
+
+	mcl->state = MCL_IDLE;
+
+	if (!cache)
+		mcl->ctrl |= MCAP_CTRL_NOCACHE;
 }
 
 struct mcap_mcl *mcap_mcl_ref(struct mcap_mcl *mcl)
-- 
1.6.3.3


^ permalink raw reply related

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

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

diff --git a/mcap/mcap.c b/mcap/mcap.c
index f8caa01..ce91e58 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -604,6 +604,35 @@ struct mcap_instance *mcap_create_instance(struct btd_adapter *btd_adapter,
 
 void mcap_release_instance(struct mcap_instance *ms)
 {
-	/* TODO */
+	GSList *l;
+
+	if (!ms)
+		return;
+
+	if (ms->ccio) {
+		g_io_channel_shutdown(ms->ccio, TRUE, NULL);
+		g_io_channel_unref(ms->ccio);
+		ms->ccio = NULL;
+	}
+
+	if (ms->dcio) {
+		g_io_channel_shutdown(ms->dcio, TRUE, NULL);
+		g_io_channel_unref(ms->dcio);
+		ms->dcio = NULL;
+	}
+
+	for (l = ms->mcls; l; l = l->next) {
+		mcap_mcl_shutdown(l->data);
+		mcap_mcl_unref(l->data);
+	}
+	g_slist_free(ms->mcls);
+	ms->mcls = NULL;
+
+	for (l = ms->cached; l; l = l->next)
+		mcap_mcl_unref(l->data);
+	g_slist_free(ms->cached);
+	ms->cached = NULL;
+
+	g_free(ms);
 }
 
-- 
1.6.3.3


^ permalink raw reply related

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

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

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


^ permalink raw reply related

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

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

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 15b9141..a8bdc9e 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -479,6 +479,48 @@ static void process_md_create_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
 	send5B_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_SUCCESS, mdl_id, conf);
 }
 
+static void process_md_reconnect_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
+								uint32_t len)
+{
+	mcap_md_req *req;
+	struct mcap_mdl *mdl;
+	uint16_t mdl_id;
+	uint8_t rsp;
+
+	if (len != sizeof(mcap_md_req)) {
+		send4B_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP,
+				MCAP_INVALID_PARAM_VALUE, MCAP_MDLID_RESERVED);
+		return;
+	}
+
+	req = (mcap_md_req *)cmd;
+	mdl_id = ntohs(req->mdl);
+
+	mdl = get_mdl(mcl, mdl_id);
+	if (!mdl) {
+		send4B_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP,
+						MCAP_INVALID_MDL, mdl_id);
+		return;
+	}
+
+	/* Callback to upper layer */
+	rsp = mcl->cb->mdl_reconn_req(mdl, mcl->cb->user_data);
+	if (mcl->state == MCL_IDLE)
+		return;
+
+	if (rsp != MCAP_SUCCESS) {
+		send4B_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, rsp, mdl_id);
+		return;
+	}
+
+	if (mdl->state == MDL_CONNECTED)
+		shutdown_mdl(mdl);
+
+	mdl->state = MDL_WAITING;
+	mcl->state = MCL_PENDING;
+	send4B_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_SUCCESS, mdl_id);
+}
+
 /* Function used to process commands depending of MCL state */
 static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
 {
@@ -487,7 +529,7 @@ static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
 		process_md_create_mdl_req(mcl, cmd, len);
 		break;
 	case MCAP_MD_RECONNECT_MDL_REQ:
-		/*process_md_reconnect_mdl_req(mcl, cmd, len);*/
+		process_md_reconnect_mdl_req(mcl, cmd, len);
 		break;
 	case MCAP_MD_DELETE_MDL_REQ:
 		/*process_md_delete_mdl_req(mcl, cmd, len);*/
-- 
1.6.3.3


^ permalink raw reply related

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

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

diff --git a/mcap/mcap.c b/mcap/mcap.c
index a8bdc9e..e4d9a1a 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -174,6 +174,26 @@ static gint compare_mdl(gconstpointer a, gconstpointer b)
 		return 1;
 }
 
+static void update_mcl_state(struct mcap_mcl *mcl)
+{
+	GSList *l;
+	struct mcap_mdl *mdl;
+
+	if (mcl->state == MCL_PENDING)
+		return;
+
+	for (l = mcl->mdls; l; l = l->next) {
+		mdl = l->data;
+
+		if (mdl->state == MDL_CONNECTED) {
+			mcl->state = MCL_ACTIVE;
+			return;
+		}
+	}
+
+	mcl->state = MCL_CONNECTED;
+}
+
 static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr)
 {
 	GSList *l;
@@ -407,6 +427,17 @@ static struct mcap_mdl *get_mdl(struct mcap_mcl *mcl, uint16_t mdlid)
 	return NULL;
 }
 
+static void mcap_delete_mdl(gpointer elem, gpointer user_data)
+{
+	struct mcap_mdl *mdl = elem;
+	gboolean notify = *(gboolean *)user_data;
+
+	shutdown_mdl(mdl);
+	if (notify)
+		mdl->mcl->cb->mdl_deleted(mdl, mdl->mcl->cb->user_data);
+	g_free(mdl);
+}
+
 static void process_md_create_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
 								uint32_t len)
 {
@@ -521,6 +552,61 @@ static void process_md_reconnect_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
 	send4B_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_SUCCESS, mdl_id);
 }
 
+static void process_md_delete_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
+								uint32_t len)
+{
+	mcap_md_req *req;
+	struct mcap_mdl *mdl, *aux;
+	uint16_t mdlid;
+	gboolean notify;
+	GSList *l;
+
+	if (len != sizeof(mcap_md_req)) {
+		send4B_cmd(mcl, MCAP_MD_ABORT_MDL_RSP,
+				MCAP_INVALID_PARAM_VALUE, MCAP_MDLID_RESERVED);
+		return;
+	}
+
+	req = (mcap_md_req *)cmd;
+	mdlid = ntohs(req->mdl);
+	if (mdlid == MCAP_ALL_MDLIDS) {
+		notify = FALSE;
+		g_slist_foreach(mcl->mdls, mcap_delete_mdl, &notify);
+		g_slist_free(mcl->mdls);
+		mcl->mdls = NULL;
+		mcl->state = MCL_CONNECTED;
+		/* NULL mdl means ALL_MDLS */
+		mcl->cb->mdl_deleted(NULL, mcl->cb->user_data);
+		goto resp;
+	}
+
+	if ((mdlid < MCAP_MDLID_INITIAL) || (mdlid > MCAP_MDLID_FINAL)) {
+		send4B_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_INVALID_MDL,
+									mdlid);
+		return;
+	}
+
+	for (l=mcl->mdls, mdl = NULL; l; l = l->next) {
+		aux = l->data;
+		if (aux->mdlid == mdlid) {
+			mdl = aux;
+			break;
+		}
+	}
+
+	if (!mdl || (mdl->state == MDL_WAITING)) {
+		send4B_cmd(mcl, MCAP_MD_DELETE_MDL_RSP, MCAP_INVALID_MDL,
+									mdlid);
+		return;
+	}
+	mcl->mdls = g_slist_remove(mcl->mdls, mdl);
+	update_mcl_state(mcl);
+	notify = TRUE;
+	mcap_delete_mdl(mdl, &notify);
+resp:
+	send4B_cmd(mcl, MCAP_MD_DELETE_MDL_RSP, MCAP_SUCCESS, mdlid);
+}
+
 /* Function used to process commands depending of MCL state */
 static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
 {
@@ -532,7 +618,7 @@ static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
 		process_md_reconnect_mdl_req(mcl, cmd, len);
 		break;
 	case MCAP_MD_DELETE_MDL_REQ:
-		/*process_md_delete_mdl_req(mcl, cmd, len);*/
+		process_md_delete_mdl_req(mcl, cmd, len);
 		break;
 	default:
 		error_cmd_rsp(mcl, cmd, len);
-- 
1.6.3.3


^ permalink raw reply related

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

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

diff --git a/mcap/mcap.c b/mcap/mcap.c
index e4d9a1a..ac0d938 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -552,6 +552,51 @@ static void process_md_reconnect_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
 	send4B_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_SUCCESS, mdl_id);
 }
 
+static void process_md_abort_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
+								uint32_t len)
+{
+	mcap_md_req *req;
+	GSList *l;
+	struct mcap_mdl *mdl, *del;
+	uint16_t mdl_id;
+
+	if (len != sizeof(mcap_md_req)) {
+		send4B_cmd(mcl, MCAP_MD_ABORT_MDL_RSP,
+				MCAP_INVALID_PARAM_VALUE, MCAP_MDLID_RESERVED);
+		return;
+	}
+
+	req = (mcap_md_req *)cmd;
+	mdl_id = ntohs(req->mdl);
+	mcl->state = MCL_CONNECTED;
+	for (l = mcl->mdls; l; l = l->next) {
+		mdl = l->data;
+		if ((mdl_id == mdl->mdlid) && (mdl->state == MDL_WAITING)) {
+			del = mdl;
+			if (mcl->state != MCL_CONNECTED)
+				break;
+			continue;
+		}
+		if ((mdl->state == MDL_CONNECTED) && (mcl->state != MCL_ACTIVE))
+			mcl->state = MCL_ACTIVE;
+
+		if ((del) && (mcl->state == MCL_ACTIVE))
+			break;
+	}
+
+	if (!del) {
+		send4B_cmd(mcl, MCAP_MD_ABORT_MDL_RSP, MCAP_INVALID_MDL,
+									mdl_id);
+		return;
+	}
+
+	mcl->cb->mdl_aborted(del, mcl->cb->user_data);
+
+	mcl->mdls = g_slist_remove(mcl->mdls, del);
+	g_free(del);
+	send4B_cmd(mcl, MCAP_MD_ABORT_MDL_RSP, MCAP_SUCCESS, mdl_id);
+}
+
 static void process_md_delete_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
 								uint32_t len)
 {
@@ -627,7 +672,10 @@ static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
 
 static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
 {
-	/* TODO */
+	if (cmd[0] == MCAP_MD_ABORT_MDL_REQ)
+		process_md_abort_mdl_req(mcl, cmd, len);
+	else
+		error_cmd_rsp(mcl, cmd, len);
 }
 
 static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
-- 
1.6.3.3


^ permalink raw reply related

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

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

diff --git a/mcap/mcap.c b/mcap/mcap.c
index ac0d938..dfa455f 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -680,7 +680,19 @@ static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
 
 static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
 {
-	/* TODO */
+	switch (cmd[0]) {
+	case MCAP_MD_CREATE_MDL_REQ:
+		process_md_create_mdl_req(mcl, cmd, len);
+		break;
+	case MCAP_MD_RECONNECT_MDL_REQ:
+		process_md_reconnect_mdl_req(mcl, cmd, len);
+		break;
+	case MCAP_MD_DELETE_MDL_REQ:
+		process_md_delete_mdl_req(mcl, cmd, len);
+		break;
+	default:
+		error_cmd_rsp(mcl, cmd, len);
+	}
 }
 
 static void proc_response(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
-- 
1.6.3.3


^ permalink raw reply related

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

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

diff --git a/mcap/mcap.c b/mcap/mcap.c
index dfa455f..7f9f508 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -755,6 +755,26 @@ 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;
+
+	debug("Close MDL %d", mdl->mdlid);
+
+	notify = (mdl->state == MDL_CONNECTED);
+	shutdown_mdl(mdl);
+
+	update_mcl_state(mdl->mcl);
+
+	if (notify)
+		/*Callback to upper layer */
+		mdl->mcl->cb->mdl_closed(mdl, mdl->mcl->cb->user_data);
+
+	return FALSE;
+}
+
 static gboolean mcl_control_cb(GIOChannel *chan, GIOCondition cond,
 								gpointer data)
 {
@@ -780,9 +800,57 @@ fail:
 	return FALSE;
 }
 
+static void connect_dc_event_cb(GIOChannel *chan, GError *err,
+							gpointer user_data)
+{
+	struct mcap_mdl *mdl = user_data;
+	struct mcap_mcl *mcl = mdl->mcl;
+
+	mdl->state = MDL_CONNECTED;
+	mdl->dc = g_io_channel_ref(chan);
+	mdl->wid = g_io_add_watch(mdl->dc, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+						(GIOFunc) mdl_event_cb, mdl);
+
+	mcl->state = MCL_ACTIVE;
+	mcl->cb->mdl_connected(mdl, mcl->cb->user_data);
+}
+
 static void confirm_dc_event_cb(GIOChannel *chan, gpointer user_data)
 {
-	/* TODO */
+	struct mcap_instance *ms = user_data;
+	struct mcap_mcl *mcl;
+	struct mcap_mdl *mdl;
+	GError *err = NULL;
+	bdaddr_t dst;
+	GSList *l;
+
+	bt_io_get(chan, BT_IO_L2CAP, &err,
+			BT_IO_OPT_DEST_BDADDR, &dst,
+			BT_IO_OPT_INVALID);
+	if (err) {
+		error("%s", err->message);
+		g_error_free(err);
+		goto drop;
+	}
+
+	mcl = find_mcl(ms->mcls, &dst);
+	if (!mcl || (mcl->state != MCL_PENDING))
+		goto drop;
+
+	for (l = mcl->mdls; l; l = l->next) {
+		mdl = l->data;
+		if (mdl->state == MDL_WAITING) {
+			if (!bt_io_accept(chan, connect_dc_event_cb, mdl, NULL,
+									&err)) {
+				error("MDL accept error %s", err->message);
+				g_error_free(err);
+				goto drop;
+			}
+			return;
+		}
+	}
+drop:
+	g_io_channel_shutdown(chan, TRUE, NULL);
 }
 
 static void connect_mcl_event_cb(GIOChannel *chan, GError *err,
-- 
1.6.3.3


^ permalink raw reply related

* [PATCH 13/25] Enable connect operation to a remote MCAP instances
From: Santiago Carot-Nemesio @ 2010-05-14 10:19 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1273832392-18654-12-git-send-email-sancane@gmail.com>

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

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 7f9f508..bbbcf2b 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -43,6 +43,12 @@
 	__mcl->tid = 0;			\
 } while(0)
 
+struct connect_mcl {
+	struct mcap_mcl		*mcl;		/* MCL for this operation */
+	mcap_mcl_connect_cb	connect_cb;	/* Connect callback */
+	gpointer		user_data;	/* Callback user data */
+};
+
 
 /* MCAP finite state machine functions */
 static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l);
@@ -800,6 +806,66 @@ fail:
 	return FALSE;
 }
 
+static void mcap_connect_mcl_cb(GIOChannel *chan, GError *conn_err,
+							gpointer user_data)
+{
+	char dstaddr[18];
+	struct connect_mcl *con = user_data;
+	struct mcap_mcl *aux, *mcl = con->mcl;
+	mcap_mcl_connect_cb connect_cb = con->connect_cb;
+	gpointer data = con->user_data;
+	GError *gerr = NULL;
+
+	g_free(con);
+
+	mcl->ctrl &= ~MCAP_CTRL_CONN;
+
+	if (conn_err) {
+		if (mcl->ctrl & MCAP_CTRL_FREE)
+			mcl->ms->mcl_uncached_cb(mcl, mcl->ms->user_data);
+		mcap_mcl_check_del(mcl);
+		connect_cb(NULL, conn_err, data);
+		return;
+	}
+
+	ba2str(&mcl->addr, dstaddr);
+
+	aux = find_mcl(mcl->ms->mcls, &mcl->addr);
+	if (aux) {
+		/* Double MCL connection case */
+		if (aux != mcl) {
+			/* This MCL was not in cache */
+			mcap_mcl_unref(mcl);
+		}
+		error("MCL error: Device %s is already connected", dstaddr);
+		g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_ALREADY_EXISTS,
+				"MCL %s is already connected", dstaddr);
+		connect_cb(NULL, gerr, data);
+		g_error_free(gerr);
+		return;
+	}
+
+	mcl->state = MCL_CONNECTED;
+	mcl->role = MCL_INITIATOR;
+	mcl->req = MCL_AVAILABLE;
+	mcl->ctrl |= MCAP_CTRL_STD_OP;
+
+	if (mcl->ctrl & MCAP_CTRL_CACHED)
+		mcap_uncache_mcl(mcl);
+	else
+		mcl->ms->mcls = g_slist_prepend(mcl->ms->mcls, mcl);
+
+	mcl->wid = g_io_add_watch(mcl->cc,
+				G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+				(GIOFunc) mcl_control_cb, mcl);
+	connect_cb(mcl, gerr, data);
+
+	if (mcl->ref == 1) {
+		mcl->ms->mcls = g_slist_remove(mcl->ms->mcls, mcl);
+		mcap_mcl_unref(mcl);
+	}
+}
+
 static void connect_dc_event_cb(GIOChannel *chan, GError *err,
 							gpointer user_data)
 {
@@ -815,6 +881,56 @@ static void connect_dc_event_cb(GIOChannel *chan, GError *err,
 	mcl->cb->mdl_connected(mdl, mcl->cb->user_data);
 }
 
+void mcap_create_mcl(struct mcap_instance *ms,
+				const bdaddr_t *addr,
+				uint16_t ccpsm,
+				GError **err,
+				mcap_mcl_connect_cb connect_cb,
+				gpointer user_data)
+{
+	struct mcap_mcl *mcl;
+	struct connect_mcl *con;
+
+	mcl = find_mcl(ms->mcls, addr);
+	if (mcl) {
+		g_set_error(err, MCAP_ERROR, MCAP_ERROR_ALREADY_EXISTS,
+					"MCL is already connected.");
+		return;
+	}
+
+	mcl = find_mcl(ms->cached, addr);
+	if (!mcl) {
+		mcl = g_new0(struct mcap_mcl, 1);
+		mcl->ms = ms;
+		mcl->state = MCL_IDLE;
+		bacpy(&mcl->addr, addr);
+		set_default_cb(mcl);
+		mcl = mcap_mcl_ref(mcl);
+	} else
+		mcl->ctrl |= MCAP_CTRL_CONN;
+
+	con = g_new0(struct connect_mcl, 1);
+	con->mcl = mcl;
+	con->connect_cb = connect_cb;
+	con->user_data = user_data;
+
+	mcl->cc = bt_io_connect(BT_IO_L2CAP, mcap_connect_mcl_cb, con,
+				NULL, err,
+				BT_IO_OPT_SOURCE_BDADDR, &ms->src,
+				BT_IO_OPT_DEST_BDADDR, addr,
+				BT_IO_OPT_PSM, ccpsm,
+				BT_IO_OPT_MTU, MCAP_CC_MTU,
+				BT_IO_OPT_SEC_LEVEL, ms->sec,
+				BT_IO_OPT_INVALID);
+	if (*err) {
+		g_free(con);
+		mcl->ctrl &= ~MCAP_CTRL_CONN;
+		if (mcl->ctrl & MCAP_CTRL_FREE)
+			mcl->ms->mcl_uncached_cb(mcl, mcl->ms->user_data);
+		mcap_mcl_check_del(mcl);
+	}
+}
+
 static void confirm_dc_event_cb(GIOChannel *chan, gpointer user_data)
 {
 	struct mcap_instance *ms = user_data;
-- 
1.6.3.3


^ permalink raw reply related

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

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

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


^ permalink raw reply related


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