Linux bluetooth development
 help / color / mirror / Atom feed
* Re: "Conditional jump or move" errors on attrib_create_sdp()
From: Brian Gix @ 2011-02-24 18:40 UTC (permalink / raw)
  To: Anderson Lizardo; +Cc: Claudio Takahasi, BlueZ development
In-Reply-To: <AANLkTimZKv2D3BZy+QWiutokQUGrnBWWT_uHQ0Lp06n8@mail.gmail.com>

Hi Lizardo,

On 2/24/2011 9:56 AM, Anderson Lizardo wrote:
> Hi Brian,
>
> I just noticed "Conditional jump or move depends on uninitialised
> value(s)" errors when running bluez with valgrind:
>
> ==690== Conditional jump or move depends on uninitialised value(s)
> ==690==    at 0x4837EA0: sdp_set_service_id (sdp.c:2456)
> ==690==    by 0x166F79: attrib_create_sdp (attrib-server.c:133)
> ==690==    by 0x167436: register_core_services (attrib-server.c:856)
> ==690==    by 0x1675E3: attrib_server_init (attrib-server.c:902)
> ==690==    by 0x162424: main (main.c:462)
>
> Full log is attached, it was generated with:
>
> env G_SLICE=always-malloc valgrind bluetoothd -n -d
>
> Can you take a look at this? Thanks,


This can be fixed in one of about 3 ways:
1. Eliminate the call to sdp_set_service_id all together (it's not 
required by the specification)

2. Set the service ID to services UUID (doesn't service a useful purpose)

3. Let the profile deal with the SDP service ID. (same as 1 for now)

The offending code attempts to give the SDP record a "Service ID" which 
is not required by the specification, but is useful if there is more 
than one instance of the service being declared in SDP.

An example of this in the case of GATT might be Two Primary Battery 
meter services, where both would have the same service UUID, but one 
would be referring to a "Main" battery, and the other an "Aux" battery.

In LE mode, the Service ID is unavailable and would be superfluous 
because everything you need to know about the service can be determined 
from the other Attributes. Therefore, I think the argument can be made 
that specific instance information is equally superflous, and should not 
be included in the service record.

If there are no objections, I am just going to eliminate the call to 
sdp_set_service_id in the attribute server all together.


-- 
Brian Gix
bgix@codeaurora.org
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum

^ permalink raw reply

* Re: [PATCH 1/2 v3] Add generic descriptor support to Attribute API document
From: Anderson Lizardo @ 2011-02-24 18:29 UTC (permalink / raw)
  To: Elvis Pfützenreuter; +Cc: linux-bluetooth
In-Reply-To: <1298468980-2215-1-git-send-email-epx@signove.com>

Hi Elvis,

On Wed, Feb 23, 2011 at 10:49 AM, Elvis Pfützenreuter <epx@signove.com> wrote:
> This patch proposes extensions to Attribute API, giving access to all
> characteristic descriptors (beyond 'Description' and 'Format').
>
> Client Characteristic Configuration automatic update upon Watcher
> registering will be handled by another patch series.
> ---
>  doc/attribute-api.txt |   30 ++++++++++++++++++++++++++++++
>  1 files changed, 30 insertions(+), 0 deletions(-)
>
> diff --git a/doc/attribute-api.txt b/doc/attribute-api.txt
> index 23808e6..bb7cbfa 100644
> --- a/doc/attribute-api.txt
> +++ b/doc/attribute-api.txt
> @@ -104,6 +104,7 @@ Methods             dict GetProperties()
>
>                        Possible Errors: org.bluez.Error.InvalidArguments
>
> +
>  Properties     string UUID [readonly]
>
>                        UUID128 of this characteristic.
> @@ -143,6 +144,35 @@ Properties         string UUID [readonly]
>                        Friendly representation of the Characteristic Value
>                        based on the format attribute.
>
> +               dict Descriptors [readwrite]
> +
> +                       Dict of descriptors for this characteristic.
> +
> +                       This dict contains only the descriptors not already
> +                       covered by other properties (v.g. Description, Format).
> +
> +                       Each descriptor is mapped to an unique object path,
> +                       which is the dict key.
> +
> +                       Each dict value is, in turn, a dict with at least
> +                       the following keys:
> +
> +                       {
> +                               "UUID": string. Descriptor UUID, always present
> +                               "Value": array of bytes. Raw descriptor value,
> +                                        present only when/if descriptor value
> +                                        has been fetched.
> +                       }
> +
> +                       When updating a descriptor value using SetProperty(),
> +                       only one descriptor at a time may be updated in order
> +                       to guarantee unambiguous error reporting. In other
> +                       words, when calling SetProperty('Descriptors', dict),
> +                       dict must have exactly one entry.
> +
> +                       Descriptor's UUID may not be updated. If present, it is
> +                       ignored by SetProperty().

With all those restrictions for writing, do you think it makes sense
to allow writing to the "Descriptors" property? Can you mention
situations where you might want applications to modify descriptors?

Regards,
-- 
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil

^ permalink raw reply

* Re: [PATCH] Don't register GATT related SDP records if attrib server is disabled
From: Johan Hedberg @ 2011-02-24 18:28 UTC (permalink / raw)
  To: Claudio Takahasi; +Cc: linux-bluetooth
In-Reply-To: <1298484913-21415-1-git-send-email-claudio.takahasi@openbossa.org>

Hi Claudio,

On Wed, Feb 23, 2011, Claudio Takahasi wrote:
> GATT related SDP records should not be added if "AttributeServer" option
> is false in the configuration file. Problem happens only when attribute
> plugin is enabled.
> ---
>  attrib/manager.c |   14 ++++++++------
>  1 files changed, 8 insertions(+), 6 deletions(-)

Pushed upstream. Thanks.

Johan

^ permalink raw reply

* Re: [PATCH] Fix DBG() calls with bogus messages
From: Johan Hedberg @ 2011-02-24 18:28 UTC (permalink / raw)
  To: Anderson Lizardo; +Cc: linux-bluetooth
In-Reply-To: <1298484663-19369-1-git-send-email-anderson.lizardo@openbossa.org>

Hi Lizardo,

On Wed, Feb 23, 2011, Anderson Lizardo wrote:
> Remove unnecessary trailing newlines (already added by DBG()) and
> rewrite debug messages to become more useful.
> ---
>  audio/telephony-ofono.c |    2 +-
>  plugins/service.c       |    5 +++--
>  2 files changed, 4 insertions(+), 3 deletions(-)

Pushed upstream. Thanks.

Johan

^ permalink raw reply

* Re: [PATCH] Add GStreamer version check in acinclude.m4
From: Johan Hedberg @ 2011-02-24 18:26 UTC (permalink / raw)
  To: Szymon Janc; +Cc: linux-bluetooth, par-gunnar.p.hjalmdahl, henrik.possung
In-Reply-To: <1298466787-2854-1-git-send-email-szymon.janc@tieto.com>

Hi Szymon,

On Wed, Feb 23, 2011, Szymon Janc wrote:
> Since commit cc04c6a2f7500f3d29d56634e645130ff3bd80fb compilation
> fails with GStreamer 0.10.28 or older.
> ---
>  acinclude.m4 |    3 ++-
>  1 files changed, 2 insertions(+), 1 deletions(-)

The patch has been pushed upstream. Thanks. Btw, be careful with your
commit message width. It needs to fit within 80 columns even with the
indentation that git log applies (I had to edit it manually this time).

Johan

^ permalink raw reply

* Re: [PATCH] Fix HCI LE advertising report dump
From: Claudio Takahasi @ 2011-02-24 17:40 UTC (permalink / raw)
  To: Andre Dieb Martins; +Cc: linux-bluetooth
In-Reply-To: <1298567839-8008-1-git-send-email-andre.dieb@signove.com>

SGkgQW5kcmUsCgpPbiBUaHUsIEZlYiAyNCwgMjAxMSBhdCA1OjE3IFBNLCBBbmRyZSBEaWViIE1h
cnRpbnMKPGFuZHJlLmRpZWJAc2lnbm92ZS5jb20+IHdyb3RlOgo+IExFIGFkdmVydGlzaW5nIHJl
cG9ydCBldmVudCBoYXMgb25seSBvbmUgZGF0YSBibG9jayBmb3IgZWFjaCByZXBvcnQuIFRodXMs
IHdlCj4gY2FuJ3QgcmV1c2UgZXh0X2lucXVpcnlfcmVzcG9uc2VfZHVtcCgpLCB3aGljaCBsb29w
cyBvdmVyIHN1Y2Nlc3NpdmUgZGF0YSBibG9ja3MKPiB1bnRpbCByZWFjaGVzIGEgemVyby1sZW5n
dGggb25lLgo+Cj4gVGhpcyBjb21taXQgaW50cm9kdWNlcyBleHRfaW5xdWlyeV9kYXRhX2R1bXAo
KSwgd2hpY2ggZHVtcHMgYSBmcmFtZSBjb250YWluaW5nCj4gZGF0YSBmb3JtYXR0ZWQgYWNjb3Jk
aW5nIHRvIFtWb2wgM10gUGFydCBDLCBTZWN0aW9uIDguIFRoaXMgZnVuY3Rpb24gaXMgcmV1c2Vk
Cj4gYnkgZXh0X2lucXVpcnlfcmVzcG9uc2VfZHVtcCgpLgo+Cj4gQWxzbyBhZGRzIFJTU0kgcGFy
c2luZyB0byBlYWNoIGFkdmVydGlzaW5nIHJlcG9ydC4KPiAtLS0KPiDCoHBhcnNlci9oY2kuYyB8
IMKgMTM2ICsrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLQo+IMKgMSBmaWxlcyBjaGFuZ2VkLCA3NiBpbnNlcnRpb25zKCspLCA2MCBkZWxldGlv
bnMoLSkKPgo+IGRpZmYgLS1naXQgYS9wYXJzZXIvaGNpLmMgYi9wYXJzZXIvaGNpLmMKPiBpbmRl
eCAxODNmYTY2Li5kYzI3YTI3IDEwMDY0NAo+IC0tLSBhL3BhcnNlci9oY2kuYwo+ICsrKyBiL3Bh
cnNlci9oY2kuYwo+IEBAIC03NTcsNjcgKzc1Nyw4MyBAQCBzdGF0aWMgY2hhciAqZmlsdGVycG9s
aWN5MnN0cih1aW50OF90IHBvbGljeSkKPiDCoCDCoCDCoCDCoH0KPiDCoH0KPgo+IC1zdGF0aWMg
aW5saW5lIHZvaWQgZXh0X2lucXVpcnlfcmVzcG9uc2VfZHVtcChpbnQgbGV2ZWwsIHN0cnVjdCBm
cmFtZSAqZnJtKQo+ICtzdGF0aWMgaW5saW5lIHZvaWQgZXh0X2lucXVpcnlfZGF0YV9kdW1wKGlu
dCBsZXZlbCwgc3RydWN0IGZyYW1lICpmcm0sCj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCB1aW50OF90ICpkYXRh
KQo+IMKgewo+IC0gwqAgwqAgwqAgdm9pZCAqcHRyID0gZnJtLT5wdHI7Cj4gLSDCoCDCoCDCoCB1
aW50MzJfdCBsZW4gPSBmcm0tPmxlbjsKPiAtIMKgIMKgIMKgIHVpbnQ4X3QgdHlwZSwgbGVuZ3Ro
Owo+ICsgwqAgwqAgwqAgdWludDhfdCBsZW4gPSBkYXRhWzBdOwo+ICsgwqAgwqAgwqAgdWludDhf
dCB0eXBlOwo+IMKgIMKgIMKgIMKgY2hhciAqc3RyOwo+IMKgIMKgIMKgIMKgaW50IGk7Cj4KPiAt
IMKgIMKgIMKgIGxlbmd0aCA9IGdldF91OChmcm0pOwo+ICsgwqAgwqAgwqAgaWYgKGxlbiA9PSAw
KQo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgcmV0dXJuOwo+Cj4gLSDCoCDCoCDCoCB3aGlsZSAo
bGVuZ3RoID4gMCkgewo+IC0gwqAgwqAgwqAgwqAgwqAgwqAgwqAgdHlwZSA9IGdldF91OChmcm0p
Owo+IC0gwqAgwqAgwqAgwqAgwqAgwqAgwqAgbGVuZ3RoLS07Cj4gKyDCoCDCoCDCoCB0eXBlID0g
ZGF0YVsxXTsKPiArIMKgIMKgIMKgIGRhdGEgKz0gMjsKPiArIMKgIMKgIMKgIGxlbiAtPSAxOwo+
Cj4gLSDCoCDCoCDCoCDCoCDCoCDCoCDCoCBzd2l0Y2ggKHR5cGUpIHsKPiAtIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIGNhc2UgMHgwMToKPiAtIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IHBfaW5kZW50KGxldmVsLCBmcm0pOwo+IC0gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgcHJpbnRmKCJGbGFnczoiKTsKPiAtIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IGZvciAoaSA9IDA7IGkgPCBsZW5ndGg7IGkrKykKPiAtIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIHByaW50ZigiIDB4JTIuMngiLCAqKCh1aW50OF90ICopIChm
cm0tPnB0ciArIGkpKSk7Cj4gLSDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCBwcmlu
dGYoIlxuIik7Cj4gLSDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCBicmVhazsKPiAr
IMKgIMKgIMKgIHN3aXRjaCAodHlwZSkgewo+ICsgwqAgwqAgwqAgY2FzZSAweDAxOgo+ICsgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgcF9pbmRlbnQobGV2ZWwsIGZybSk7Cj4gKyDCoCDCoCDCoCDCoCDC
oCDCoCDCoCBwcmludGYoIkZsYWdzOiIpOwo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgZm9yIChp
ID0gMDsgaSA8IGxlbjsgaSsrKQo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
cHJpbnRmKCIgMHglMi4yeCIsIGRhdGFbaV0pOwo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgcHJp
bnRmKCJcbiIpOwo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgYnJlYWs7Cj4KPiAtIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIGNhc2UgMHgwMjoKPiAtIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGNhc2UgMHgw
MzoKPiAtIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIHBfaW5kZW50KGxldmVsLCBm
cm0pOwo+IC0gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgcHJpbnRmKCIlcyBzZXJ2
aWNlIGNsYXNzZXM6IiwKPiAtIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIHR5cGUgPT0gMHgwMiA/ICJTaG9ydGVuZWQiIDogIkNvbXBsZXRl
Iik7Cj4gLSDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCBmb3IgKGkgPSAwOyBpIDwg
bGVuZ3RoIC8gMjsgaSsrKSB7Cj4gLSDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCB1aW50MTZfdCB2YWwgPSBidG9ocyhidF9nZXRfdW5hbGlnbmVkKCh1aW50MTZf
dCAqKSAoZnJtLT5wdHIgKyAoaSAqIDIpKSkpOwo+IC0gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgcHJpbnRmKCIgMHglNC40eCIsIHZhbCk7Cj4gLSDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCB9Cj4gLSDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCBwcmludGYoIlxuIik7Cj4gLSDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCBicmVhazsKPiArIMKgIMKgIMKgIGNhc2UgMHgwMjoKPiArIMKgIMKgIMKgIGNhc2UgMHgwMzoK
PiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIHBfaW5kZW50KGxldmVsLCBmcm0pOwo+ICsgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgcHJpbnRmKCIlcyBzZXJ2aWNlIGNsYXNzZXM6IiwKPiArIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIHR5cGUgPT0gMHgwMiA/ICJTaG9y
dGVuZWQiIDogIkNvbXBsZXRlIik7Cj4KPiAtIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGNhc2UgMHgw
ODoKPiAtIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGNhc2UgMHgwOToKPiAtIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIHN0ciA9IG1hbGxvYyhsZW5ndGggKyAxKTsKPiAtIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGlmIChzdHIpIHsKPiAtIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIHNucHJpbnRmKHN0ciwgbGVuZ3RoICsgMSwgIiVz
IiwgKGNoYXIgKikgZnJtLT5wdHIpOwo+IC0gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgZm9yIChpID0gMDsgaSA8IGxlbmd0aDsgaSsrKQo+IC0gwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgaWYgKCFpc3By
aW50KHN0cltpXSkpCj4gLSDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCBzdHJbaV0gPSAnLic7Cj4gLSDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCBwX2luZGVudChsZXZlbCwgZnJtKTsK
PiAtIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIHByaW50Zigi
JXMgbG9jYWwgbmFtZTogXCclc1wnXG4iLAo+IC0gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgdHlwZSA9PSAweDA4ID8gIlNob3J0ZW5lZCIg
OiAiQ29tcGxldGUiLCBzdHIpOwo+IC0gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgZnJlZShzdHIpOwo+IC0gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgfQo+IC0gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgYnJlYWs7Cj4gKyDCoCDC
oCDCoCDCoCDCoCDCoCDCoCBmb3IgKGkgPSAwOyBpIDwgbGVuIC8gMjsgaSsrKSB7Cj4gKyDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCB1aW50MTZfdCB2YWw7Cj4KPiAtIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIGNhc2UgMHgwYToKPiAtIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIHBfaW5kZW50KGxldmVsLCBmcm0pOwo+IC0gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgcHJpbnRmKCJUWCBwb3dlciBsZXZlbDogJWRcbiIsICooKHVpbnQ4X3QgKikgZnJtLT5w
dHIpKTsKPiAtIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGJyZWFrOwo+ICsgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgdmFsID0gYnRvaHMoYnRfZ2V0X3VuYWxpZ25l
ZCgoKHVpbnQxNl90ICopIChkYXRhICsgaSAqIDIpKSkpOwo+ICsgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgcHJpbnRmKCIgMHglNC40eCIsIHZhbCk7Cj4gKyDCoCDCoCDCoCDCoCDC
oCDCoCDCoCB9Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBwcmludGYoIlxuIik7Cj4gKyDCoCDC
oCDCoCDCoCDCoCDCoCDCoCBicmVhazsKPgo+IC0gwqAgwqAgwqAgwqAgwqAgwqAgwqAgZGVmYXVs
dDoKPiArIMKgIMKgIMKgIGNhc2UgMHgwODoKPiArIMKgIMKgIMKgIGNhc2UgMHgwOToKPiArIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIHN0ciA9IG1hbGxvYyhsZW4gKyAxKTsKPiArIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIGlmIChzdHIpIHsKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IHNucHJpbnRmKHN0ciwgbGVuICsgMSwgIiVzIiwgKGNoYXIgKikgZGF0YSk7Cj4gKyDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCBmb3IgKGkgPSAwOyBpIDwgbGVuOyBpKyspCj4gKyDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCBpZiAoIWlzcHJpbnQo
c3RyW2ldKSkKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIHN0cltpXSA9ICcuJzsKPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoHBfaW5kZW50KGxldmVsLCBmcm0pOwo+IC0gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgcHJpbnRmKCJVbmtub3duIHR5cGUgMHglMDJ4IHdpdGggJWQgYnl0ZXMgZGF0YVxu
IiwKPiAtIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIHR5cGUsIGxlbmd0aCk7
Cj4gLSDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCBicmVhazsKPiArIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIHByaW50ZigiJXMgbG9jYWwgbmFtZTogXCclc1wnXG4i
LAo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgdHlwZSA9
PSAweDA4ID8gIlNob3J0ZW5lZCIgOiAiQ29tcGxldGUiLCBzdHIpOwo+ICsgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgZnJlZShzdHIpOwo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
fQo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgYnJlYWs7Cj4gKwo+ICsgwqAgwqAgwqAgY2FzZSAw
eDBhOgo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgcF9pbmRlbnQobGV2ZWwsIGZybSk7Cj4gKyDC
oCDCoCDCoCDCoCDCoCDCoCDCoCBwcmludGYoIlRYIHBvd2VyIGxldmVsOiAlZFxuIiwgKigodWlu
dDhfdCAqKSBkYXRhKSk7Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBicmVhazsKPiArCj4gKyDC
oCDCoCDCoCBkZWZhdWx0Ogo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgcF9pbmRlbnQobGV2ZWws
IGZybSk7Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBwcmludGYoIlVua25vd24gdHlwZSAweCUw
Mnggd2l0aCAlZCBieXRlcyBkYXRhXG4iLAo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgdHlw
ZSwgbGVuKTsKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGJyZWFrOwo+ICsgwqAgwqAgwqAgfQo+
ICt9Cj4gKwo+ICtzdGF0aWMgaW5saW5lIHZvaWQgZXh0X2lucXVpcnlfcmVzcG9uc2VfZHVtcChp
bnQgbGV2ZWwsIHN0cnVjdCBmcmFtZSAqZnJtKQo+ICt7Cj4gKyDCoCDCoCDCoCB2b2lkICpwdHIg
PSBmcm0tPnB0cjsKPiArIMKgIMKgIMKgIHVpbnQzMl90IGxlbiA9IGZybS0+bGVuOwo+ICsgwqAg
wqAgwqAgdWludDhfdCBsZW5ndGg7Cj4gKwo+ICsgwqAgwqAgwqAgbGVuZ3RoID0gZ2V0X3U4KGZy
bSk7Cj4gKwo+ICsgwqAgwqAgwqAgd2hpbGUgKGxlbmd0aCA+IDApIHsKPiArIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIGV4dF9pbnF1aXJ5X2RhdGFfZHVtcChsZXZlbCwgZnJtLCBmcm0tPnB0cik7Cj4K
PiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoGZybS0+cHRyICs9IGxlbmd0aDsKPiDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoGZybS0+bGVuIC09IGxlbmd0aDsKPiBAQCAtMzUwNCwxNCArMzUyMCwxMiBA
QCBzdGF0aWMgaW5saW5lIHZvaWQgZXZ0X2xlX2Nvbm5fY29tcGxldGVfZHVtcChpbnQgbGV2ZWws
IHN0cnVjdCBmcmFtZSAqZnJtKQo+Cj4gwqBzdGF0aWMgaW5saW5lIHZvaWQgZXZ0X2xlX2FkdmVy
dGlzaW5nX3JlcG9ydF9kdW1wKGludCBsZXZlbCwgc3RydWN0IGZyYW1lICpmcm0pCj4gwqB7Cj4g
LSDCoCDCoCDCoCB1aW50OF90IG51bSA9IGdldF91OChmcm0pOwo+IC0gwqAgwqAgwqAgY2hhciBh
ZGRyWzE4XTsKPiAtIMKgIMKgIMKgIGludCBpOwo+ICsgwqAgwqAgwqAgdWludDhfdCBudW1fcmVw
b3J0cyA9IGdldF91OChmcm0pOwo+ICsgwqAgwqAgwqAgY29uc3QgdWludDhfdCBSU1NJX1NJWkUg
PSAxOwo+Cj4gLSDCoCDCoCDCoCBmb3IgKGkgPSAwOyBpIDwgbnVtOyBpKyspIHsKPiArIMKgIMKg
IMKgIHdoaWxlIChudW1fcmVwb3J0cy0tKSB7Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBjaGFy
IGFkZHJbMThdOwo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgbGVfYWR2ZXJ0aXNpbmdfaW5mbyAq
aW5mbyA9IGZybS0+cHRyOwo+IC0gwqAgwqAgwqAgwqAgwqAgwqAgwqAgdm9pZCAqcHRyID0gZnJt
LT5wdHI7Cj4gLSDCoCDCoCDCoCDCoCDCoCDCoCDCoCB1aW50MzJfdCBsZW4gPSBmcm0tPmxlbjsK
Pgo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgcF9iYTJzdHIoJmluZm8tPmJkYWRkciwgYWRkcik7
Cj4KPiBAQCAtMzUyMiwxMyArMzUzNiwxNSBAQCBzdGF0aWMgaW5saW5lIHZvaWQgZXZ0X2xlX2Fk
dmVydGlzaW5nX3JlcG9ydF9kdW1wKGludCBsZXZlbCwgc3RydWN0IGZyYW1lICpmcm0pCj4gwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqBwcmludGYoImJkYWRkciAlcyAoJXMpXG4iLCBhZGRyLAo+IMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
YmRhZGRydHlwZTJzdHIoaW5mby0+YmRhZGRyX3R5cGUpKTsKPgo+IC0gwqAgwqAgwqAgwqAgwqAg
wqAgwqAgZnJtLT5wdHIgKz0gTEVfQURWRVJUSVNJTkdfSU5GT19TSVpFOwo+IC0gwqAgwqAgwqAg
wqAgwqAgwqAgwqAgZnJtLT5sZW4gLT0gTEVfQURWRVJUSVNJTkdfSU5GT19TSVpFOwo+ICsgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgaWYgKGluZm8tPmxlbmd0aCA+IDApIHsKPiArIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIGV4dF9pbnF1aXJ5X2RhdGFfZHVtcChsZXZlbCwgZnJtLCAm
aW5mby0+bGVuZ3RoICsgMSk7Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCB9Cj4KPiAtIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIGV4dF9pbnF1aXJ5X3Jlc3BvbnNlX2R1bXAobGV2ZWwsIGZybSk7Cj4g
KyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBmcm0tPnB0ciArPSBMRV9BRFZFUlRJU0lOR19JTkZPX1NJ
WkUgKyBpbmZvLT5sZW5ndGggKyBSU1NJX1NJWkU7Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBm
cm0tPmxlbiAtPSBMRV9BRFZFUlRJU0lOR19JTkZPX1NJWkUgKyBpbmZvLT5sZW5ndGggKyBSU1NJ
X1NJWkU7Cj4KPiAtIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGZybS0+cHRyID0gcHRyICsgMTsKPiAt
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIGZybS0+bGVuID0gbGVuIC0gMTsKPiArIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIHBfaW5kZW50KGxldmVsLCBmcm0pOwo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
cHJpbnRmKCJSU1NJOiAlZFxuIiwgKChpbnQ4X3QgKikgZnJtLT5wdHIpW2ZybS0+bGVuIC0gMV0p
Owo+IMKgIMKgIMKgIMKgfQo+IMKgfQo+Cj4gLS0KPiAxLjcuMQo+Cj4gLS0KPiBUbyB1bnN1YnNj
cmliZSBmcm9tIHRoaXMgbGlzdDogc2VuZCB0aGUgbGluZSAidW5zdWJzY3JpYmUgbGludXgtYmx1
ZXRvb3RoIiBpbgo+IHRoZSBib2R5IG9mIGEgbWVzc2FnZSB0byBtYWpvcmRvbW9Admdlci5rZXJu
ZWwub3JnCj4gTW9yZSBtYWpvcmRvbW8gaW5mbyBhdCDCoGh0dHA6Ly92Z2VyLmtlcm5lbC5vcmcv
bWFqb3Jkb21vLWluZm8uaHRtbAo+CgpoY2lkdW1wIGlzIGNyYXNoaW5nLiBJIGdvbm5hIHNlbmQg
YSBwcml2YXRlIGUtbWFpbCB3aXRoIHRoZSBoY2lkdW1wCmxvZyB0byByZXByb2R1Y2UgdGhlIHBy
b2JsZW0uCgpDbGF1ZGlvLgo=

^ permalink raw reply

* [PATCH] Fix HCI LE advertising report dump
From: Andre Dieb Martins @ 2011-02-24 17:17 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: andre.dieb

LE advertising report event has only one data block for each report. Thus, we
can't reuse ext_inquiry_response_dump(), which loops over successive data blocks
until reaches a zero-length one.

This commit introduces ext_inquiry_data_dump(), which dumps a frame containing
data formatted according to [Vol 3] Part C, Section 8. This function is reused
by ext_inquiry_response_dump().

Also adds RSSI parsing to each advertising report.
---
 parser/hci.c |  136 ++++++++++++++++++++++++++++++++-------------------------
 1 files changed, 76 insertions(+), 60 deletions(-)

diff --git a/parser/hci.c b/parser/hci.c
index 183fa66..dc27a27 100644
--- a/parser/hci.c
+++ b/parser/hci.c
@@ -757,67 +757,83 @@ static char *filterpolicy2str(uint8_t policy)
 	}
 }
 
-static inline void ext_inquiry_response_dump(int level, struct frame *frm)
+static inline void ext_inquiry_data_dump(int level, struct frame *frm,
+						uint8_t *data)
 {
-	void *ptr = frm->ptr;
-	uint32_t len = frm->len;
-	uint8_t type, length;
+	uint8_t len = data[0];
+	uint8_t type;
 	char *str;
 	int i;
 
-	length = get_u8(frm);
+	if (len == 0)
+		return;
 
-	while (length > 0) {
-		type = get_u8(frm);
-		length--;
+	type = data[1];
+	data += 2;
+	len -= 1;
 
-		switch (type) {
-		case 0x01:
-			p_indent(level, frm);
-			printf("Flags:");
-			for (i = 0; i < length; i++)
-				printf(" 0x%2.2x", *((uint8_t *) (frm->ptr + i)));
-			printf("\n");
-			break;
+	switch (type) {
+	case 0x01:
+		p_indent(level, frm);
+		printf("Flags:");
+		for (i = 0; i < len; i++)
+			printf(" 0x%2.2x", data[i]);
+		printf("\n");
+		break;
 
-		case 0x02:
-		case 0x03:
-			p_indent(level, frm);
-			printf("%s service classes:",
-					type == 0x02 ? "Shortened" : "Complete");
-			for (i = 0; i < length / 2; i++) {
-				uint16_t val = btohs(bt_get_unaligned((uint16_t *) (frm->ptr + (i * 2))));
-				printf(" 0x%4.4x", val);
-			}
-			printf("\n");
-			break;
+	case 0x02:
+	case 0x03:
+		p_indent(level, frm);
+		printf("%s service classes:",
+				type == 0x02 ? "Shortened" : "Complete");
 
-		case 0x08:
-		case 0x09:
-			str = malloc(length + 1);
-			if (str) {
-				snprintf(str, length + 1, "%s", (char *) frm->ptr);
-				for (i = 0; i < length; i++)
-					if (!isprint(str[i]))
-						str[i] = '.';
-				p_indent(level, frm);
-				printf("%s local name: \'%s\'\n",
-					type == 0x08 ? "Shortened" : "Complete", str);
-				free(str);
-			}
-			break;
+		for (i = 0; i < len / 2; i++) {
+			uint16_t val;
 
-		case 0x0a:
-			p_indent(level, frm);
-			printf("TX power level: %d\n", *((uint8_t *) frm->ptr));
-			break;
+			val = btohs(bt_get_unaligned(((uint16_t *) (data + i * 2))));
+			printf(" 0x%4.4x", val);
+		}
+		printf("\n");
+		break;
 
-		default:
+	case 0x08:
+	case 0x09:
+		str = malloc(len + 1);
+		if (str) {
+			snprintf(str, len + 1, "%s", (char *) data);
+			for (i = 0; i < len; i++)
+				if (!isprint(str[i]))
+					str[i] = '.';
 			p_indent(level, frm);
-			printf("Unknown type 0x%02x with %d bytes data\n",
-								type, length);
-			break;
+			printf("%s local name: \'%s\'\n",
+				type == 0x08 ? "Shortened" : "Complete", str);
+			free(str);
 		}
+		break;
+
+	case 0x0a:
+		p_indent(level, frm);
+		printf("TX power level: %d\n", *((uint8_t *) data));
+		break;
+
+	default:
+		p_indent(level, frm);
+		printf("Unknown type 0x%02x with %d bytes data\n",
+							type, len);
+		break;
+	}
+}
+
+static inline void ext_inquiry_response_dump(int level, struct frame *frm)
+{
+	void *ptr = frm->ptr;
+	uint32_t len = frm->len;
+	uint8_t length;
+
+	length = get_u8(frm);
+
+	while (length > 0) {
+		ext_inquiry_data_dump(level, frm, frm->ptr);
 
 		frm->ptr += length;
 		frm->len -= length;
@@ -3504,14 +3520,12 @@ static inline void evt_le_conn_complete_dump(int level, struct frame *frm)
 
 static inline void evt_le_advertising_report_dump(int level, struct frame *frm)
 {
-	uint8_t num = get_u8(frm);
-	char addr[18];
-	int i;
+	uint8_t num_reports = get_u8(frm);
+	const uint8_t RSSI_SIZE = 1;
 
-	for (i = 0; i < num; i++) {
+	while (num_reports--) {
+		char addr[18];
 		le_advertising_info *info = frm->ptr;
-		void *ptr = frm->ptr;
-		uint32_t len = frm->len;
 
 		p_ba2str(&info->bdaddr, addr);
 
@@ -3522,13 +3536,15 @@ static inline void evt_le_advertising_report_dump(int level, struct frame *frm)
 		printf("bdaddr %s (%s)\n", addr,
 					bdaddrtype2str(info->bdaddr_type));
 
-		frm->ptr += LE_ADVERTISING_INFO_SIZE;
-		frm->len -= LE_ADVERTISING_INFO_SIZE;
+		if (info->length > 0) {
+			ext_inquiry_data_dump(level, frm, &info->length + 1);
+		}
 
-		ext_inquiry_response_dump(level, frm);
+		frm->ptr += LE_ADVERTISING_INFO_SIZE + info->length + RSSI_SIZE;
+		frm->len -= LE_ADVERTISING_INFO_SIZE + info->length + RSSI_SIZE;
 
-		frm->ptr = ptr + 1;
-		frm->len = len - 1;
+		p_indent(level, frm);
+		printf("RSSI: %d\n", ((int8_t *) frm->ptr)[frm->len - 1]);
 	}
 }
 
-- 
1.7.1


^ permalink raw reply related

* RE: [PATCH 00/11] mfd and bluetooth: Add CG2900 suppor
From: Par-Gunnar HJALMDAHL @ 2011-02-24 14:16 UTC (permalink / raw)
  To: Par-Gunnar HJALMDAHL, Arnd Bergmann, Pavan Savoy
  Cc: Vitaly Wool, Linus Walleij, Alan Cox, Samuel Ortiz,
	Marcel Holtmann, linux-kernel@vger.kernel.org,
	linux-bluetooth@vger.kernel.org, Lukasz Rymanowski,
	Par-Gunnar Hjalmdahl, Lee Jones
In-Reply-To: <201101091955.05174.arnd@arndb.de>

SGksDQoNCkkgc2VudCB0aGUgbWFpbCBiZWxvdyBvbmUgbW9udGggYWdvLCBidXQgaGF2ZSBzdGls
bCBub3QgcmVjZWl2ZWQgYW55IGFuc3dlcnMgb3IgZnVydGhlciBjb21tZW50cy4NCkhhcyBhbnlv
bmUgb2YgeW91IHdobyBtYWRlIGNvbW1lbnRzIG9uIHRoZSBDRzI5MDAgcGF0Y2hlcyBlYXJsaWVy
LCBhbnkgbW9yZSBjb21tZW50cyBvciBxdWVzdGlvbnM/DQoNCkl0IGlzIHVuY2xlYXIgdG8gbWUg
d2hlcmUgd2Ugc3RhbmQgd2l0aCB0aGUgQ0cyOTAwIHBhdGNoZXMuIEkgYW0gbXlzZWxmIGhhcHB5
IHdpdGggdGhlIGN1cnJlbnQgYXJjaGl0ZWN0dXJlLCBidXQgSSB1bmRlcnN0YW5kIHRoZXJlIGFy
ZSBkaWZmZXJpbmcgb3BpbmlvbnMuDQpJIHdvdWxkIGxpa2UgdG8ga25vdyB3aGF0IHdlIG5lZWQg
dG8gZG8gaW4gb3JkZXIgdG8gZ2V0IHRoaXMgZHJpdmVyIGludG8gdGhlIExpbnV4IEtlcm5lbCB0
cmVlLg0KDQovUC1HDQoNCj4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gRnJvbTogUGFy
LUd1bm5hciBISkFMTURBSEwNCj4gU2VudDogZGVuIDE3IGphbnVhcmkgMjAxMSAxNjozMw0KPiBU
bzogJ0FybmQgQmVyZ21hbm4nOyBQYXZhbiBTYXZveQ0KPiBDYzogVml0YWx5IFdvb2w7IExpbnVz
IFdhbGxlaWo7IEFsYW4gQ294OyBTYW11ZWwgT3J0aXo7IE1hcmNlbA0KPiBIb2x0bWFubjsgbGlu
dXgta2VybmVsQHZnZXIua2VybmVsLm9yZzsgbGludXgtDQo+IGJsdWV0b290aEB2Z2VyLmtlcm5l
bC5vcmc7IEx1a2FzeiBSeW1hbm93c2tpOyBQYXItR3VubmFyIEhqYWxtZGFobA0KPiBTdWJqZWN0
OiBSRTogW1BBVENIIDAwLzExXSBtZmQgYW5kIGJsdWV0b290aDogQWRkIENHMjkwMCBzdXBwb3IN
Cj4gDQo+IEhpLA0KPiANCj4gU29ycnkgZm9yIG5vdCBhbnN3ZXJpbmcgZWFybGllci4gSSd2ZSBi
ZWVuIG92ZXJsb2FkZWQgd2l0aCB0aGluZ3MgdG8gZG8NCj4gbm93IGFmdGVyIE5ldyBZZWFyLiBT
ZWUgYmVsb3cuDQo+IA0KPiA+IC0tLS0tT3JpZ2luYWwgTWVzc2FnZS0tLS0tDQo+ID4gRnJvbTog
QXJuZCBCZXJnbWFubiBbbWFpbHRvOmFybmRAYXJuZGIuZGVdDQo+ID4gU2VudDogZGVuIDkgamFu
dWFyaSAyMDExIDE5OjU1DQo+ID4gVG86IFBhdmFuIFNhdm95DQo+ID4gQ2M6IFBhci1HdW5uYXIg
SEpBTE1EQUhMOyBWaXRhbHkgV29vbDsgTGludXMgV2FsbGVpajsgQWxhbiBDb3g7DQo+IFNhbXVl
bA0KPiA+IE9ydGl6OyBNYXJjZWwgSG9sdG1hbm47IGxpbnV4LWtlcm5lbEB2Z2VyLmtlcm5lbC5v
cmc7IGxpbnV4LQ0KPiA+IGJsdWV0b290aEB2Z2VyLmtlcm5lbC5vcmc7IEx1a2FzeiBSeW1hbm93
c2tpOyBQYXItR3VubmFyIEhqYWxtZGFobA0KPiA+IFN1YmplY3Q6IFJlOiBbUEFUQ0ggMDAvMTFd
IG1mZCBhbmQgYmx1ZXRvb3RoOiBBZGQgQ0cyOTAwIHN1cHBvcg0KPiA+DQo+ID4gT24gU3VuZGF5
IDA5IEphbnVhcnkgMjAxMSwgUGF2YW4gU2F2b3kgd3JvdGU6DQo+ID4gPiBPbiBGcmksIEphbiA3
LCAyMDExIGF0IDEyOjE2IEFNLCBBcm5kIEJlcmdtYW5uIDxhcm5kQGFybmRiLmRlPg0KPiB3cm90
ZToNCj4gPiA+ID4gT24gV2VkbmVzZGF5IDA1IEphbnVhcnkgMjAxMSwgUGFyLUd1bm5hciBISkFM
TURBSEwgd3JvdGU6DQo+ID4gPiA+DQo+ID4gPiA+PiBTb3JyeSBmb3Igbm90IGFuc3dlcmluZyBz
b29uZXIuIEkndmUgYmVlbiBvbiBDaHJpc3RtYXMgYW5kIE5ldw0KPiA+IFllYXIgdmFjYXRpb24u
DQo+ID4gPiA+DQo+ID4gPiA+IEknbSBhbHNvIHN0aWxsIGNhdGNoaW5nIHVwIHdpdGggZW1haWwg
dGhhdCBoYXMgYWNjdW11bGF0ZWQgb3Zlcg0KPiBteQ0KPiA+ID4gPiB2YWNhdGlvbiwgaW5jbHVk
aW5nIHlvdXIgcHJldmlvdXMgcmVzcG9uc2UuDQo+ID4gPiA+DQo+ID4gPiA+IFRoaXMgc291bmRz
IHdyb25nIGZvciBib3RoIFRJIGFuZCBTVC1FOiBBRkFJQ1QgdGhleSBhcmUgYWN0dWFsbHkNCj4g
PiBidWlsdA0KPiA+ID4gPiBhcm91bmQgYW4gSENJIGludGVyZmFjZS4gSXQncyB1bmZvcnR1bmF0
ZSB0aGF0IHRoZSBUSSBjb2RlDQo+IGFjdHVhbGx5DQo+ID4gZ290DQo+ID4gPiA+IG1lcmdlZCBp
bnRvIHRoZSBrZXJuZWwgbGlrZSB0aGlzLg0KPiA+ID4NCj4gPiA+IEkgYW0gbm90IHN1cmUgd2hh
dCBkb2VzIGJ1aWx0IGFyb3VuZCBIQ0kgSW50ZXJmYWNlIG1lYW4/IEFsc28geWVzLA0KPiBpbg0K
PiA+IFRJLSBjb2RlDQo+ID4gPiB3ZSBkbyByZWZlciB0byBCbHVldG9vdGggaGVhZGVycy4NCj4g
PiA+IEhvd2V2ZXIgdGhlIGZhY3QgdGhhdCBJIHdhbnRlZCB0byBwb2ludCBvdXQgdG8gUGFyLUd1
bm5hciB3YXMsIHRoYXQNCj4gPiB3ZQ0KPiA+ID4gZG9uJ3Qgd2FudCB0byB1c2UNCj4gPiA+IGhj
aWF0dGFjaCBhbmQgZW5hYmxlIEhDSS1VQVJUICsgSENJLUg0IGZvciBlbmFibGluZyBvdXIgZHJp
dmVyIG9yDQo+IG91cg0KPiA+ID4gZHJpdmVyIHNob3VsZCBub3QNCj4gPiA+IGRlcGVuZCBvbiB0
aG9zZSBtb2R1bGVzIGFzIHN1Y2guLi4NCj4gPg0KPiA+IEdvb2QgcG9pbnQgYWJvdXQgaGNpYXR0
YWNoLCB5b3UgY2VydGFpbmx5IHNob3VsZG4ndCBuZWVkIHRvIHVzZSB0aGF0DQo+IGlmDQo+ID4g
dGhlIGtlcm5lbCBhbHJlYWR5IGtub3dzIHRoYXQgYSB0dHkgaXMgY29ubmVjdGVkIHRvIGFuIEhD
SSBhbmQgd2hhdA0KPiB0aGUNCj4gPiBwYXJhbWV0ZXJzIGFyZS4gRXZlbiBtb3JlIHNvIGlmIHRo
ZSBIQ0kgaXMgbm90IGFjdHVhbGx5IG9uIGEgcnMyMzINCj4gbGluZQ0KPiA+IGJ1dCBzb21ldGhp
bmcgbGlrZSBpMmMgb3Igc3BpLiBBdXRvbWF0aWNhbGx5IGJpbmRpbmcgdG8gdGhlIHJpZ2h0DQo+
IGxpbmUNCj4gPiBkaXNjaXBsaW5lIHNob3VsZCBiZSBlYXNpbHkgZG9hYmxlIGluIHRoZSBkcml2
ZXJzIHRob3VnaC4NCj4gPg0KPiANCj4gV2hlbiBoYXZpbmcgVUFSVCBhcyB0cmFuc3BvcnQgeW91
IG5lZWQgc29tZXRoaW5nIHRvIG9wZW4gdGhlIFVBUlQgYW5kDQo+IHNldCB0aGUgbGluZSBkaXNj
aXBsaW5lLiBJZiB0aGlzIGlzIGhjaWF0dGFjaCBvciBzb21ldGhpbmcgZWxzZSBpcyB1cA0KPiB0
byBlYWNoIGRldmVsb3BlciB0byBzdWl0IHdoYXQgdGhleSBhcmUgZG9pbmcuIEkgZG9uJ3Qgc2Vl
IGEgcHJvYmxlbQ0KPiB3aXRoIHVzaW5nIGhjaWF0dGFjaCBldmVuIGlmIHlvdSBkb24ndCB1c2Ug
dGhlIEJsdWV0b290aCBwYXJ0IChpZiB0aGUNCj4gZXhlIGlzIHBhcnQgb2YgdGhlIHN5c3RlbSBh
bnl3YXkpLCBidXQgaWYgYSBjb21wYW55L2RldmVsb3BlciB3YW50IHRvDQo+IHVzZSBzb21ldGhp
bmcgZWxzZSB0aGV5IGNhbiBkbyB0aGF0LiBJdCdzIGEgdXNhZ2Ugb2Ygc3RhbmRhcmQNCj4gaW50
ZXJmYWNlcyB1c2luZyBvcGVuKCkgYW5kIGlvY3RsKCkuDQo+IEkgc3RpbGwgZG9uJ3QgdGhpbmsg
dGhhdCB5b3Ugc2hvdWxkIGhhdmUgYSBsaW5lIGRpc2NpcGxpbmUgZm9yIG90aGVyDQo+IHRyYW5z
cG9ydHMgdGhhbiBVQVJULiBJZiBJIHdvdWxkIGxvb2sgYXQgaG93IEkgd291bGQgaW1wbGVtZW50
IGFuIFNQSQ0KPiBkcml2ZXIgZm9yIENHMjkwMCwgdGhlcmUgd291bGQgYWxtb3N0IGJlIG5vIGNv
ZGUgdGhhdCBjb3VsZCBiZSB1c2VkIGluDQo+IGNvbW1vbiBiZXR3ZWVuIGNnMjkwMF91YXJ0IGFu
ZCBjZzI5MDBfc3BpLiBTUEkgZG9lc24ndCBjaGFuZ2UgYmF1ZA0KPiByYXRlLCBTUEkgdXNlcyBj
b21tYW5kcyBmb3Igc2xlZXAvd2FrZSBpbnN0ZWFkIG9mIEJyZWFrLCBTUEkgcGFja2V0cw0KPiBk
b2Vzbid0IG5lZWQgZXh0cmEgcGFja2V0aXppbmcsIGV0Yy4NCj4gDQo+ID4gSSBkb24ndCB1bmRl
cnN0YW5kIHRoZSBwcm9ibGVtIHdpdGggcmVseWluZyBvbiB0aGUgaGNpLXVhcnQgb3IgaGNpLWg0
DQo+ID4gbW9kdWxlcy4gSWYgdGhlIGhhcmR3YXJlIHVzZXMgdGhlIEg0IHByb3RvY29sLCB3ZSBj
ZXJ0YWlubHkgc2hvdWxkDQo+IHVzZQ0KPiA+IHRoZSBrZXJuZWwgbW9kdWxlIHRoYXQga25vd3Mg
aG93IHRvIGRlYWwgd2l0aCBINCwgYW5kIHdlIGRvbid0IHdhbnQNCj4gPiB0byBoYXZlIHR3byBt
b2R1bGVzIGltcGxlbWVudGluZyB0aGUgc2FtZSBwcm90b2NvbC4NCj4gPg0KPiANCj4gSSBtdXN0
IHNheSBJIGRvbid0IHVuZGVyc3RhbmQgdGhpcyBwcm9ibGVtIGVpdGhlci4gVW5sZXNzIHRoZSBw
cm90b2NvbA0KPiBkcml2ZXIgaXMgYWN0aXZhdGVkIHRocm91Z2ggaW9jdGwgU0VUX1BST1RPQ09M
LCB0aGUgY29kZSB3aWxsIG5vdCBiZQ0KPiBleGVjdXRlZCwgYW5kIHRoZSBhbW91bnQgb2YgUk9N
IG5lZWRlZCBpcyBuZWdsaWdpYmxlLg0KPiBJZiB5b3UgbG9vayBhdCBvdXIgc3VibWlzc2lvbiwg
dGhlIGhjaS1oNCBjb3VsZCBwb3NzaWJseSBiZSByZXVzZWQgdG8NCj4gc29tZSBleHRlbnQuIEJh
c2ljYWxseSB0aGUgcGFja2V0aXppbmcgdG8gdGhlIEJsdWV0b290aCBINCBjaGFubmVscyAxLTQN
Cj4gY291bGQgYmUgcmUtdXNlZC4gSW4gb3JkZXIgdG8gYWxsb3cgZm9yIHZlbmRvciBzcGVjaWZp
YyBjaGFubmVscyB0byBiZQ0KPiBoYW5kbGVkIHNvbWUgbmV3IHJlZ2lzdHJhdGlvbiBzeXN0ZW0g
b24gdG9wIG9mIGhjaS1oNCBwbHVzIGEgY2FsbGJhY2sNCj4gc3lzdGVtIGZvciBkYXRhIHJlY2Vw
dGlvbiB3b3VsZCBoYXZlIHRvIGJlIGFkZGVkIChpbiBvcmRlciB0bw0KPiBmYWNpbGl0YXRlIHN5
c3RlbXMgdGhhdCBkbyBub3Qgd2FudCBhbGwgZGF0YSB0byBiZSBzZW50IGRpcmVjdGx5IHRvIHRo
ZQ0KPiBCbHVldG9vdGggc3RhY2sgc3VjaCBhcyB0aGUgQ0cyOTAwIGRyaXZlcikuIEknbSBhZnJh
aWQgdGhhdCB3ZSB3b3VsZA0KPiBoYXZlIGEgc2lnbmlmaWNhbnRseSBtb3JlIGNvbXBsZXggc3lz
dGVtIGFuZCBsYXJnZXIgYW1vdW50IG9mIGNvZGUgaWYNCj4gd2Ugd291bGQgdHJ5IHRvIGdlbmVy
YWxpemUgdGhlIGhjaS1oNCBtb2R1bGUuIEkgZGVmaW5pdGVseSBwcmVmZXIgdGhlDQo+IGN1cnJl
bnQgbW9kZWwgd2hlcmUgYSB2ZW5kb3Igc3BlY2lmaWMgZHJpdmVyIHJlcGxhY2VzIHRoZSBoY2kt
aDQNCj4gcHJvdG9jb2wgZHJpdmVyLg0KPiANCj4gPiA+ID4+ID4gaW5zdGVhZCBvZiBjb21tb24t
aGNpLW1vZHVsZSwgd2h5IG5vdCBjcmVhdGUgYSBhbGdvLWRyaXZlcg0KPiBsYXllcg0KPiA+ICdh
bGENCj4gPiA+ID4+ID4gaTJjID8gd2hlcmUgaW5kaXZpZHVhbCBkcml2ZXJzIGNhbiByZWdpc3Rl
ciB0aGVpciByZWNlaXZlDQo+ID4gaGFuZGxlcnMgZm9yDQo+ID4gPiA+PiA+IGRhdGEgaW50ZXJw
cmV0YXRpb24gPw0KPiA+ID4gPg0KPiA+ID4gPiBUaGF0IHdvdWxkIGJlIHdoYXQgSSBzdWdnZXN0
ZWQgOy0pDQo+ID4gPg0KPiA+ID4gQnV0IGV2ZW4gaGVyZSB0b28sIHRoZSBhbGdvcyBsYXllciBp
ZiB5b3UgaW1hZ2luZSB3aGljaCBjYW4gYmUgdGhlDQo+ID4gPiBzb3J0IG9mIHRoZSBmaXJzdA0K
PiA+ID4gcmVjZWl2ZXIgb2YgZGF0YSBmcm9tIHRoZSB0cmFuc3BvcnQgd291bGQgcmVmZXIgdG8g
QlQgaGVhZGVycyB0bw0KPiA+ID4gaW50ZXJwcmV0IHRoZSBkYXRhIChub3QganVzdCBCVCwgYnV0
IEZNL0dQUykNCj4gPiA+IGFuZCBwYXNzIGl0IG9udG8gb3RoZXIgcHJvdG9jb2wvY2xpZW50IGRy
aXZlcnMsDQo+ID4NCj4gPiBSaWdodCwgdGhhdCBpcyB0aGUgZW50aXJlIGlkZWEsIGFuZCBJIGRv
bid0IHNlZSBhIHByb2JsZW0gaGVyZS4NCj4gPiBJZiB5b3UgZG8gdGhpcywgeW91IHVzZSB0aGUg
aGVhZGVycyBvZiB0aGUgdHdvIHN1YnN5c3RlbXMgeW91DQo+ID4gaW50ZXJmYWNlIHdpdGguIFdo
YXQgeW91IHNob3VsZCAvbm90LyBpbnN0ZWFkIGlzIHVzZSBoZWFkZXINCj4gPiBmaWxlcyBvZiBh
IHN1YnN5c3RlbSB5b3UgZG9uJ3QgaW50ZXJmYWNlIHdpdGggYW5kIHJlaW50ZXJwcmV0ZQ0KPiA+
IHRoZSBkZWZpbml0aW9ucyBpbiBjcmVhdGl2ZSB3YXlzLCB3aGljaCBpcyB3aGF0IEkgdW5kZXJz
dG9vZA0KPiA+IHdhcyBiZWluZyBkaXNjdXNzZWQgZWFybGllci4NCj4gPg0KPiA+ID4gPj4gSW4g
c29tZSB3YXkgeW91IHRoZW4gcnVuIGludG8gdGhlIHNhbWUgcHJvYmxlbSBoYXMgSSBoYWQgaW4N
Cj4gPiBwcmV2aW91cyBwYXRjaA0KPiA+ID4gPj4gc2V0cy4gVGhlIGZ1bmN0aW9uYWxpdGllcyBz
dXBwb3J0ZWQgaXMgcmVhbGx5IGRldGVybWluZWQgYnkgZWFjaA0KPiA+IGNoaXAuDQo+ID4gPiA+
PiBZb3UgbWlnaHQgb3IgbWlnaHQgbm90IGhhdmUgZm9yIGV4YW1wbGUgR1BTIGluIGEgY2VydGFp
biBjaGlwLg0KPiBTbw0KPiA+IHlvdSBkbyBub3QNCj4gPiA+ID4+IHdhbnQgYSBjZW50cmFsIG1v
ZHVsZSB0byBleHBvc2UgYWxsIHBvc3NpYmxlIGNoYW5uZWxzIHRvIHRoZQ0KPiA+IHN0YWNrcyBv
biB0b3AuDQo+ID4gPiA+Pg0KPiA+ID4gPj4gWW91IG9ubHkgd2FudCB0aGUgYWN0dWFsbHkgc3Vw
cG9ydGVkIGZlYXR1cmVzIHRvIGJlIGV4cG9zZWQgdG8NCj4gPiB1cHBlciBsYXllcnMuDQo+ID4g
PiA+PiBUaGVuIHRoZSBNRkQgc3lzdGVtIGlzIHByZXR0eSBuaWNlLiBJdCdzIGVhc3kgYW5kIG1v
ZHVsYXJpemVkIHRvDQo+ID4gZXhwb3NlIHRoZQ0KPiA+ID4gPj4gZGlmZmVyZW50IGNoYW5uZWxz
IGFzIE1GRCBjZWxscy4NCj4gPiA+ID4NCj4gPiA+ID4gQnV0IGFzIHNvb24gYXMgeW91IGhhdmUg
dGhlIGNvbmNlcHQgb2YgY2hhbm5lbHMgd2l0aCBhIGNsZWFybHkNCj4gPiBkZWZpbmVkDQo+ID4g
PiA+IGludGVyZmFjZSwgeW91IGhhdmUgYWxtb3N0IGFic3RyYWN0ZWQgaXQgZW5vdWdoIHRvIGdv
IGFsbCB0aGUNCj4gd2F5Lg0KPiA+ID4NCj4gPiA+IFNvbWV0aGluZyBsaWtlIHRoaXMgaXMgd2hh
dCB0aGUgcmVjZW50IFJGQyBwb3N0ZWQgdG8NCj4gPiA+IGxrbWwvbGludXgtYmx1ZXRvb3RoDQo+
ID4gPiBodHRwOi8vd3d3LnNwaW5pY3MubmV0L2xpc3RzL2xpbnV4LWJsdWV0b290aC9tc2cwOTk5
MC5odG1sLA0KPiA+ID4gaXQga2luZGEgbG9va3MgY2x1bXN5DQo+ID4gPiBidXQgd2hhdCBJIGZl
ZWwgaXMgd2Ugc2hvdWxkbid0IHNoeSBhd2F5IGZyb20gbm90IHJlZmVyZW5jaW5nDQo+ID4gPiBC
bHVldG9vdGgsIChvciBtYXkgYmUgdG9tb3Jyb3cgR1BTDQo+ID4gPiB3aXRoIE5NRUEgaGVhZGVy
cykuLi4uDQo+ID4NCj4gPiBUaGUgb25lIGltcG9ydGFudCBnb2FsIGhlcmUgc2hvdWxkIGJlIHRv
IGF2b2lkIGNvZGUgZHVwbGljYXRpb24uDQo+ID4gVXNpbmcgdGhlIGhlYWRlciB0byBnZXQgdGhl
IGRhdGEgc3RydWN0dXJlcyBmcm9tIHNlcGFyYXRlIGNvZGUNCj4gPiBtZWFucyB5b3UgbmVlZCB0
byBoYXZlIHNpbWlsYXIgcGFyc2luZyBmdW5jdGlvbnMgaW4gZWFjaCBvZiB0aGUNCj4gbW9kdWxl
cw0KPiA+IHVzaW5nIGl0LiBOb3Qgc2hhcmluZyB0aGUgaGVhZGVyIHdvdWxkbid0IGhlbHAsIGJl
Y2F1c2UgdGhlbiB5b3UgZW5kDQo+ID4gdXAgZHVwbGljYXRpbmcgZXZlbiBtb3JlLiBUaGUgcmVh
bCBzb2x1dGlvbiwgc3BlYWtpbmcgdmVyeSBicm9hZGx5LA0KPiA+IG11c3QgYmUgdG8gaGF2ZSBh
IGdlbmVyYWwgbW9kdWxlIHRoYXQgZGVhbHMgd2l0aCB3aGF0ZXZlciB0aGUgbW9yZQ0KPiA+IHNw
ZWNpZmljIG1vZHVsZXMgaGF2ZSBpbiBjb21tb24sIGFuZCBoYXZlIGEgaGVhZGVyIGZpbGUgdGhh
dCBkZWZpbmVzDQo+ID4gdGhlIGludGVyZmFjZSB0byBpdC4NCj4gPg0KPiANCj4gSW4gZ2VuZXJh
bCBJIGFncmVlIHdpdGggeW91LCBidXQgdGhlcmUgYXJlIHNvbWUgcHJvYmxlbXMgaGVyZS4NCj4g
VGhlIG1vc3QgdXNlZCBCVCBIQ0kgZXZlbnRzIGFyZSBDb21tYW5kIFN0YXR1cyBhbmQgQ29tbWFu
ZCBDb21wbGV0ZS4NCj4gQ29tbWFuZCBTdGF0dXMgY291bGQgYmUgcGFyc2VkIGNvbXBsZXRlbHkg
aW4gYSBnb29kIHdheSAocmV0cmlldmluZyBvcA0KPiBjb2RlLCBuYnIgb2YgY29tbWFuZHMgYWxs
b3dlZCwgYW5kIHN0YXR1cyBvZiBjb21tYW5kIHNlbnQpLg0KPiBDb21tYW5kIENvbXBsZXRlIGlz
IGhvd2V2ZXIgcXVpdGUgY29tcGxleCBzaW5jZSB0aGUgcmV0dXJuZWQgZGF0YSB3aWxsDQo+IGRp
ZmZlciBkZXBlbmRpbmcgb24gY29tbWFuZCBzZW50LiBPcCBjb2RlIGFuZCBuYnIgb2YgY29tbWFu
ZHMgYWxsb3dlZA0KPiBjYW4gYmUgcmV0cmlldmVkIGJ1dCBldmVyeXRoaW5nIGVsc2UgaGF2ZSB0
byBiZSBleHRyYWN0ZWQgZGlmZmVyZW50bHkNCj4gZGVwZW5kaW5nIG9uIGNvbW1hbmQuIFRoaXMg
bWVhbnMgdGhhdCB0aGVyZSBpcyBub3QgbXVjaCB0aGF0IHdpbGwgYmUNCj4gc2F2ZWQgaGVyZS4g
QnV0IG1heWJlIHdlIGNvdWxkIGV4dHJhY3Qgc29tZSBwYXJzaW5nIGludG8gY29tbW9uDQo+IGZ1
bmN0aW9ucywgYnV0IEkgZG9uJ3QgdGhpbmsgeW91IHdvdWxkIGdhaW4gdGhhdCBtdWNoLg0KPiBN
b3Jlb3ZlciwgdGhpcyB3b3VsZCBsZWFkIHRvIGEgbWFqb3IgcmVpbXBsZW1lbnRhdGlvbiBvZiB0
aGUgaGNpX2NvcmUuYw0KPiBhbmQgcmVsYXRlZCBmaWxlcywgc2luY2UgdGhleSBkbyBub3QgdXNl
IGFueSBleHBvcnRlZCBjb21tb24gZnVuY3Rpb25zDQo+IGFzIGl0IGlzIHRvZGF5LiBJIGRvIG5v
dCBrbm93IGlmIHRoZXkgKEJsdWVaIGNvbW11bml0eSkgd291bGQgd2FudCB0aGlzDQo+IGFuZCBJ
IGRvIG5vdCB0aGluayB0aGF0IHRoYXQgc2hvdWxkIGJlIHBhcnQgb2YgdGhlIENHMjkwMCBkcml2
ZXIgdG8gZG8uDQo+IEl0IHNob3VsZCBpbiB0aGF0IGNhc2UgYmUgZG9uZSBzZXBhcmF0ZWx5Lg0K
PiANCj4gPiA+ID4+IEFsc28gbm90ZSB0aGF0IHRoZSBjb21tb24taGNpLW1vZHVsZSBpcyBvbmx5
IHJlYWxseSB1c2VkIHVudGlsDQo+IHRoZQ0KPiA+IGNvbm5lY3RlZA0KPiA+ID4gPj4gY2hpcCBo
YXMgYmVlbiBkZXRlY3RlZC4gVGhlIGNoaXAgaGFuZGxlciB3aWxsIHRoZW4gc2V0IHRoZQ0KPiA+
IGNhbGxiYWNrIGZ1bmN0aW9ucw0KPiA+ID4gPj4gc28gYWN0dWFsIGRhdGEgdHJhbnNtaXNzaW9u
cyBuZXZlciBwYXNzIHRoZSBjb21tb24taGNpLW1vZHVsZS4NCj4gPiBUaGV5IGdvIGRpcmVjdGx5
DQo+ID4gPiA+PiBmcm9tIHRyYW5zcG9ydCB0byBjaGlwIGhhbmRsZXIuIFRoYXQgaXMgbm90IHJl
YWxseSBzaG93biBpbiB0aGUNCj4gPiBwaWN0dXJlIGFib3ZlLg0KPiA+ID4gPj4gSnVzdCBpbWFn
aW5lIHRoYXQgY29tbW9uLWhjaS1tb2R1bGUgaXMgcmVtb3ZlZCBhZnRlciBhIGNoaXAgaGFzDQo+
ID4gYmVlbiBjb25uZWN0ZWQNCj4gPiA+ID4+IGFuZCBhIGNoaXAgaGFuZGxlciBoYXMgYmVlbiBk
ZXRlcm1pbmVkLg0KPiA+ID4gPj4NCj4gPiA+ID4+IEkgaG9wZSBJIGhhdmVuJ3QgbWlzdW5kZXJz
dG9vZCB5b3VyIHF1ZXN0aW9uLiBJIGRvIG5vdCBrbm93IG11Y2gNCj4gPiBhYm91dCB0aGUgSTJD
DQo+ID4gPiA+PiBzeXN0ZW0sIGJ1dCBJIHRyaWVkIHRvIHVuZGVyc3RhbmQgeW91ciBxdWVzdGlv
biBhcyBiZXN0IGFzIEkNCj4gPiBjb3VsZC4NCj4gPiA+ID4NCj4gPiA+ID4gSSB0aGluayB0aGVy
ZSBpcyBhIGRpc2Nvbm5lY3Qgd2hlbiB0YWxraW5nIGFib3V0IGhpZXJhcmNoaWVzLCBhcw0KPiBp
dA0KPiA+IGNhbiBiZSBhcHBsaWVkDQo+ID4gPiA+IHRvIGRpZmZlcmVudCBhcmVhczoNCj4gPiA+
ID4NCj4gPiA+ID4gKiBtb2R1bGUgZGVwZW5kZW5jaWVzDQo+ID4gPiA+ICogZGV2aWNlIGRldGVj
dGlvbg0KPiA+ID4gPiAqIHN5c2ZzIG9iamVjdCBoaWVyYXJjaHkNCj4gPiA+ID4gKiBkYXRhIGZs
b3cNCj4gPiA+DQo+ID4gPiBtb2R1bGUgZGVwZW5kZWN5LXdpc2UgSSBhZ3JlZSwNCj4gPiA+IEkg
d291bGQgd2FudCBGTS1WNEwyIHdpdGhvdXQgQlQgb3IgSSBtaWdodCB3YW50IEdQUyBzaW1wbGlz
dGljIGNoYXINCj4gPiA+IGRyaXZlciB3aXRob3V0IEJUIG9yIEZNIFY0TDIuDQo+ID4NCj4gPiBC
dXQgeW91J2Qgc3RpbGwgbmVlZCB0byBoYXZlIGFuIEhDSSBtb2R1bGUuIEkgYmVsaWV2ZSByaWdo
dCBub3csIHRoZQ0KPiA+IGhjaSBtb2R1bGUgZGVwZW5kcyBvbiB0aGUgYmx1ZXRvb3RoIG1vZHVs
ZSwgYW5kIHlvdSBhcmUgcmlnaHQgdGhhdA0KPiB0aGlzDQo+ID4gaXMgYW4gdW5kZXNpcmFibGUg
ZGVwZW5kZW5jeSB0byBoYXZlIGZvciBhIEdQUyBtb2R1bGUuIEhvd2V2ZXIsIHRoZQ0KPiA+IHNv
bHV0aW9uDQo+ID4gdG8gdGhpcyBzaG91bGQgbm90IGJlIHRvIG1ha2UgR1BTIGluZGVwZW5kZW50
IG9mIEhDSSwgYnV0IHRvIG1ha2UNCj4gcGFydHMNCj4gPiBvZiBIQ0kgaW5kZXBlbmRlbnQgb2Yg
Ymx1ZXRvb3RoLg0KPiA+DQo+IA0KPiBGb3IgdGhlIENHMjkwMCB0aGF0IGlzIG5vdCBwb3NzaWJs
ZS4gRXZlbiBpZiB5b3UgYXJlIHJ1bm5pbmcganVzdCBHUFMNCj4geW91IHN0aWxsIG11c3QgZG93
bmxvYWQgcGF0Y2hlcyBhbmQgc2V0dGluZ3MgYW5kIHRoYXQgaXMgZG9uZSB0aHJvdWdoDQo+IEhD
SSBjb21tYW5kcyBvdmVyIHRoZSBCbHVldG9vdGggY29tbWFuZCBpbnRlcmZhY2UuIFdlIGFsc28g
dXNlDQo+IEJsdWV0b290aCBjb21tYW5kcyB0byBpZGVudGlmeSB0aGUgY29udHJvbGxlci4NCj4g
DQo+ID4gPiBkZXZpY2UgZGV0ZWN0aW9uIHdpc2UsIEl0IGlzIGEgcHJvYmxlbSwgdGhlcmUgaXMg
bm90ICJfcHJvYmUiDQo+ID4gPiBtZWNoYW5pc20gZm9yIFVBUlQgYmFzZWQgdHJhbnNwb3J0IGFz
IGl0IGlzDQo+ID4gPiB1bmRlcnN0YW5kYWJsZSwgYW5kIHByZXR0eSBtdWNoIHRoZSBkcml2ZXIg
d291bGQgZW5kIHVwIGJlaW5nDQo+ID4gcGxhdGZvcm0NCj4gPiA+IGRldmljZSBkcml2ZXIgLi4u
DQo+ID4NCj4gPiBUaGUgcGxhdGZvcm0gZGV2aWNlIGlzIGp1c3QgdGhlIGxvd2VzdCBsZXZlbCBp
biB0aGUgZGV2aWNlIGhpZXJhcmNoeS4NCj4gPg0KPiA+IElmIGVhY2ggSENJIGNoYW5uZWwgaXMg
YSBkZXZpY2UsIHlvdSBjYW4gc3RhY2sgYnQsIGdwcywgYXVkaW8sIC4uLg0KPiA+IGRldmljZXMg
YWxsIG9uIHRvcCBvZiB0aGUgSENJIGRldmljZSwgd2hpY2ggaXMgZWl0aGVyIHN0YWNrZWQgb24g
dG9wDQo+ID4gb2YgYSBzZXJpYWwgcG9ydCBvciBpbiBzb21lIG90aGVyIHdheSBjb25uZWN0ZWQg
dG8gdGhlIHVuZGVyeWluZw0KPiA+IHRyYW5zcG9ydC4NCj4gPg0KPiA+IEluIHRoaXMgY2FzZSwg
dGhlIGNoYW5uZWxzIHRoZW1zZWx2ZXMgYXJlIG5vdCBwbGF0Zm9ybSBkZXZpY2VzLCBidXQNCj4g
PiB3b3VsZCBnZXQgYSBuZXcgYnVzIGZvciB0aGVtLiBUaGF0IGJ1cyBpcyBwb3B1bGF0ZWQgYnkg
YSBkcml2ZXIgdGhhdA0KPiA+IG93bnMgdGhlIEhDSSBhbmQgdGhhdCBrbm93cyAoZS5nLiBmcm9t
IGl0cyBwbGF0Zm9ybSBkYXRhLCBoYXJkd2FyZQ0KPiA+IHJlZ2lzdGVycywgdXNlciBjb25maWcg
b3IgZGV2aWNlIHRyZWUpIHdoYXQgY2hhbm5lbHMgYXJlIHByZXNlbnQuDQo+ID4NCj4gPiA+IGRh
dGEgZmxvdyBpcyB3aGVyZSBJIGd1ZXNzIHRoZSBhYnN0cmFjdGlvbiBoYXMgdG8gbGllIGluLCBm
b3INCj4gPiA+IGRpZmZlcmVudCB2ZW5kb3JzLi4uDQo+ID4NCj4gPiBJIGRvbid0IGtub3cgd2hh
dCB5b3UgbWVhbiB3aXRoIHRoYXQuIE15IHBvaW50IHdhcyB0aGF0IHdlIG5lZWQgdG8NCj4gPiBj
b25zaWRlciBhbGwgdGhlIGhpZXJhcmNoaWVzLCBhbmQgdGhhdCB0aGV5IG1pZ2h0IGJlIGRpZmZl
cmVudC4NCj4gPg0KPiA+IAlBcm5kDQo+IA0KPiAvUC1HDQoNCg==

^ permalink raw reply

* [PATCH v2] Add sec-level option to interactive gattool
From: Sheldon Demario @ 2011-02-24 13:59 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Sheldon Demario
In-Reply-To: <20110224025653.GB6189@jh-x301>

---
 attrib/interactive.c |   44 ++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 44 insertions(+), 0 deletions(-)

diff --git a/attrib/interactive.c b/attrib/interactive.c
index 368e5cf..30cef43 100644
--- a/attrib/interactive.c
+++ b/attrib/interactive.c
@@ -531,6 +531,48 @@ static void cmd_char_write_req(int argcp, char **argvp)
 	g_free(value);
 }
 
+static void cmd_sec_level(int argcp, char **argvp)
+{
+	GError *gerr = NULL;
+	BtIOSecLevel sec_level;
+
+	if (argcp < 2) {
+		printf("sec-level: %s\n", opt_sec_level);
+		return;
+	}
+
+	if (strcasecmp(argvp[1], "medium") == 0)
+		sec_level = BT_IO_SEC_MEDIUM;
+	else if (strcasecmp(argvp[1], "high") == 0)
+		sec_level = BT_IO_SEC_HIGH;
+	else if (strcasecmp(argvp[1], "low") == 0)
+		sec_level = BT_IO_SEC_LOW;
+	else {
+		printf("Allowed values: low | medium | high\n");
+		return;
+	}
+
+	g_free(opt_sec_level);
+	opt_sec_level = strdup(argvp[1]);
+
+	if (conn_state != STATE_CONNECTED)
+		return;
+
+	if (opt_psm) {
+		printf("It must be reconnected to this change take effect\n");
+		return;
+	}
+
+	bt_io_set(iochannel, BT_IO_L2CAP, &gerr,
+			BT_IO_OPT_SEC_LEVEL, sec_level,
+			BT_IO_OPT_INVALID);
+
+	if (gerr) {
+		printf("Error: %s\n", gerr->message);
+		g_error_free(gerr);
+	}
+}
+
 static struct {
 	const char *cmd;
 	void (*func)(int argcp, char **argvp);
@@ -557,6 +599,8 @@ static struct {
 		"Characteristics Value/Descriptor Read by UUID" },
 	{ "char-write-req",	cmd_char_write_req,	"<handle> <new value>",
 		"Characteristic Value Write (Write Request)" },
+	{ "sec-level",		cmd_sec_level,	"[low | medium | high]",
+		"Set security level. Default: low" },
 	{ NULL, NULL, NULL}
 };
 
-- 
1.7.1


^ permalink raw reply related

* [PATCH v3 5/7] Add characteristics read options in interactive gatttool
From: Sheldon Demario @ 2011-02-24 13:55 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Sheldon Demario
In-Reply-To: <1298328606-7993-1-git-send-email-sheldon.demario@openbossa.org>

---

Remove return statements at the end of void functions

 attrib/interactive.c |  143 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 142 insertions(+), 1 deletions(-)

diff --git a/attrib/interactive.c b/attrib/interactive.c
index b00d0bc..7f3f658 100644
--- a/attrib/interactive.c
+++ b/attrib/interactive.c
@@ -50,6 +50,13 @@ static gchar *opt_sec_level = NULL;
 static int opt_psm = 0;
 static int opt_mtu = 0;
 
+struct characteristic_data {
+	uint16_t orig_start;
+	uint16_t start;
+	uint16_t end;
+	uuid_t uuid;
+};
+
 static void cmd_help(int argcp, char **argvp);
 
 enum state {
@@ -210,6 +217,79 @@ static void char_desc_cb(guint8 status, const guint8 *pdu, guint16 plen,
 	rl_forced_update_display();
 }
 
+static void char_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
+							gpointer user_data)
+{
+	uint8_t value[ATT_MAX_MTU];
+	int i, vlen;
+
+	if (status != 0) {
+		printf("Characteristic value/descriptor read failed: %s\n",
+							att_ecode2str(status));
+		return;
+	}
+
+	if (!dec_read_resp(pdu, plen, value, &vlen)) {
+		printf("Protocol error\n");
+		return;
+	}
+
+	printf("\nCharacteristic value/descriptor: ");
+	for (i = 0; i < vlen; i++)
+		printf("%02x ", value[i]);
+	printf("\n");
+
+	rl_forced_update_display();
+}
+
+static void char_read_by_uuid_cb(guint8 status, const guint8 *pdu,
+					guint16 plen, gpointer user_data)
+{
+	struct characteristic_data *char_data = user_data;
+	struct att_data_list *list;
+	int i;
+
+	if (status == ATT_ECODE_ATTR_NOT_FOUND &&
+				char_data->start != char_data->orig_start)
+		goto done;
+
+	if (status != 0) {
+		printf("Read characteristics by UUID failed: %s\n",
+							att_ecode2str(status));
+		goto done;
+	}
+
+	list = dec_read_by_type_resp(pdu, plen);
+	if (list == NULL)
+		goto done;
+
+	for (i = 0; i < list->num; i++) {
+		uint8_t *value = list->data[i];
+		int j;
+
+		char_data->start = att_get_u16(value) + 1;
+
+		printf("\nhandle: 0x%04x \t value: ", att_get_u16(value));
+		value += 2;
+		for (j = 0; j < list->len - 2; j++, value++)
+			printf("%02x ", *value);
+		printf("\n");
+	}
+
+	att_data_list_free(list);
+
+	gatt_read_char_by_uuid(attrib, char_data->start, char_data->end,
+					&char_data->uuid, char_read_by_uuid_cb,
+					char_data);
+
+	rl_forced_update_display();
+
+	return;
+
+done:
+	g_free(char_data);
+}
+
 static void cmd_exit(int argcp, char **argvp)
 {
 	rl_callback_handler_remove();
@@ -344,6 +424,63 @@ static void cmd_char_desc(int argcp, char **argvp)
 	gatt_find_info(attrib, start, end, char_desc_cb, NULL);
 }
 
+static void cmd_read_hnd(int argcp, char **argvp)
+{
+	int handle;
+
+	if (conn_state != STATE_CONNECTED) {
+		printf("Command failed: disconnected\n");
+		return;
+	}
+
+	if (argcp < 2) {
+		printf("Missing argument: handle\n");
+		return;
+	}
+
+	if (strtohandle(&handle, argvp[1])) {
+		printf("Invalid handle: %s\n", argvp[1]);
+		return;
+	}
+
+	gatt_read_char(attrib, handle, char_read_cb, attrib);
+}
+
+static void cmd_read_uuid(int argcp, char **argvp)
+{
+	struct characteristic_data *char_data;
+	int start = 0x0001;
+	int end = 0xffff;
+	uuid_t uuid;
+
+	if (conn_state != STATE_CONNECTED) {
+		printf("Command failed: disconnected\n");
+		return;
+	}
+
+	if (argcp < 2) {
+		printf("Missing argument: UUID\n");
+		return;
+	}
+
+	if (bt_string2uuid(&uuid, argvp[1]) < 0) {
+		printf("Invalid UUID\n");
+		return;
+	}
+
+	if (set_handles(&start, &end, argcp - 1, argvp + 1))
+		return;
+
+	char_data = g_new(struct characteristic_data, 1);
+	char_data->orig_start = start;
+	char_data->start = start;
+	char_data->end = end;
+	char_data->uuid = uuid;
+
+	gatt_read_char_by_uuid(attrib, start, end, &char_data->uuid,
+					char_read_by_uuid_cb, char_data);
+}
+
 static struct {
 	const char *cmd;
 	void (*func)(int argcp, char **argvp);
@@ -364,6 +501,10 @@ static struct {
 		"Characteristics Discovery" },
 	{ "char-desc",		cmd_char_desc,	"[start hnd] [end hnd]",
 		"Characteristics Descriptor Discovery" },
+	{ "char-read-hnd",	cmd_read_hnd,	"<handle>",
+		"Characteristics Value/Descriptor Read by handle" },
+	{ "char-read-uuid",	cmd_read_uuid,	"<UUID> [start hnd] [end hnd]",
+		"Characteristics Value/Descriptor Read by UUID" },
 	{ NULL, NULL, NULL}
 };
 
@@ -372,7 +513,7 @@ static void cmd_help(int argcp, char **argvp)
 	int i;
 
 	for (i = 0; commands[i].cmd; i++)
-		printf("%-15s %-25s %s\n", commands[i].cmd,
+		printf("%-15s %-30s %s\n", commands[i].cmd,
 				commands[i].params, commands[i].desc);
 }
 
-- 
1.7.1


^ permalink raw reply related

* [PATCH v3 4/7] Add Characteristics Descriptor Discovery option in interactive gatttool
From: Sheldon Demario @ 2011-02-24 13:54 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Sheldon Demario
In-Reply-To: <1298328606-7993-1-git-send-email-sheldon.demario@openbossa.org>

---

Remove return statements at the end of void functions.

 attrib/interactive.c |   59 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 59 insertions(+), 0 deletions(-)

diff --git a/attrib/interactive.c b/attrib/interactive.c
index ed45894..b00d0bc 100644
--- a/attrib/interactive.c
+++ b/attrib/interactive.c
@@ -169,6 +169,47 @@ static void char_cb(GSList *characteristics, guint8 status, gpointer user_data)
 	rl_forced_update_display();
 }
 
+static void char_desc_cb(guint8 status, const guint8 *pdu, guint16 plen,
+							gpointer user_data)
+{
+	struct att_data_list *list;
+	guint8 format;
+	int i;
+
+	if (status != 0) {
+		printf("Discover all characteristic descriptors failed: "
+						"%s\n", att_ecode2str(status));
+		return;
+	}
+
+	list = dec_find_info_resp(pdu, plen, &format);
+	if (list == NULL)
+		return;
+
+	printf("\n");
+	for (i = 0; i < list->num; i++) {
+		char uuidstr[MAX_LEN_UUID_STR];
+		uint16_t handle;
+		uint8_t *value;
+		uuid_t uuid;
+
+		value = list->data[i];
+		handle = att_get_u16(value);
+
+		if (format == 0x01)
+			sdp_uuid16_create(&uuid, att_get_u16(&value[2]));
+		else
+			sdp_uuid128_create(&uuid, &value[2]);
+
+		sdp_uuid2strn(&uuid, uuidstr, MAX_LEN_UUID_STR);
+		printf("handle: 0x%04x, uuid: %s\n", handle, uuidstr);
+	}
+
+	att_data_list_free(list);
+
+	rl_forced_update_display();
+}
+
 static void cmd_exit(int argcp, char **argvp)
 {
 	rl_callback_handler_remove();
@@ -287,6 +328,22 @@ static void cmd_char(int argcp, char **argvp)
 	return;
 }
 
+static void cmd_char_desc(int argcp, char **argvp)
+{
+	int start = 0x0001;
+	int end = 0xffff;
+
+	if (conn_state != STATE_CONNECTED) {
+		printf("Command failed: disconnected\n");
+		return;
+	}
+
+	if (set_handles(&start, &end, argcp, argvp))
+		return;
+
+	gatt_find_info(attrib, start, end, char_desc_cb, NULL);
+}
+
 static struct {
 	const char *cmd;
 	void (*func)(int argcp, char **argvp);
@@ -305,6 +362,8 @@ static struct {
 		"Primary Service Discovery" },
 	{ "characteristics",	cmd_char,	"[start hnd] [end hnd]",
 		"Characteristics Discovery" },
+	{ "char-desc",		cmd_char_desc,	"[start hnd] [end hnd]",
+		"Characteristics Descriptor Discovery" },
 	{ NULL, NULL, NULL}
 };
 
-- 
1.7.1


^ permalink raw reply related

* [PATCH] Move index to common header in management interface
From: Szymon Janc @ 2011-02-24 13:36 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: par-gunnar.p.hjalmdahl, henrik.possung, Szymon Janc

Match changes introduced in mgmt interface after moving controller
index to common header.
---
 lib/mgmt.h        |   43 +---------
 plugins/mgmtops.c |  243 +++++++++++++++++++----------------------------------
 2 files changed, 90 insertions(+), 196 deletions(-)

diff --git a/lib/mgmt.h b/lib/mgmt.h
index b3eabac..7854ab1 100644
--- a/lib/mgmt.h
+++ b/lib/mgmt.h
@@ -25,11 +25,14 @@
 #define __packed __attribute__((packed))
 #endif
 
+#define MGMT_INDEX_NONE			0xFFFF
+
 struct mgmt_hdr {
 	uint16_t opcode;
+	uint16_t index;
 	uint16_t len;
 } __packed;
-#define MGMT_HDR_SIZE	4
+#define MGMT_HDR_SIZE	6
 
 #define MGMT_OP_READ_VERSION		0x0001
 struct mgmt_rp_read_version {
@@ -49,11 +52,7 @@ struct mgmt_rp_read_index_list {
 } __packed;
 
 #define MGMT_OP_READ_INFO		0x0004
-struct mgmt_cp_read_info {
-	uint16_t index;
-} __packed;
 struct mgmt_rp_read_info {
-	uint16_t index;
 	uint8_t type;
 	uint8_t powered;
 	uint8_t connectable;
@@ -69,7 +68,6 @@ struct mgmt_rp_read_info {
 } __packed;
 
 struct mgmt_mode {
-	uint16_t index;
 	uint8_t val;
 } __packed;
 
@@ -83,27 +81,23 @@ struct mgmt_mode {
 
 #define MGMT_OP_ADD_UUID		0x0009
 struct mgmt_cp_add_uuid {
-	uint16_t index;
 	uint8_t uuid[16];
 	uint8_t svc_hint;
 } __packed;
 
 #define MGMT_OP_REMOVE_UUID		0x000A
 struct mgmt_cp_remove_uuid {
-	uint16_t index;
 	uint8_t uuid[16];
 } __packed;
 
 #define MGMT_OP_SET_DEV_CLASS		0x000B
 struct mgmt_cp_set_dev_class {
-	uint16_t index;
 	uint8_t major;
 	uint8_t minor;
 } __packed;
 
 #define MGMT_OP_SET_SERVICE_CACHE	0x000C
 struct mgmt_cp_set_service_cache {
-	uint16_t index;
 	uint8_t enable;
 } __packed;
 
@@ -116,7 +110,6 @@ struct mgmt_key_info {
 
 #define MGMT_OP_LOAD_KEYS		0x000D
 struct mgmt_cp_load_keys {
-	uint16_t index;
 	uint8_t debug_keys;
 	uint16_t key_count;
 	struct mgmt_key_info keys[0];
@@ -124,34 +117,26 @@ struct mgmt_cp_load_keys {
 
 #define MGMT_OP_REMOVE_KEY		0x000E
 struct mgmt_cp_remove_key {
-	uint16_t index;
 	bdaddr_t bdaddr;
 	uint8_t disconnect;
 } __packed;
 
 #define MGMT_OP_DISCONNECT		0x000F
 struct mgmt_cp_disconnect {
-	uint16_t index;
 	bdaddr_t bdaddr;
 } __packed;
 struct mgmt_rp_disconnect {
-	uint16_t index;
 	bdaddr_t bdaddr;
 } __packed;
 
 #define MGMT_OP_GET_CONNECTIONS		0x0010
-struct mgmt_cp_get_connections {
-	uint16_t index;
-} __packed;
 struct mgmt_rp_get_connections {
-	uint16_t index;
 	uint16_t conn_count;
 	bdaddr_t conn[0];
 } __packed;
 
 #define MGMT_OP_PIN_CODE_REPLY		0x0011
 struct mgmt_cp_pin_code_reply {
-	uint16_t index;
 	bdaddr_t bdaddr;
 	uint8_t pin_len;
 	uint8_t pin_code[16];
@@ -159,35 +144,29 @@ struct mgmt_cp_pin_code_reply {
 
 #define MGMT_OP_PIN_CODE_NEG_REPLY	0x0012
 struct mgmt_cp_pin_code_neg_reply {
-	uint16_t index;
 	bdaddr_t bdaddr;
 } __packed;
 
 #define MGMT_OP_SET_IO_CAPABILITY	0x0013
 struct mgmt_cp_set_io_capability {
-	uint16_t index;
 	uint8_t io_capability;
 } __packed;
 
 #define MGMT_OP_PAIR_DEVICE		0x0014
 struct mgmt_cp_pair_device {
-	uint16_t index;
 	bdaddr_t bdaddr;
 	uint8_t io_cap;
 } __packed;
 struct mgmt_rp_pair_device {
-	uint16_t index;
 	bdaddr_t bdaddr;
 	uint8_t status;
 } __packed;
 
 #define MGMT_OP_USER_CONFIRM_REPLY	0x0015
 struct mgmt_cp_user_confirm_reply {
-	uint16_t index;
 	bdaddr_t bdaddr;
 } __packed;
 struct mgmt_rp_user_confirm_reply {
-	uint16_t index;
 	bdaddr_t bdaddr;
 	uint8_t status;
 } __packed;
@@ -208,19 +187,12 @@ struct mgmt_ev_cmd_status {
 
 #define MGMT_EV_CONTROLLER_ERROR	0x0003
 struct mgmt_ev_controller_error {
-	uint16_t index;
 	uint8_t error_code;
 } __packed;
 
 #define MGMT_EV_INDEX_ADDED		0x0004
-struct mgmt_ev_index_added {
-	uint16_t index;
-} __packed;
 
 #define MGMT_EV_INDEX_REMOVED		0x0005
-struct mgmt_ev_index_removed {
-	uint16_t index;
-} __packed;
 
 #define MGMT_EV_POWERED			0x0006
 
@@ -232,46 +204,39 @@ struct mgmt_ev_index_removed {
 
 #define MGMT_EV_NEW_KEY			0x000A
 struct mgmt_ev_new_key {
-	uint16_t index;
 	struct mgmt_key_info key;
 	uint8_t old_key_type;
 } __packed;
 
 #define MGMT_EV_DEVICE_CONNECTED	0x000B
 struct mgmt_ev_device_connected {
-	uint16_t index;
 	bdaddr_t bdaddr;
 } __packed;
 
 #define MGMT_EV_DEVICE_DISCONNECTED	0x000C
 struct mgmt_ev_device_disconnected {
-	uint16_t index;
 	bdaddr_t bdaddr;
 } __packed;
 
 #define MGMT_EV_CONNECT_FAILED		0x000D
 struct mgmt_ev_connect_failed {
-	uint16_t index;
 	bdaddr_t bdaddr;
 	uint8_t status;
 } __packed;
 
 #define MGMT_EV_PIN_CODE_REQUEST	0x000E
 struct mgmt_ev_pin_code_request {
-	uint16_t index;
 	bdaddr_t bdaddr;
 } __packed;
 
 #define MGMT_EV_USER_CONFIRM_REQUEST	0x000F
 struct mgmt_ev_user_confirm_request {
-	uint16_t index;
 	bdaddr_t bdaddr;
 	uint32_t value;
 } __packed;
 
 #define MGMT_EV_AUTH_FAILED		0x0010
 struct mgmt_ev_auth_failed {
-	uint16_t index;
 	bdaddr_t bdaddr;
 	uint8_t status;
 } __packed;
diff --git a/plugins/mgmtops.c b/plugins/mgmtops.c
index 49f0728..a19a6cc 100644
--- a/plugins/mgmtops.c
+++ b/plugins/mgmtops.c
@@ -92,6 +92,7 @@ static void read_version_complete(int sk, void *buf, size_t len)
 
 	memset(&hdr, 0, sizeof(hdr));
 	hdr.opcode = htobs(MGMT_OP_READ_INDEX_LIST);
+	hdr.index = htobs(MGMT_INDEX_NONE);
 	if (write(sk, &hdr, sizeof(hdr)) < 0)
 		error("Unable to read controller index list: %s (%d)",
 						strerror(errno), errno);
@@ -114,50 +115,32 @@ static void add_controller(uint16_t index)
 
 static void read_info(int sk, uint16_t index)
 {
-	char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_read_info)];
-	struct mgmt_hdr *hdr = (void *) buf;
-	struct mgmt_cp_read_info *cp = (void *) &buf[sizeof(*hdr)];
-
-	memset(buf, 0, sizeof(buf));
-	hdr->opcode = htobs(MGMT_OP_READ_INFO);
-	hdr->len = htobs(sizeof(*cp));
+	struct mgmt_hdr hdr;
 
-	cp->index = htobs(index);
+	memset(&hdr, 0, sizeof(hdr));
+	hdr.opcode = htobs(MGMT_OP_READ_INFO);
+	hdr.index = htobs(index);
 
-	if (write(sk, buf, sizeof(buf)) < 0)
+	if (write(sk, &hdr, sizeof(hdr)) < 0)
 		error("Unable to send read_info command: %s (%d)",
 						strerror(errno), errno);
 }
 
 static void get_connections(int sk, uint16_t index)
 {
-	char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_get_connections)];
-	struct mgmt_hdr *hdr = (void *) buf;
-	struct mgmt_cp_get_connections *cp = (void *) &buf[sizeof(*hdr)];
-
-	memset(buf, 0, sizeof(buf));
-	hdr->opcode = htobs(MGMT_OP_GET_CONNECTIONS);
-	hdr->len = htobs(sizeof(*cp));
+	struct mgmt_hdr hdr;
 
-	cp->index = htobs(index);
+	memset(&hdr, 0, sizeof(hdr));
+	hdr.opcode = htobs(MGMT_OP_GET_CONNECTIONS);
+	hdr.index = htobs(index);
 
-	if (write(sk, buf, sizeof(buf)) < 0)
+	if (write(sk, &hdr, sizeof(hdr)) < 0)
 		error("Unable to send get_connections command: %s (%d)",
 						strerror(errno), errno);
 }
 
-static void mgmt_index_added(int sk, void *buf, size_t len)
+static void mgmt_index_added(int sk, uint16_t index)
 {
-	struct mgmt_ev_index_added *ev = buf;
-	uint16_t index;
-
-	if (len < sizeof(*ev)) {
-		error("Too small index added event");
-		return;
-	}
-
-	index = btohs(bt_get_unaligned(&ev->index));
-
 	add_controller(index);
 	read_info(sk, index);
 }
@@ -177,18 +160,8 @@ static void remove_controller(uint16_t index)
 	DBG("Removed controller %u", index);
 }
 
-static void mgmt_index_removed(int sk, void *buf, size_t len)
+static void mgmt_index_removed(int sk, uint16_t index)
 {
-	struct mgmt_ev_index_removed *ev = buf;
-	uint16_t index;
-
-	if (len < sizeof(*ev)) {
-		error("Too small index removed event");
-		return;
-	}
-
-	index = btohs(bt_get_unaligned(&ev->index));
-
 	remove_controller(index);
 }
 
@@ -200,9 +173,9 @@ static int mgmt_set_mode(int index, uint16_t opcode, uint8_t val)
 
 	memset(buf, 0, sizeof(buf));
 	hdr->opcode = htobs(opcode);
+	hdr->index = htobs(index);
 	hdr->len = htobs(sizeof(*cp));
 
-	cp->index = htobs(index);
 	cp->val = val;
 
 	if (write(mgmt_sock, buf, sizeof(buf)) < 0)
@@ -287,29 +260,25 @@ static int mgmt_update_powered(int index, uint8_t powered)
 	return 0;
 }
 
-static void mgmt_powered(int sk, void *buf, size_t len)
+static void mgmt_powered(int sk, uint16_t index, void *buf, size_t len)
 {
 	struct mgmt_mode *ev = buf;
-	uint16_t index;
 
 	if (len < sizeof(*ev)) {
 		error("Too small powered event");
 		return;
 	}
 
-	index = btohs(bt_get_unaligned(&ev->index));
-
 	DBG("Controller %u powered %u", index, ev->val);
 
 	mgmt_update_powered(index, ev->val);
 }
 
-static void mgmt_discoverable(int sk, void *buf, size_t len)
+static void mgmt_discoverable(int sk, uint16_t index, void *buf, size_t len)
 {
 	struct mgmt_mode *ev = buf;
 	struct controller_info *info;
 	struct btd_adapter *adapter;
-	uint16_t index;
 	uint8_t mode;
 
 	if (len < sizeof(*ev)) {
@@ -317,8 +286,6 @@ static void mgmt_discoverable(int sk, void *buf, size_t len)
 		return;
 	}
 
-	index = btohs(bt_get_unaligned(&ev->index));
-
 	DBG("Controller %u discoverable %u", index, ev->val);
 
 	if (index > max_index) {
@@ -345,12 +312,11 @@ static void mgmt_discoverable(int sk, void *buf, size_t len)
 	adapter_mode_changed(adapter, mode);
 }
 
-static void mgmt_connectable(int sk, void *buf, size_t len)
+static void mgmt_connectable(int sk, uint16_t index, void *buf, size_t len)
 {
 	struct mgmt_mode *ev = buf;
 	struct controller_info *info;
 	struct btd_adapter *adapter;
-	uint16_t index;
 	uint8_t mode;
 
 	if (len < sizeof(*ev)) {
@@ -358,8 +324,6 @@ static void mgmt_connectable(int sk, void *buf, size_t len)
 		return;
 	}
 
-	index = btohs(bt_get_unaligned(&ev->index));
-
 	DBG("Controller %u connectable %u", index, ev->val);
 
 	if (index > max_index) {
@@ -386,20 +350,17 @@ static void mgmt_connectable(int sk, void *buf, size_t len)
 	adapter_mode_changed(adapter, mode);
 }
 
-static void mgmt_pairable(int sk, void *buf, size_t len)
+static void mgmt_pairable(int sk, uint16_t index, void *buf, size_t len)
 {
 	struct mgmt_mode *ev = buf;
 	struct controller_info *info;
 	struct btd_adapter *adapter;
-	uint16_t index;
 
 	if (len < sizeof(*ev)) {
 		error("Too small pairable event");
 		return;
 	}
 
-	index = btohs(bt_get_unaligned(&ev->index));
-
 	DBG("Controller %u pairable %u", index, ev->val);
 
 	if (index > max_index) {
@@ -418,11 +379,10 @@ static void mgmt_pairable(int sk, void *buf, size_t len)
 	btd_adapter_pairable_changed(adapter, info->pairable);
 }
 
-static void mgmt_new_key(int sk, void *buf, size_t len)
+static void mgmt_new_key(int sk, uint16_t index, void *buf, size_t len)
 {
 	struct mgmt_ev_new_key *ev = buf;
 	struct controller_info *info;
-	uint16_t index;
 
 	if (len != sizeof(*ev)) {
 		error("new_key event size mismatch (%zu != %zu)",
@@ -430,8 +390,6 @@ static void mgmt_new_key(int sk, void *buf, size_t len)
 		return;
 	}
 
-	index = btohs(bt_get_unaligned(&ev->index));
-
 	DBG("Controller %u new key of type %u pin_len %u", index,
 					ev->key.type, ev->key.pin_len);
 
@@ -455,11 +413,10 @@ static void mgmt_new_key(int sk, void *buf, size_t len)
 	btd_event_bonding_complete(&info->bdaddr, &ev->key.bdaddr, 0);
 }
 
-static void mgmt_device_connected(int sk, void *buf, size_t len)
+static void mgmt_device_connected(int sk, uint16_t index, void *buf, size_t len)
 {
 	struct mgmt_ev_device_connected *ev = buf;
 	struct controller_info *info;
-	uint16_t index;
 	char addr[18];
 
 	if (len < sizeof(*ev)) {
@@ -467,7 +424,6 @@ static void mgmt_device_connected(int sk, void *buf, size_t len)
 		return;
 	}
 
-	index = btohs(bt_get_unaligned(&ev->index));
 	ba2str(&ev->bdaddr, addr);
 
 	DBG("hci%u device %s connected", index, addr);
@@ -482,11 +438,11 @@ static void mgmt_device_connected(int sk, void *buf, size_t len)
 	btd_event_conn_complete(&info->bdaddr, &ev->bdaddr);
 }
 
-static void mgmt_device_disconnected(int sk, void *buf, size_t len)
+static void mgmt_device_disconnected(int sk, uint16_t index, void *buf,
+								size_t len)
 {
 	struct mgmt_ev_device_disconnected *ev = buf;
 	struct controller_info *info;
-	uint16_t index;
 	char addr[18];
 
 	if (len < sizeof(*ev)) {
@@ -494,7 +450,6 @@ static void mgmt_device_disconnected(int sk, void *buf, size_t len)
 		return;
 	}
 
-	index = btohs(bt_get_unaligned(&ev->index));
 	ba2str(&ev->bdaddr, addr);
 
 	DBG("hci%u device %s disconnected", index, addr);
@@ -509,11 +464,10 @@ static void mgmt_device_disconnected(int sk, void *buf, size_t len)
 	btd_event_disconn_complete(&info->bdaddr, &ev->bdaddr);
 }
 
-static void mgmt_connect_failed(int sk, void *buf, size_t len)
+static void mgmt_connect_failed(int sk, uint16_t index, void *buf, size_t len)
 {
 	struct mgmt_ev_connect_failed *ev = buf;
 	struct controller_info *info;
-	uint16_t index;
 	char addr[18];
 
 	if (len < sizeof(*ev)) {
@@ -521,7 +475,6 @@ static void mgmt_connect_failed(int sk, void *buf, size_t len)
 		return;
 	}
 
-	index = btohs(bt_get_unaligned(&ev->index));
 	ba2str(&ev->bdaddr, addr);
 
 	DBG("hci%u %s status %u", index, addr, ev->status);
@@ -556,9 +509,9 @@ static int mgmt_pincode_reply(int index, bdaddr_t *bdaddr, const char *pin)
 
 		hdr->opcode = htobs(MGMT_OP_PIN_CODE_NEG_REPLY);
 		hdr->len = htobs(sizeof(*cp));
+		hdr->index = htobs(index);
 
 		cp = (void *) &buf[sizeof(*hdr)];
-		cp->index = htobs(index);
 		bacpy(&cp->bdaddr, bdaddr);
 
 		buf_len = sizeof(*hdr) + sizeof(*cp);
@@ -572,9 +525,9 @@ static int mgmt_pincode_reply(int index, bdaddr_t *bdaddr, const char *pin)
 
 		hdr->opcode = htobs(MGMT_OP_PIN_CODE_REPLY);
 		hdr->len = htobs(sizeof(*cp));
+		hdr->index = htobs(index);
 
 		cp = (void *) &buf[sizeof(*hdr)];
-		cp->index = htobs(index);
 		bacpy(&cp->bdaddr, bdaddr);
 		cp->pin_len = pin_len;
 		memcpy(cp->pin_code, pin, pin_len);
@@ -588,11 +541,10 @@ static int mgmt_pincode_reply(int index, bdaddr_t *bdaddr, const char *pin)
 	return 0;
 }
 
-static void mgmt_pin_code_request(int sk, void *buf, size_t len)
+static void mgmt_pin_code_request(int sk, uint16_t index, void *buf, size_t len)
 {
 	struct mgmt_ev_pin_code_request *ev = buf;
 	struct controller_info *info;
-	uint16_t index;
 	char addr[18];
 	int err;
 
@@ -601,7 +553,6 @@ static void mgmt_pin_code_request(int sk, void *buf, size_t len)
 		return;
 	}
 
-	index = btohs(bt_get_unaligned(&ev->index));
 	ba2str(&ev->bdaddr, addr);
 
 	DBG("hci%u %s", index, addr);
@@ -638,9 +589,9 @@ static int mgmt_confirm_reply(int index, bdaddr_t *bdaddr, gboolean success)
 		hdr->opcode = htobs(MGMT_OP_USER_CONFIRM_NEG_REPLY);
 
 	hdr->len = htobs(sizeof(*cp));
+	hdr->index = htobs(index);
 
 	cp = (void *) &buf[sizeof(*hdr)];
-	cp->index = htobs(index);
 	bacpy(&cp->bdaddr, bdaddr);
 
 	if (write(mgmt_sock, buf, sizeof(buf)) < 0)
@@ -649,11 +600,11 @@ static int mgmt_confirm_reply(int index, bdaddr_t *bdaddr, gboolean success)
 	return 0;
 }
 
-static void mgmt_user_confirm_request(int sk, void *buf, size_t len)
+static void mgmt_user_confirm_request(int sk, uint16_t index, void *buf,
+								size_t len)
 {
 	struct mgmt_ev_user_confirm_request *ev = buf;
 	struct controller_info *info;
-	uint16_t index;
 	char addr[18];
 	int err;
 
@@ -662,7 +613,6 @@ static void mgmt_user_confirm_request(int sk, void *buf, size_t len)
 		return;
 	}
 
-	index = btohs(bt_get_unaligned(&ev->index));
 	ba2str(&ev->bdaddr, addr);
 
 	DBG("hci%u %s", index, addr);
@@ -707,8 +657,8 @@ static int mgmt_add_uuid(int index, uuid_t *uuid, uint8_t svc_hint)
 	memset(buf, 0, sizeof(buf));
 	hdr->opcode = htobs(MGMT_OP_ADD_UUID);
 	hdr->len = htobs(sizeof(*cp));
+	hdr->index = htobs(index);
 
-	cp->index = htobs(index);
 	memcpy(cp->uuid, uuid128.value.uuid128.data, 16);
 	cp->svc_hint = svc_hint;
 
@@ -732,8 +682,8 @@ static int mgmt_remove_uuid(int index, uuid_t *uuid)
 	memset(buf, 0, sizeof(buf));
 	hdr->opcode = htobs(MGMT_OP_REMOVE_UUID);
 	hdr->len = htobs(sizeof(*cp));
+	hdr->index = htobs(index);
 
-	cp->index = htobs(index);
 	memcpy(cp->uuid, uuid128.value.uuid128.data, 16);
 
 	if (write(mgmt_sock, buf, sizeof(buf)) < 0)
@@ -787,13 +737,12 @@ static int mgmt_set_powered(int index, gboolean powered)
 	return mgmt_set_mode(index, MGMT_OP_SET_POWERED, powered);
 }
 
-static void read_info_complete(int sk, void *buf, size_t len)
+static void read_info_complete(int sk, uint16_t index, void *buf, size_t len)
 {
 	struct mgmt_rp_read_info *rp = buf;
 	struct controller_info *info;
 	struct btd_adapter *adapter;
 	uint8_t mode;
-	uint16_t index;
 	char addr[18];
 
 	if (len < sizeof(*rp)) {
@@ -801,7 +750,6 @@ static void read_info_complete(int sk, void *buf, size_t len)
 		return;
 	}
 
-	index = btohs(bt_get_unaligned(&rp->index));
 	if (index > max_index) {
 		error("Unexpected index %u in read info complete", index);
 		return;
@@ -853,29 +801,26 @@ static void read_info_complete(int sk, void *buf, size_t len)
 	btd_adapter_unref(adapter);
 }
 
-static void set_powered_complete(int sk, void *buf, size_t len)
+static void set_powered_complete(int sk, uint16_t index, void *buf, size_t len)
 {
 	struct mgmt_mode *rp = buf;
-	uint16_t index;
 
 	if (len < sizeof(*rp)) {
 		error("Too small set powered complete event");
 		return;
 	}
 
-	index = btohs(bt_get_unaligned(&rp->index));
-
 	DBG("hci%d powered %u", index, rp->val);
 
 	mgmt_update_powered(index, rp->val);
 }
 
-static void set_discoverable_complete(int sk, void *buf, size_t len)
+static void set_discoverable_complete(int sk, uint16_t index, void *buf,
+								size_t len)
 {
 	struct mgmt_mode *rp = buf;
 	struct controller_info *info;
 	struct btd_adapter *adapter;
-	uint16_t index;
 	uint8_t mode;
 
 	if (len < sizeof(*rp)) {
@@ -883,8 +828,6 @@ static void set_discoverable_complete(int sk, void *buf, size_t len)
 		return;
 	}
 
-	index = btohs(bt_get_unaligned(&rp->index));
-
 	DBG("hci%d discoverable %u", index, rp->val);
 
 	if (index > max_index) {
@@ -909,20 +852,18 @@ static void set_discoverable_complete(int sk, void *buf, size_t len)
 	adapter_mode_changed(adapter, mode);
 }
 
-static void set_connectable_complete(int sk, void *buf, size_t len)
+static void set_connectable_complete(int sk, uint16_t index, void *buf,
+								size_t len)
 {
 	struct mgmt_mode *rp = buf;
 	struct controller_info *info;
 	struct btd_adapter *adapter;
-	uint16_t index;
 
 	if (len < sizeof(*rp)) {
 		error("Too small set connectable complete event");
 		return;
 	}
 
-	index = btohs(bt_get_unaligned(&rp->index));
-
 	DBG("hci%d connectable %u", index, rp->val);
 
 	if (index > max_index) {
@@ -939,20 +880,18 @@ static void set_connectable_complete(int sk, void *buf, size_t len)
 		adapter_mode_changed(adapter, rp->val ? SCAN_PAGE : 0);
 }
 
-static void set_pairable_complete(int sk, void *buf, size_t len)
+static void set_pairable_complete(int sk, uint16_t index, void *buf,
+								size_t len)
 {
 	struct mgmt_mode *rp = buf;
 	struct controller_info *info;
 	struct btd_adapter *adapter;
-	uint16_t index;
 
 	if (len < sizeof(*rp)) {
 		error("Too small set pairable complete event");
 		return;
 	}
 
-	index = btohs(bt_get_unaligned(&rp->index));
-
 	DBG("hci%d pairable %u", index, rp->val);
 
 	if (index > max_index) {
@@ -971,11 +910,10 @@ static void set_pairable_complete(int sk, void *buf, size_t len)
 	btd_adapter_pairable_changed(adapter, info->pairable);
 }
 
-static void disconnect_complete(int sk, void *buf, size_t len)
+static void disconnect_complete(int sk, uint16_t index, void *buf, size_t len)
 {
 	struct mgmt_rp_disconnect *rp = buf;
 	struct controller_info *info;
-	uint16_t index;
 	char addr[18];
 
 	if (len < sizeof(*rp)) {
@@ -983,8 +921,6 @@ static void disconnect_complete(int sk, void *buf, size_t len)
 		return;
 	}
 
-	index = btohs(bt_get_unaligned(&rp->index));
-
 	ba2str(&rp->bdaddr, addr);
 
 	DBG("hci%d %s disconnected", index, addr);
@@ -1002,11 +938,10 @@ static void disconnect_complete(int sk, void *buf, size_t len)
 						HCI_CONNECTION_TERMINATED);
 }
 
-static void pair_device_complete(int sk, void *buf, size_t len)
+static void pair_device_complete(int sk, uint16_t index, void *buf, size_t len)
 {
 	struct mgmt_rp_pair_device *rp = buf;
 	struct controller_info *info;
-	uint16_t index;
 	char addr[18];
 
 	if (len < sizeof(*rp)) {
@@ -1014,8 +949,6 @@ static void pair_device_complete(int sk, void *buf, size_t len)
 		return;
 	}
 
-	index = btohs(bt_get_unaligned(&rp->index));
-
 	ba2str(&rp->bdaddr, addr);
 
 	DBG("hci%d %s pairing complete status %u", index, addr, rp->status);
@@ -1030,11 +963,11 @@ static void pair_device_complete(int sk, void *buf, size_t len)
 	btd_event_bonding_complete(&info->bdaddr, &rp->bdaddr, rp->status);
 }
 
-static void get_connections_complete(int sk, void *buf, size_t len)
+static void get_connections_complete(int sk, uint16_t index, void *buf,
+								size_t len)
 {
 	struct mgmt_rp_get_connections *rp = buf;
 	struct controller_info *info;
-	uint16_t index;
 	int i;
 
 	if (len < sizeof(*rp)) {
@@ -1047,8 +980,6 @@ static void get_connections_complete(int sk, void *buf, size_t len)
 		return;
 	}
 
-	index = btohs(bt_get_unaligned(&rp->index));
-
 	if (index > max_index) {
 		error("Unexpected index %u in get_connections complete",
 								index);
@@ -1065,7 +996,7 @@ static void get_connections_complete(int sk, void *buf, size_t len)
 	read_info(sk, index);
 }
 
-static void mgmt_cmd_complete(int sk, void *buf, size_t len)
+static void mgmt_cmd_complete(int sk, uint16_t index, void *buf, size_t len)
 {
 	struct mgmt_ev_cmd_complete *ev = buf;
 	uint16_t opcode;
@@ -1079,27 +1010,29 @@ static void mgmt_cmd_complete(int sk, void *buf, size_t len)
 
 	opcode = btohs(bt_get_unaligned(&ev->opcode));
 
+	len -= sizeof(*ev);
+
 	switch (opcode) {
 	case MGMT_OP_READ_VERSION:
-		read_version_complete(sk, ev->data, len - sizeof(*ev));
+		read_version_complete(sk, ev->data, len);
 		break;
 	case MGMT_OP_READ_INDEX_LIST:
-		read_index_list_complete(sk, ev->data, len - sizeof(*ev));
+		read_index_list_complete(sk, ev->data, len);
 		break;
 	case MGMT_OP_READ_INFO:
-		read_info_complete(sk, ev->data, len - sizeof(*ev));
+		read_info_complete(sk, index, ev->data, len);
 		break;
 	case MGMT_OP_SET_POWERED:
-		set_powered_complete(sk, ev->data, len - sizeof(*ev));
+		set_powered_complete(sk, index, ev->data, len);
 		break;
 	case MGMT_OP_SET_DISCOVERABLE:
-		set_discoverable_complete(sk, ev->data, len - sizeof(*ev));
+		set_discoverable_complete(sk, index, ev->data, len);
 		break;
 	case MGMT_OP_SET_CONNECTABLE:
-		set_connectable_complete(sk, ev->data, len - sizeof(*ev));
+		set_connectable_complete(sk, index, ev->data, len);
 		break;
 	case MGMT_OP_SET_PAIRABLE:
-		set_pairable_complete(sk, ev->data, len - sizeof(*ev));
+		set_pairable_complete(sk, index, ev->data, len);
 		break;
 	case MGMT_OP_ADD_UUID:
 		DBG("add_uuid complete");
@@ -1121,10 +1054,10 @@ static void mgmt_cmd_complete(int sk, void *buf, size_t len)
 		break;
 	case MGMT_OP_DISCONNECT:
 		DBG("disconnect complete");
-		disconnect_complete(sk, ev->data, len - sizeof(*ev));
+		disconnect_complete(sk, index, ev->data, len);
 		break;
 	case MGMT_OP_GET_CONNECTIONS:
-		get_connections_complete(sk, ev->data, len - sizeof(*ev));
+		get_connections_complete(sk, index, ev->data, len);
 		break;
 	case MGMT_OP_PIN_CODE_REPLY:
 		DBG("pin_code_reply complete");
@@ -1136,7 +1069,7 @@ static void mgmt_cmd_complete(int sk, void *buf, size_t len)
 		DBG("set_io_capability complete");
 		break;
 	case MGMT_OP_PAIR_DEVICE:
-		pair_device_complete(sk, ev->data, len - sizeof(*ev));
+		pair_device_complete(sk, index, ev->data, len);
 		break;
 	case MGMT_OP_USER_CONFIRM_REPLY:
 		DBG("user_confirm_reply complete");
@@ -1150,7 +1083,7 @@ static void mgmt_cmd_complete(int sk, void *buf, size_t len)
 	}
 }
 
-static void mgmt_cmd_status(int sk, void *buf, size_t len)
+static void mgmt_cmd_status(int sk, uint16_t index, void *buf, size_t len)
 {
 	struct mgmt_ev_cmd_status *ev = buf;
 	uint16_t opcode;
@@ -1162,37 +1095,31 @@ static void mgmt_cmd_status(int sk, void *buf, size_t len)
 
 	opcode = btohs(bt_get_unaligned(&ev->opcode));
 
-	DBG("status %u opcode %u", ev->status, opcode);
+	DBG("status %u opcode %u (index %u)", ev->status, opcode, index);
 }
 
-static void mgmt_controller_error(int sk, void *buf, size_t len)
+static void mgmt_controller_error(int sk, uint16_t index, void *buf, size_t len)
 {
 	struct mgmt_ev_controller_error *ev = buf;
-	uint16_t index;
 
 	if (len < sizeof(*ev)) {
 		error("Too small management controller error event packet");
 		return;
 	}
 
-	index = btohs(bt_get_unaligned(&ev->index));
-
 	DBG("index %u error_code %u", index, ev->error_code);
 }
 
-static void mgmt_auth_failed(int sk, void *buf, size_t len)
+static void mgmt_auth_failed(int sk, uint16_t index, void *buf, size_t len)
 {
 	struct controller_info *info;
 	struct mgmt_ev_auth_failed *ev = buf;
-	uint16_t index;
 
 	if (len < sizeof(*ev)) {
 		error("Too small mgmt_auth_failed event packet");
 		return;
 	}
 
-	index = btohs(bt_get_unaligned(&ev->index));
-
 	DBG("hci%u auth failed status %u", index, ev->status);
 
 	if (index > max_index) {
@@ -1211,7 +1138,7 @@ static gboolean mgmt_event(GIOChannel *io, GIOCondition cond, gpointer user_data
 	struct mgmt_hdr *hdr = (void *) buf;
 	int sk;
 	ssize_t ret;
-	uint16_t len, opcode;
+	uint16_t len, opcode, index;
 
 	DBG("cond %d", cond);
 
@@ -1241,6 +1168,7 @@ static gboolean mgmt_event(GIOChannel *io, GIOCondition cond, gpointer user_data
 
 	opcode = btohs(bt_get_unaligned(&hdr->opcode));
 	len = btohs(bt_get_unaligned(&hdr->len));
+	index = btohs(bt_get_unaligned(&hdr->index));
 
 	if (ret != MGMT_HDR_SIZE + len) {
 		error("Packet length mismatch. ret %zd len %u", ret, len);
@@ -1249,55 +1177,55 @@ static gboolean mgmt_event(GIOChannel *io, GIOCondition cond, gpointer user_data
 
 	switch (opcode) {
 	case MGMT_EV_CMD_COMPLETE:
-		mgmt_cmd_complete(sk, buf + MGMT_HDR_SIZE, len);
+		mgmt_cmd_complete(sk, index, buf + MGMT_HDR_SIZE, len);
 		break;
 	case MGMT_EV_CMD_STATUS:
-		mgmt_cmd_status(sk, buf + MGMT_HDR_SIZE, len);
+		mgmt_cmd_status(sk, index, buf + MGMT_HDR_SIZE, len);
 		break;
 	case MGMT_EV_CONTROLLER_ERROR:
-		mgmt_controller_error(sk, buf + MGMT_HDR_SIZE, len);
+		mgmt_controller_error(sk, index, buf + MGMT_HDR_SIZE, len);
 		break;
 	case MGMT_EV_INDEX_ADDED:
-		mgmt_index_added(sk, buf + MGMT_HDR_SIZE, len);
+		mgmt_index_added(sk, index);
 		break;
 	case MGMT_EV_INDEX_REMOVED:
-		mgmt_index_removed(sk, buf + MGMT_HDR_SIZE, len);
+		mgmt_index_removed(sk, index);
 		break;
 	case MGMT_EV_POWERED:
-		mgmt_powered(sk, buf + MGMT_HDR_SIZE, len);
+		mgmt_powered(sk, index, buf + MGMT_HDR_SIZE, len);
 		break;
 	case MGMT_EV_DISCOVERABLE:
-		mgmt_discoverable(sk, buf + MGMT_HDR_SIZE, len);
+		mgmt_discoverable(sk, index, buf + MGMT_HDR_SIZE, len);
 		break;
 	case MGMT_EV_CONNECTABLE:
-		mgmt_connectable(sk, buf + MGMT_HDR_SIZE, len);
+		mgmt_connectable(sk, index, buf + MGMT_HDR_SIZE, len);
 		break;
 	case MGMT_EV_PAIRABLE:
-		mgmt_pairable(sk, buf + MGMT_HDR_SIZE, len);
+		mgmt_pairable(sk, index, buf + MGMT_HDR_SIZE, len);
 		break;
 	case MGMT_EV_NEW_KEY:
-		mgmt_new_key(sk, buf + MGMT_HDR_SIZE, len);
+		mgmt_new_key(sk, index, buf + MGMT_HDR_SIZE, len);
 		break;
 	case MGMT_EV_DEVICE_CONNECTED:
-		mgmt_device_connected(sk, buf + MGMT_HDR_SIZE, len);
+		mgmt_device_connected(sk, index, buf + MGMT_HDR_SIZE, len);
 		break;
 	case MGMT_EV_DEVICE_DISCONNECTED:
-		mgmt_device_disconnected(sk, buf + MGMT_HDR_SIZE, len);
+		mgmt_device_disconnected(sk, index, buf + MGMT_HDR_SIZE, len);
 		break;
 	case MGMT_EV_CONNECT_FAILED:
-		mgmt_connect_failed(sk, buf + MGMT_HDR_SIZE, len);
+		mgmt_connect_failed(sk, index, buf + MGMT_HDR_SIZE, len);
 		break;
 	case MGMT_EV_PIN_CODE_REQUEST:
-		mgmt_pin_code_request(sk, buf + MGMT_HDR_SIZE, len);
+		mgmt_pin_code_request(sk, index, buf + MGMT_HDR_SIZE, len);
 		break;
 	case MGMT_EV_USER_CONFIRM_REQUEST:
-		mgmt_user_confirm_request(sk, buf + MGMT_HDR_SIZE, len);
+		mgmt_user_confirm_request(sk, index, buf + MGMT_HDR_SIZE, len);
 		break;
 	case MGMT_EV_AUTH_FAILED:
-		mgmt_auth_failed(sk, buf + MGMT_HDR_SIZE, len);
+		mgmt_auth_failed(sk, index, buf + MGMT_HDR_SIZE, len);
 		break;
 	default:
-		error("Unknown Management opcode %u", opcode);
+		error("Unknown Management opcode %u (index %u)", opcode, index);
 		break;
 	}
 
@@ -1328,6 +1256,7 @@ static int mgmt_setup(void)
 
 	memset(&hdr, 0, sizeof(hdr));
 	hdr.opcode = htobs(MGMT_OP_READ_VERSION);
+	hdr.index = htobs(MGMT_INDEX_NONE);
 	if (write(dd, &hdr, sizeof(hdr)) < 0) {
 		err = -errno;
 		goto fail;
@@ -1377,8 +1306,8 @@ static int mgmt_set_dev_class(int index, uint8_t major, uint8_t minor)
 	memset(buf, 0, sizeof(buf));
 	hdr->opcode = htobs(MGMT_OP_SET_DEV_CLASS);
 	hdr->len = htobs(sizeof(*cp));
+	hdr->index = htobs(index);
 
-	cp->index = htobs(index);
 	cp->major = major;
 	cp->minor = minor;
 
@@ -1554,8 +1483,8 @@ static int mgmt_disconnect(int index, bdaddr_t *bdaddr)
 	memset(buf, 0, sizeof(buf));
 	hdr->opcode = htobs(MGMT_OP_DISCONNECT);
 	hdr->len = htobs(sizeof(*cp));
+	hdr->index = htobs(index);
 
-	cp->index = htobs(index);
 	bacpy(&cp->bdaddr, bdaddr);
 
 	if (write(mgmt_sock, buf, sizeof(buf)) < 0)
@@ -1577,8 +1506,8 @@ static int mgmt_remove_bonding(int index, bdaddr_t *bdaddr)
 	memset(buf, 0, sizeof(buf));
 	hdr->opcode = htobs(MGMT_OP_REMOVE_KEY);
 	hdr->len = htobs(sizeof(*cp));
+	hdr->index = htobs(index);
 
-	cp->index = htobs(index);
 	bacpy(&cp->bdaddr, bdaddr);
 	cp->disconnect = 1;
 
@@ -1660,9 +1589,9 @@ static int mgmt_load_keys(int index, GSList *keys, gboolean debug_keys)
 	hdr = (void *) buf;
 	hdr->opcode = htobs(MGMT_OP_LOAD_KEYS);
 	hdr->len = htobs(cp_size);
+	hdr->index = htobs(index);
 
 	cp = (void *) (buf + sizeof(*hdr));
-	cp->index = htobs(index);
 	cp->debug_keys = debug_keys;
 	cp->key_count = htobs(key_count);
 
@@ -1696,8 +1625,8 @@ static int mgmt_set_io_capability(int index, uint8_t io_capability)
 	memset(buf, 0, sizeof(buf));
 	hdr->opcode = htobs(MGMT_OP_SET_IO_CAPABILITY);
 	hdr->len = htobs(sizeof(*cp));
+	hdr->index = htobs(index);
 
-	cp->index = htobs(index);
 	cp->io_capability = io_capability;
 
 	if (write(mgmt_sock, buf, sizeof(buf)) < 0)
@@ -1719,8 +1648,8 @@ static int mgmt_create_bonding(int index, bdaddr_t *bdaddr, uint8_t io_cap)
 	memset(buf, 0, sizeof(buf));
 	hdr->opcode = htobs(MGMT_OP_PAIR_DEVICE);
 	hdr->len = htobs(sizeof(*cp));
+	hdr->index = htobs(index);
 
-	cp->index = htobs(index);
 	bacpy(&cp->bdaddr, bdaddr);
 	cp->io_cap = io_cap;
 
-- 
1.7.0.4
on behalf of ST-Ericsson

^ permalink raw reply related

* Do you have a plan to split ERTM into a separate file?
From: Haijun Liu @ 2011-02-24 13:23 UTC (permalink / raw)
  To: Gustavo F. Padovan (padovan@profusion.mobi)
  Cc:  (linux-bluetooth@vger.kernel.org), Dan Tian,
	liuhaijun.er@gmail.com

RGVhciBHdXN0YXZvLA0KDQpEbyB5b3UgaGF2ZSBhIHBsYW4gdG8gc3BsaXQgRVJUTSBjb2RlIGlu
dG8gYSBzZXBhcmF0ZSBmaWxlPw0KSXQgbWF5IGJlIGVhc2llciB0byByZWFkL2xlYXJuIEVSVE0g
bWVjaGFuaXNtIHdpdGggbG9vc2VseSBjb3VwbGVkIGNvZGUgZm9yIHBlb3BsZS4NClRoYW5rIHlv
dSEg4pi6DQoNClJlZ2FyZHMNCkhhaWp1bg0KU2t5cGU6IGxpdS5oYWlqdW4NCg0K

^ permalink raw reply

* [PATCH] Close SCO before headset interface state change
From: Daniel Örstadius @ 2011-02-24 12:41 UTC (permalink / raw)
  To: linux-bluetooth

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

Hi,

Attached is a tentative patch proposal, I'm not sure how to make this
modification in a good way.

Maybe the check for G_IO_NVAL in sco_cb should not be removed, but
that is the GIOCondition the callback receives
when shutting down the SCO socket.
It was added in commit
http://git.kernel.org/?p=bluetooth/bluez.git;a=commit;h=6834de18b98fea0e7d370a296318115a659047af

Br,
Daniel

[-- Attachment #2: 0001-Close-SCO-before-headset-interface-state-change.patch --]
[-- Type: text/x-patch, Size: 2916 bytes --]

From 608c2d4322fa2a9dbe61f6c97cacd4c73f9d26ef Mon Sep 17 00:00:00 2001
From: Daniel Orstadius <daniel.orstadius@nokia.com>
Date: Thu, 24 Feb 2011 12:31:34 +0200
Subject: [PATCH] Close SCO before headset interface state change

When the SCO connection is released by the MediaTransport interface,
wait for the SCO callback before entering the
HEADSET_STATE_CONNECTED state.

The reason for the patch is to notify the headset state change on
D-Bus at a later stage in the SCO disconnection process. In case the
user of the Media interface wants to start sending audio over A2DP,
the audio routing switch can be delayed until the D-Bus signal is
received (some headsets have issues if AVDTP Start is sent before
or while the SCO link is being disconnected).
---
 audio/headset.c |   15 ++++++---------
 1 files changed, 6 insertions(+), 9 deletions(-)

diff --git a/audio/headset.c b/audio/headset.c
index bdaa8da..ec6ef08 100644
--- a/audio/headset.c
+++ b/audio/headset.c
@@ -1233,7 +1233,7 @@ static int handle_event(struct audio_device *device, const char *buf)
 	return -EINVAL;
 }
 
-static void close_sco(struct audio_device *device)
+static void close_sco(struct audio_device *device, gboolean remove_callback)
 {
 	struct headset *hs = device->headset;
 
@@ -1245,7 +1245,7 @@ static void close_sco(struct audio_device *device)
 		hs->sco = NULL;
 	}
 
-	if (hs->sco_id) {
+	if (remove_callback && hs->sco_id) {
 		g_source_remove(hs->sco_id);
 		hs->sco_id = 0;
 	}
@@ -1340,9 +1340,6 @@ failed:
 static gboolean sco_cb(GIOChannel *chan, GIOCondition cond,
 			struct audio_device *device)
 {
-	if (cond & G_IO_NVAL)
-		return FALSE;
-
 	error("Audio connection got disconnected");
 
 	headset_set_state(device, HEADSET_STATE_CONNECTED);
@@ -2142,7 +2139,7 @@ static void headset_free(struct audio_device *dev)
 		hs->dc_timer = 0;
 	}
 
-	close_sco(dev);
+	close_sco(dev, TRUE);
 
 	headset_close_rfcomm(dev);
 
@@ -2474,7 +2471,7 @@ void headset_set_state(struct audio_device *dev, headset_state_t state)
 	switch (state) {
 	case HEADSET_STATE_DISCONNECTED:
 		value = FALSE;
-		close_sco(dev);
+		close_sco(dev, TRUE);
 		headset_close_rfcomm(dev);
 		emit_property_changed(dev->conn, dev->path,
 					AUDIO_HEADSET_INTERFACE, "State",
@@ -2497,7 +2494,7 @@ void headset_set_state(struct audio_device *dev, headset_state_t state)
 					DBUS_TYPE_STRING, &state_str);
 		break;
 	case HEADSET_STATE_CONNECTED:
-		close_sco(dev);
+		close_sco(dev, TRUE);
 		if (hs->state != HEADSET_STATE_PLAY_IN_PROGRESS)
 			emit_property_changed(dev->conn, dev->path,
 					AUDIO_HEADSET_INTERFACE, "State",
@@ -2622,7 +2619,7 @@ gboolean headset_unlock(struct audio_device *dev, headset_lock_t lock)
 		return TRUE;
 
 	if (hs->state == HEADSET_STATE_PLAYING)
-		headset_set_state(dev, HEADSET_STATE_CONNECTED);
+		close_sco(dev, FALSE);
 
 	if (hs->auto_dc) {
 		if (hs->state == HEADSET_STATE_CONNECTED)
-- 
1.6.0.4


^ permalink raw reply related

* [PATCH] Maemo6 MCE: skip first adapter_powered callback
From: Daniel Örstadius @ 2011-02-24 12:27 UTC (permalink / raw)
  To: linux-bluetooth

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



[-- Attachment #2: 0001-Maemo6-MCE-skip-first-adapter_powered-callback.patch --]
[-- Type: text/x-patch, Size: 1690 bytes --]

From 12f6e83e8a437f945a18d9e15e956039acad3a4b Mon Sep 17 00:00:00 2001
From: Daniel Orstadius <daniel.orstadius@nokia.com>
Date: Thu, 24 Feb 2011 13:45:33 +0200
Subject: [PATCH] Maemo6 MCE: skip first adapter_powered callback

The maemo6 MCE plugin should be used with the flag InitiallyPowered
in main.conf set to 'true' so that BlueZ powers on the adapter
and leaves it in that state when the daemon is started. The plugin
will read the radio state from the MCE and set the state
accordingly. The maemo6 plugin is a btd_adapter_driver and those
drivers are loaded after BlueZ has read the BD address etc from the
adapter.

This patch adds a boolean flag in the callback to ignore the initial
powering on of the adapter by BlueZ, since it shouldn't be
propagated to the MCE. With InitiallyPowered set to 'false' the
adapter_powered callback is not called when the adapter is turned
on at BlueZ startup, which is why this wasn't implemented before.
---
 plugins/maemo6.c |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/plugins/maemo6.c b/plugins/maemo6.c
index 3c91926..56f2664 100644
--- a/plugins/maemo6.c
+++ b/plugins/maemo6.c
@@ -135,9 +135,15 @@ static void adapter_powered(struct btd_adapter *adapter, gboolean powered)
 	DBusMessage *msg;
 	dbus_uint32_t radio_states = 0;
 	dbus_uint32_t radio_mask = MCE_RADIO_STATE_BLUETOOTH;
+	static gboolean startup = TRUE;
 
 	DBG("adapter_powered called with %d", powered);
 
+	if (startup) {
+		startup = FALSE;
+		return;
+	}
+
 	/* check if the plugin got the get_radio_states reply from the
 	 * mce when the adapter was not yet down during the power
 	 * cycling when bluetoothd is started */
-- 
1.6.0.4


^ permalink raw reply related

* [PATCH v2 4/4] Sim Access Profile dummy driver
From: Waldemar Rymarkiewicz @ 2011-02-24 12:13 UTC (permalink / raw)
  To: linux-bluetooth
  Cc: Johan Hedberg, padovan, Marcel Holtmann, Waldemar Rymarkiewicz
In-Reply-To: <1298549606-16594-1-git-send-email-waldemar.rymarkiewicz@tieto.com>

Add SAP dummy driver implementation and extend configure
with --with-sap=<driver>.
---
 .gitignore      |    1 +
 Makefile.am     |   13 ++-
 acinclude.m4    |    6 +
 sap/sap-dummy.c |  275 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
 4 files changed, 278 insertions(+), 17 deletions(-)

diff --git a/.gitignore b/.gitignore
index 07e239f..3e36a59 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,6 +35,7 @@ lib/bluetooth
 src/builtin.h
 src/bluetoothd
 audio/telephony.c
+sap/sap.c
 scripts/bluetooth.rules
 scripts/97-bluetooth.rules
 scripts/97-bluetooth-hid2hci.rules
diff --git a/Makefile.am b/Makefile.am
index af374a9..93a0794 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -148,7 +148,13 @@ builtin_modules += sap
 builtin_sources += sap/main.c \
 			sap/manager.h sap/manager.c \
 			sap/server.h sap/server.c \
-			sap/sap.h sap/sap-dummy.c
+			sap/sap.h
+
+builtin_nodist += sap/sap.c
+
+noinst_LIBRARIES = sap/libsap.a
+
+sap_libsap_a_SOURCES = sap/sap.h sap/sap-dummy.c
 endif
 
 if INPUTPLUGIN
@@ -278,7 +284,7 @@ EXTRA_DIST += src/genbuiltin src/bluetooth.conf \
 			input/input.conf serial/serial.conf \
 			audio/audio.conf audio/telephony-dummy.c \
 			audio/telephony-maemo5.c audio/telephony-ofono.c \
-			audio/telephony-maemo6.c
+			audio/telephony-maemo6.c sap/sap-dummy.c
 
 
 if ALSA
@@ -403,6 +409,9 @@ src/builtin.h: src/genbuiltin $(builtin_sources)
 audio/telephony.c: audio/@TELEPHONY_DRIVER@
 	$(AM_V_GEN)$(LN_S) $(abs_top_srcdir)/$< $@
 
+sap/sap.c: sap/@SAP_DRIVER@
+	$(AM_V_GEN)$(LN_S) $(abs_top_srcdir)/$< $@
+
 scripts/%.rules:
 	$(AM_V_GEN)cp $(subst 97-,,$@) $@
 
diff --git a/acinclude.m4 b/acinclude.m4
index ebf618e..b03e6d2 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -204,6 +204,7 @@ AC_DEFUN([AC_ARG_BLUEZ], [
 	configfiles_enable=yes
 	telephony_driver=dummy
 	maemo6_enable=no
+	sap_driver=dummy
 
 	AC_ARG_ENABLE(optimization, AC_HELP_STRING([--disable-optimization], [disable code optimization]), [
 		optimization_enable=${enableval}
@@ -225,6 +226,11 @@ AC_DEFUN([AC_ARG_BLUEZ], [
 		sap_enable=${enableval}
 	])
 
+	AC_ARG_WITH(sap, AC_HELP_STRING([--with-sap=DRIVER], [select SAP driver]), [
+		sap_driver=${withval}
+	])
+	AC_SUBST([SAP_DRIVER], [sap-${sap_driver}.c])
+
 	AC_ARG_ENABLE(serial, AC_HELP_STRING([--disable-serial], [disable serial plugin]), [
 		serial_enable=${enableval}
 	])
diff --git a/sap/sap-dummy.c b/sap/sap-dummy.c
index 92d73ef..2391bac 100644
--- a/sap/sap-dummy.c
+++ b/sap/sap-dummy.c
@@ -2,12 +2,15 @@
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2010 ST-Ericsson SA
+ *  Copyright (C) 2011 Tieto
  *
- *  Author: Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com> for ST-Ericsson
+ *  Author: Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com>
+ *          for ST-Ericsson
  *
  *  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; version 2 of the License.
+ *  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
@@ -19,65 +22,307 @@
  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <glib.h>
+#include <gdbus.h>
+
 #include "log.h"
 #include "sap.h"
 
+#define SAP_DUMMY_IFACE "org.bluez.SimAccessTest"
+#define SAP_DUMMY_PATH "/org/bluez/test"
+
+enum {
+	SIM_DISCONNECTED= 0x00,
+	SIM_CONNECTED	= 0x01,
+	SIM_POWERED_OFF	= 0x02,
+	SIM_MISSING	= 0x03
+};
+
+static DBusConnection *connection = NULL;
+
+static int sim_card_conn_status = SIM_DISCONNECTED;
+static void *sap_data = NULL;  /* SAP server private data.*/
+static gboolean ongoing_call_status = FALSE;
+static int max_msg_size_supported = 512;
+
 void sap_connect_req(void *sap_device, uint16_t maxmsgsize)
 {
-	sap_connect_rsp(sap_device, SAP_STATUS_OK, maxmsgsize);
-	sap_status_ind(sap_device, SAP_STATUS_CHANGE_CARD_RESET);
+	DBG("status: %d", sim_card_conn_status);
+
+	if (sim_card_conn_status != SIM_DISCONNECTED) {
+		sap_connect_rsp(sap_device, SAP_STATUS_CONNECTION_FAILED,
+								maxmsgsize);
+		return;
+	} else if (max_msg_size_supported > maxmsgsize) {
+		sap_connect_rsp(sap_device, SAP_STATUS_MAX_MSG_SIZE_TOO_SMALL,
+						max_msg_size_supported);
+		return;
+	} else if (max_msg_size_supported < maxmsgsize) {
+		sap_connect_rsp(sap_device,
+				SAP_STATUS_MAX_MSG_SIZE_NOT_SUPPORTED,
+				max_msg_size_supported);
+		return;
+	} else if (ongoing_call_status) {
+		sap_connect_rsp(sap_device, SAP_STATUS_OK_ONGOING_CALL,
+								maxmsgsize);
+		return;
+	} else {
+		sim_card_conn_status = SIM_CONNECTED;
+		sap_data = sap_device;
+
+		sap_connect_rsp(sap_device, SAP_STATUS_OK, maxmsgsize);
+		sap_status_ind(sap_device, SAP_STATUS_CHANGE_CARD_RESET);
+	}
 }
 
 void sap_disconnect_req(void *sap_device, uint8_t linkloss)
 {
+	sim_card_conn_status = SIM_DISCONNECTED;
+	sap_data = NULL;
+	ongoing_call_status = FALSE;
+
+	DBG("status: %d", sim_card_conn_status);
+
+	if (linkloss)
+		return;
+
 	sap_disconnect_rsp(sap_device);
 }
 
 void sap_transfer_apdu_req(void *sap_device, struct sap_parameter *param)
 {
-	sap_transfer_apdu_rsp(sap_device, SAP_RESULT_OK, NULL, 0);
+	char apdu[] = "APDU response!";
+
+	DBG("status: %d", sim_card_conn_status);
+
+	if (sim_card_conn_status == SIM_MISSING)
+		sap_transfer_apdu_rsp(sap_device,
+				SAP_RESULT_ERROR_CARD_REMOVED, NULL, 0);
+	else if (sim_card_conn_status == SIM_POWERED_OFF)
+		sap_transfer_apdu_rsp(sap_device, SAP_RESULT_ERROR_POWERED_OFF,
+								NULL, 0);
+	else if (sim_card_conn_status != SIM_CONNECTED)
+		sap_transfer_apdu_rsp(sap_device,
+			SAP_RESULT_ERROR_NOT_ACCESSIBLE, NULL, 0);
+	else
+		sap_transfer_apdu_rsp(sap_device, SAP_RESULT_OK, (uint8_t*)&apdu, sizeof(apdu));
 }
 
 void sap_transfer_atr_req(void *sap_device)
 {
-	sap_transfer_atr_rsp(sap_device, SAP_RESULT_OK, NULL, 0);
+	char atr[] = "ATR response!";
+
+	DBG("status: %d", sim_card_conn_status);
+
+	if (sim_card_conn_status == SIM_MISSING)
+		sap_transfer_atr_rsp(sap_device, SAP_RESULT_ERROR_CARD_REMOVED,
+								NULL, 0);
+	else if (sim_card_conn_status == SIM_POWERED_OFF)
+		sap_transfer_atr_rsp(sap_device, SAP_RESULT_ERROR_POWERED_OFF,
+								NULL, 0);
+	else if (sim_card_conn_status != SIM_CONNECTED)
+		sap_transfer_atr_rsp(sap_device, SAP_RESULT_ERROR_NO_REASON,
+								NULL, 0);
+	else
+		sap_transfer_atr_rsp(sap_device, SAP_RESULT_OK, (uint8_t*)&atr, sizeof(atr));
 }
 
 void sap_power_sim_off_req(void *sap_device)
 {
-	sap_power_sim_off_rsp(sap_device, SAP_RESULT_OK);
+	DBG("status: %d", sim_card_conn_status);
+
+	if (sim_card_conn_status == SIM_MISSING) {
+		sap_power_sim_off_rsp(sap_device,
+					SAP_RESULT_ERROR_CARD_REMOVED);
+	} else if (sim_card_conn_status == SIM_POWERED_OFF) {
+		sap_power_sim_off_rsp(sap_device,
+					SAP_RESULT_ERROR_POWERED_OFF);
+	} else if (sim_card_conn_status != SIM_CONNECTED) {
+		sap_power_sim_off_rsp(sap_device,
+					SAP_RESULT_ERROR_NO_REASON);
+	} else {
+		sap_power_sim_off_rsp(sap_device, SAP_RESULT_OK);
+		sim_card_conn_status = SIM_POWERED_OFF;
+	}
 }
 
 void sap_power_sim_on_req(void *sap_device)
 {
-	sap_power_sim_on_rsp(sap_device, SAP_RESULT_OK);
+	DBG("status: %d", sim_card_conn_status);
+
+	if (sim_card_conn_status == SIM_MISSING) {
+		sap_power_sim_on_rsp(sap_device,
+					SAP_RESULT_ERROR_CARD_REMOVED);
+	} else if (sim_card_conn_status == SIM_POWERED_OFF) {
+		sap_power_sim_on_rsp(sap_device, SAP_RESULT_OK);
+		sim_card_conn_status = SIM_CONNECTED;
+		return;
+	} else if (sim_card_conn_status != SIM_CONNECTED) {
+		sap_power_sim_on_rsp(sap_device,
+					SAP_RESULT_ERROR_NOT_ACCESSIBLE);
+	} else {
+		sap_power_sim_on_rsp(sap_device,
+					SAP_RESULT_ERROR_NO_REASON);
+	}
 }
 
 void sap_reset_sim_req(void *sap_device)
 {
-	sap_reset_sim_rsp(sap_device, SAP_RESULT_OK);
-	sap_status_ind(sap_device, SAP_STATUS_CHANGE_CARD_RESET);
+	DBG("status: %d", sim_card_conn_status);
+
+	if (sim_card_conn_status == SIM_MISSING) {
+		sap_reset_sim_rsp(sap_device, SAP_RESULT_ERROR_CARD_REMOVED);
+	} else if (sim_card_conn_status == SIM_POWERED_OFF) {
+		sap_reset_sim_rsp(sap_device, SAP_RESULT_ERROR_POWERED_OFF);
+	} else if (sim_card_conn_status != SIM_CONNECTED) {
+		sap_reset_sim_rsp(sap_device, SAP_RESULT_ERROR_NO_REASON);
+	} else {
+		sap_reset_sim_rsp(sap_device, SAP_RESULT_OK);
+	}
 }
 
 void sap_transfer_card_reader_status_req(void *sap_device)
 {
-	sap_transfer_card_reader_status_rsp(sap_device, SAP_RESULT_OK,
-						ICC_READER_CARD_POWERED_ON);
+	DBG("status: %d", sim_card_conn_status);
+
+	if (sim_card_conn_status != SIM_CONNECTED) {
+		sap_transfer_card_reader_status_rsp(sap_device,
+					SAP_RESULT_ERROR_NO_REASON, 0xF1);
+		return;
+	}
+	sap_transfer_card_reader_status_rsp(sap_device, SAP_RESULT_OK, 0xF1);
 }
 
-void sap_set_transport_protocol_req(void * sap_device,
+void sap_set_transport_protocol_req(void *sap_device,
 					struct sap_parameter *param)
 {
 	sap_transport_protocol_rsp(sap_device, SAP_RESULT_NOT_SUPPORTED);
 }
 
+static inline DBusMessage *invalid_args(DBusMessage *msg)
+{
+	return g_dbus_create_error(msg, "org.bluez.Error.InvalidArguments",
+					"Invalid arguments in method call");
+}
+
+static DBusMessage *ongoing_call(DBusConnection *conn, DBusMessage *msg,
+						void *data)
+{
+	dbus_bool_t ongoing;
+
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_BOOLEAN, &ongoing,
+						DBUS_TYPE_INVALID))
+		return invalid_args(msg);
+
+	if (ongoing_call_status && !ongoing) {
+		/* An ongoing call has finished. Continue connection.*/
+		sap_connect_rsp(sap_data, SAP_STATUS_OK,
+						max_msg_size_supported);
+		sap_status_ind(sap_data, SAP_STATUS_CHANGE_CARD_RESET);
+		ongoing_call_status = ongoing;
+	} else if (!ongoing_call_status && ongoing) {
+		/* An ongoing call has started.*/
+		ongoing_call_status = ongoing;
+	}
+
+	DBG("OngoingCall status set to %d", ongoing_call_status);
+
+	return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *max_msg_size(DBusConnection *conn, DBusMessage *msg,
+						void *data)
+{
+	dbus_uint32_t size;
+
+	if (sim_card_conn_status == SIM_CONNECTED)
+		return g_dbus_create_error(msg, "org.bluez.Error.Failed",
+				"Can't change msg size when connected.");
+
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &size,
+						DBUS_TYPE_INVALID))
+		return invalid_args(msg);
+
+	max_msg_size_supported = size;
+
+	DBG("MaxMessageSize set to %d", max_msg_size_supported);
+
+	return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *disconnect(DBusConnection *conn, DBusMessage *msg,
+						void *data)
+{
+	sim_card_conn_status = SIM_DISCONNECTED;
+	sap_status_ind(sap_data, SAP_STATUS_CHANGE_CARD_NOT_ACCESSIBLE);
+
+	return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *card_status(DBusConnection *conn, DBusMessage *msg,
+						void *data)
+{
+	dbus_uint32_t status;
+
+	DBG("status %d", sim_card_conn_status);
+
+	if (sim_card_conn_status != SIM_CONNECTED)
+		return g_dbus_create_error(msg, "org.bluez.Error.Failed",
+				"Can't change msg size when not connected.");
+
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &status,
+						DBUS_TYPE_INVALID))
+		return invalid_args(msg);
+
+	if (status) {
+		if (sim_card_conn_status == SIM_MISSING) {
+			sim_card_conn_status = SIM_CONNECTED;
+			sap_status_ind(sap_data,
+					SAP_STATUS_CHANGE_CARD_INSERTED);
+		}
+	} else {
+		sim_card_conn_status = SIM_MISSING;
+		sap_status_ind(sap_data, SAP_STATUS_CHANGE_CARD_REMOVED);
+	}
+
+	DBG("Card status changed to %d", status);
+
+	return dbus_message_new_method_return(msg);
+}
+
+static GDBusMethodTable dummy_methods[] = {
+	{ "OngoingCall",	"b",	"",	ongoing_call},
+	{ "MaxMessageSize",	"u",	"",	max_msg_size},
+	{ "Disconnect",		"",	"",	disconnect},
+	{ "CardStatus",		"u",	"",	card_status},
+	{ }
+};
+
 int sap_init(void)
 {
-	DBG("SAP driver init.");
+	connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+
+	if (g_dbus_register_interface(connection, SAP_DUMMY_PATH,
+					SAP_DUMMY_IFACE,
+					dummy_methods, NULL,
+					NULL, NULL, NULL) == FALSE) {
+		error("sap-dummy interface %s init failed on path %s",
+			SAP_DUMMY_IFACE, SAP_DUMMY_PATH);
+		return -1;
+	}
+
 	return 0;
 }
 
 void sap_exit(void)
 {
-	DBG("SAP driver exit.");
+	dbus_connection_unref(connection);
+	connection = NULL;
 }
-- 
1.7.1


^ permalink raw reply related

* [PATCH v2 3/4] Sim Access Profile Server
From: Waldemar Rymarkiewicz @ 2011-02-24 12:13 UTC (permalink / raw)
  To: linux-bluetooth
  Cc: Johan Hedberg, padovan, Marcel Holtmann, Waldemar Rymarkiewicz
In-Reply-To: <1298549606-16594-1-git-send-email-waldemar.rymarkiewicz@tieto.com>

Add a Sim Access Server to the SAP plugin and a framework for the dummy
sap driver as well.
---
 Makefile.am     |    3 +-
 sap/sap-dummy.c |   83 ++++
 sap/sap.h       |  192 ++++++++
 sap/server.c    | 1393 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 1662 insertions(+), 9 deletions(-)
 create mode 100644 sap/sap-dummy.c
 create mode 100644 sap/sap.h

diff --git a/Makefile.am b/Makefile.am
index 49c45c1..af374a9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -147,7 +147,8 @@ if SAPPLUGIN
 builtin_modules += sap
 builtin_sources += sap/main.c \
 			sap/manager.h sap/manager.c \
-			sap/server.h sap/server.c
+			sap/server.h sap/server.c \
+			sap/sap.h sap/sap-dummy.c
 endif
 
 if INPUTPLUGIN
diff --git a/sap/sap-dummy.c b/sap/sap-dummy.c
new file mode 100644
index 0000000..92d73ef
--- /dev/null
+++ b/sap/sap-dummy.c
@@ -0,0 +1,83 @@
+/*
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2010 ST-Ericsson SA
+ *
+ *  Author: Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com> for ST-Ericsson
+ *
+ *  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; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "log.h"
+#include "sap.h"
+
+void sap_connect_req(void *sap_device, uint16_t maxmsgsize)
+{
+	sap_connect_rsp(sap_device, SAP_STATUS_OK, maxmsgsize);
+	sap_status_ind(sap_device, SAP_STATUS_CHANGE_CARD_RESET);
+}
+
+void sap_disconnect_req(void *sap_device, uint8_t linkloss)
+{
+	sap_disconnect_rsp(sap_device);
+}
+
+void sap_transfer_apdu_req(void *sap_device, struct sap_parameter *param)
+{
+	sap_transfer_apdu_rsp(sap_device, SAP_RESULT_OK, NULL, 0);
+}
+
+void sap_transfer_atr_req(void *sap_device)
+{
+	sap_transfer_atr_rsp(sap_device, SAP_RESULT_OK, NULL, 0);
+}
+
+void sap_power_sim_off_req(void *sap_device)
+{
+	sap_power_sim_off_rsp(sap_device, SAP_RESULT_OK);
+}
+
+void sap_power_sim_on_req(void *sap_device)
+{
+	sap_power_sim_on_rsp(sap_device, SAP_RESULT_OK);
+}
+
+void sap_reset_sim_req(void *sap_device)
+{
+	sap_reset_sim_rsp(sap_device, SAP_RESULT_OK);
+	sap_status_ind(sap_device, SAP_STATUS_CHANGE_CARD_RESET);
+}
+
+void sap_transfer_card_reader_status_req(void *sap_device)
+{
+	sap_transfer_card_reader_status_rsp(sap_device, SAP_RESULT_OK,
+						ICC_READER_CARD_POWERED_ON);
+}
+
+void sap_set_transport_protocol_req(void * sap_device,
+					struct sap_parameter *param)
+{
+	sap_transport_protocol_rsp(sap_device, SAP_RESULT_NOT_SUPPORTED);
+}
+
+int sap_init(void)
+{
+	DBG("SAP driver init.");
+	return 0;
+}
+
+void sap_exit(void)
+{
+	DBG("SAP driver exit.");
+}
diff --git a/sap/sap.h b/sap/sap.h
new file mode 100644
index 0000000..7154e96
--- /dev/null
+++ b/sap/sap.h
@@ -0,0 +1,192 @@
+/*
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2010 Instituto Nokia de Tecnologia - INdT
+ *  Copyright (C) 2010 ST-Ericsson SA
+ *
+ *  Author: Marek Skowron <marek.skowron@tieto.com> for ST-Ericsson.
+ *  Author: Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com>
+ *          for ST-Ericsson.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <stdint.h>
+#include <glib.h>
+
+ #define SAP_VERSION 0x0101
+
+/* Connection Status - SAP v1.1 section 5.2.2 */
+typedef enum {
+	SAP_STATUS_OK				= 0x00,
+	SAP_STATUS_CONNECTION_FAILED		= 0x01,
+	SAP_STATUS_MAX_MSG_SIZE_NOT_SUPPORTED	= 0x02,
+	SAP_STATUS_MAX_MSG_SIZE_TOO_SMALL	= 0x03,
+	SAP_STATUS_OK_ONGOING_CALL		= 0x04
+} sap_status_t;
+
+/* Disconnection Type - SAP v1.1 section 5.2.3 */
+typedef enum {
+	SAP_DISCONNECTION_TYPE_GRACEFUL		= 0x00,
+	SAP_DISCONNECTION_TYPE_IMMEDIATE	= 0x01,
+	SAP_DISCONNECTION_TYPE_CLIENT		= 0xFF
+} sap_disconnection_type_t;
+
+/* Result codes - SAP v1.1 section 5.2.4 */
+typedef enum {
+	SAP_RESULT_OK			= 0x00,
+	SAP_RESULT_ERROR_NO_REASON	= 0x01,
+	SAP_RESULT_ERROR_NOT_ACCESSIBLE	= 0x02,
+	SAP_RESULT_ERROR_POWERED_OFF	= 0x03,
+	SAP_RESULT_ERROR_CARD_REMOVED	= 0x04,
+	SAP_RESULT_ERROR_POWERED_ON	= 0x05,
+	SAP_RESULT_ERROR_NO_DATA	= 0x06,
+	SAP_RESULT_NOT_SUPPORTED	= 0x07
+} sap_result_t;
+
+/* Status Change - SAP v1.1 section 5.2.8 */
+typedef enum {
+	SAP_STATUS_CHANGE_UNKNOWN_ERROR		= 0x00,
+	SAP_STATUS_CHANGE_CARD_RESET		= 0x01,
+	SAP_STATUS_CHANGE_CARD_NOT_ACCESSIBLE	= 0x02,
+	SAP_STATUS_CHANGE_CARD_REMOVED		= 0x03,
+	SAP_STATUS_CHANGE_CARD_INSERTED		= 0x04,
+	SAP_STATUS_CHANGE_CARD_RECOVERED	= 0x05
+} sap_status_change_t;
+
+/* Message format - SAP v1.1 section 5.1 */
+struct sap_parameter {
+	uint8_t id;
+	uint8_t reserved;
+	uint16_t len;
+	uint8_t val[0];
+	/*
+	 * Padding bytes 0-3 bytes
+	 */
+} __attribute__ ((packed));
+
+struct sap_message {
+	uint8_t id;
+	uint8_t nparam;
+	uint16_t reserved;
+	struct sap_parameter param[0];
+} __attribute__ ((packed));
+
+typedef enum {
+	ICC_READER_UNSPECIFIED_ERROR, /* No further information available */
+	ICC_READER_NOT_PRESENT,       /* Card Reader removed or not present */
+	ICC_READER_BUSY,              /* Card Reader in use */
+	ICC_READER_CARD_POWERED_ON,   /* Card in reader and is powered on */
+	ICC_READER_DEACTIVATED,       /* Card Reader deactivated */
+	ICC_READER_CARD_POWERED_OFF,  /* Card in reader, but powered off */
+	ICC_READER_NO_CARD,           /* No card in reader */
+	ICC_READER_LAST
+} icc_reader_status_t;
+
+#define SAP_BUF_SIZE		512
+
+#define SAP_MSG_HEADER_SIZE	4
+
+enum sap_protocol {
+	SAP_CONNECT_REQ		= 0x00,
+	SAP_CONNECT_RESP	= 0x01,
+	SAP_DISCONNECT_REQ	= 0x02,
+	SAP_DISCONNECT_RESP	= 0x03,
+	SAP_DISCONNECT_IND	= 0x04,
+	SAP_TRANSFER_APDU_REQ	= 0x05,
+	SAP_TRANSFER_APDU_RESP	= 0x06,
+	SAP_TRANSFER_ATR_REQ	= 0x07,
+	SAP_TRANSFER_ATR_RESP	= 0x08,
+	SAP_POWER_SIM_OFF_REQ	= 0x09,
+	SAP_POWER_SIM_OFF_RESP	= 0x0A,
+	SAP_POWER_SIM_ON_REQ	= 0x0B,
+	SAP_POWER_SIM_ON_RESP	= 0x0C,
+	SAP_RESET_SIM_REQ	= 0x0D,
+	SAP_RESET_SIM_RESP	= 0x0E,
+	SAP_TRANSFER_CARD_READER_STATUS_REQ	= 0x0F,
+	SAP_TRANSFER_CARD_READER_STATUS_RESP	= 0x10,
+	SAP_STATUS_IND	= 0x11,
+	SAP_ERROR_RESP	= 0x12,
+	SAP_SET_TRANSPORT_PROTOCOL_REQ	= 0x13,
+	SAP_SET_TRANSPORT_PROTOCOL_RESP	= 0x14,
+};
+
+/* Parameters Ids - SAP 1.1 section 5.2 */
+#define SAP_PARAM_ID_MAX_MSG_SIZE		0x00
+#define SAP_PARAM_ID_MAX_MSG_SIZE_LEN		0x02
+
+#define SAP_PARAM_ID_CONN_STATUS		0x01
+#define SAP_PARAM_ID_CONN_STATUS_LEN		0x01
+
+#define SAP_PARAM_ID_RESULT_CODE		0x02
+#define SAP_PARAM_ID_RESULT_CODE_LEN		0x01
+
+#define SAP_PARAM_ID_DISCONNECT_IND		0x03
+#define SAP_PARAM_ID_DISCONNECT_IND_LEN		0x01
+
+#define SAP_PARAM_ID_COMMAND_APDU		0x04
+#define SAP_PARAM_ID_RESPONSE_APDU		0x05
+#define SAP_PARAM_ID_ATR			0x06
+
+#define SAP_PARAM_ID_CARD_READER_STATUS		0x07
+#define SAP_PARAM_ID_CARD_READER_STATUS_LEN	0x01
+
+#define SAP_PARAM_ID_STATUS_CHANGE		0x08
+#define SAP_PARAM_ID_STATUS_CHANGE_LEN		0x01
+
+#define SAP_PARAM_ID_TRANSPORT_PROTOCOL		0x09
+#define SAP_PARAM_ID_TRANSPORT_PROTOCOL_LEN	0x01
+
+#define SAP_PARAM_ID_COMMAND_APDU7816		0x10
+
+/* Transport Protocol - SAP v1.1 section 5.2.9 */
+#define SAP_TRANSPORT_PROTOCOL_T0		0x00
+#define SAP_TRANSPORT_PROTOCOL_T1		0x01
+
+/*SAP driver init and exit routines. Implemented by sap-*.c */
+int sap_init(void);
+void sap_exit(void);
+
+/* SAP requests implemented by sap-*.c */
+void sap_connect_req(void *sap_device, uint16_t maxmsgsize);
+void sap_disconnect_req(void *sap_device, uint8_t linkloss);
+void sap_transfer_apdu_req(void *sap_device, struct sap_parameter *param);
+void sap_transfer_atr_req(void *sap_device);
+void sap_power_sim_off_req(void *sap_device);
+void sap_power_sim_on_req(void *sap_device);
+void sap_reset_sim_req(void *sap_device);
+void sap_transfer_card_reader_status_req(void *sap_device);
+void sap_set_transport_protocol_req(void *sap_device,
+					struct sap_parameter *param);
+
+/*SAP responses to SAP requests. Implemented by server.c */
+int sap_connect_rsp(void *sap_device, sap_status_t status,
+						uint16_t maxmsgsize);
+int sap_disconnect_rsp(void *sap_device);
+int sap_transfer_apdu_rsp(void *sap_device, sap_result_t result,
+				uint8_t *sap_apdu_resp, uint16_t length);
+int sap_transfer_atr_rsp(void *sap_device, sap_result_t result,
+				uint8_t *sap_atr, uint16_t length);
+int sap_power_sim_off_rsp(void *sap_device, sap_result_t result);
+int sap_power_sim_on_rsp(void *sap_device, sap_result_t result);
+int sap_reset_sim_rsp(void *sap_device, sap_result_t result);
+int sap_transfer_card_reader_status_rsp(void *sap_device, sap_result_t result,
+						icc_reader_status_t status);
+int sap_error_rsp(void *sap_device);
+int sap_transport_protocol_rsp(void *sap_device, sap_result_t result);
+
+/* Event indication. Implemented by server.c*/
+int sap_status_ind(void *sap_device, sap_status_change_t status_change);
+
diff --git a/sap/server.c b/sap/server.c
index 2728778..649a96f 100644
--- a/sap/server.c
+++ b/sap/server.c
@@ -1,13 +1,18 @@
 /*
  *  BlueZ - Bluetooth protocol stack for Linux
  *
+ *  Copyright (C) 2010 Instituto Nokia de Tecnologia - INdT
  *  Copyright (C) 2010 ST-Ericsson SA
+ *  Copyright (C) 2011 Tieto
  *
- *  Author: Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com> for ST-Ericsson.
+ *  Author: Marek Skowron <marek.skowron@tieto.com> for ST-Ericsson.
+ *  Author: Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com>
+            for ST-Ericsson.
  *
  *  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; version 2 of the License.
+ *  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
@@ -19,30 +24,1402 @@
  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-#include "bluetooth.h"
-#include "log.h"
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <glib.h>
+#include <netinet/in.h>
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
 
+#include "adapter.h"
+#include "btio.h"
+#include "sdpd.h"
+#include "log.h"
+#include "error.h"
+#include "dbus-common.h"
+#include "sap.h"
 #include "server.h"
 
+#define SAP_SERVER_INTERFACE	"org.bluez.SimAccess"
+#define SAP_UUID		"0000112D-0000-1000-8000-00805F9B34FB"
+#define SAP_SERVER_CHANNEL	8
+#define SAP_BUF_SIZE		512
+
+#define PADDING4(x) (4 - (x & 0x03))
+#define PARAMETER_SIZE(x) (sizeof(struct sap_parameter) + x + PADDING4(x))
+
+#define SAP_NO_REQ 0xFF
+
+#define SAP_TIMER_GRACEFUL_DISCONNECT 30
+#define SAP_TIMER_NO_ACTIVITY 30
+
+enum {
+	SAP_STATE_DISCONNECTED,
+	SAP_STATE_CONNECT_IN_PROGRESS,
+	SAP_STATE_CONNECTED,
+	SAP_STATE_GRACEFUL_DISCONNECT,
+	SAP_STATE_IMMEDIATE_DISCONNECT,
+	SAP_STATE_CLIENT_DISCONNECT
+};
+
+struct sap_connection {
+	GIOChannel *io;
+	uint32_t state;
+	uint8_t processing_req;
+	guint timer_id;
+};
+
+struct sap_server {
+	bdaddr_t src;
+	char *path;
+	uint32_t record_id;
+	GIOChannel *listen_io;
+	struct sap_connection *conn;
+};
+
+static DBusConnection *connection = NULL;
+static struct sap_server *server = NULL;
+
+static void start_guard_timer(struct sap_connection *conn, guint interval);
+static void stop_guard_timer(struct sap_connection *conn);
+static gboolean guard_timeout(gpointer data);
+
+static size_t add_result_parameter(sap_result_t result,
+					struct sap_parameter *param)
+{
+	param->id = SAP_PARAM_ID_RESULT_CODE;
+	param->len = htons(SAP_PARAM_ID_RESULT_CODE_LEN);
+	*param->val = (uint8_t) result;
+	return PARAMETER_SIZE(SAP_PARAM_ID_RESULT_CODE_LEN);
+}
+
+static int is_power_sim_off_req_allowed(uint8_t processing_req)
+{
+	switch (processing_req) {
+	case SAP_NO_REQ:
+	case SAP_TRANSFER_APDU_REQ:
+	case SAP_TRANSFER_ATR_REQ:
+	case SAP_POWER_SIM_ON_REQ:
+	case SAP_RESET_SIM_REQ:
+	case SAP_TRANSFER_CARD_READER_STATUS_REQ:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+static int is_reset_sim_req_allowed(uint8_t processing_req)
+{
+	switch (processing_req) {
+	case SAP_NO_REQ:
+	case SAP_TRANSFER_APDU_REQ:
+	case SAP_TRANSFER_ATR_REQ:
+	case SAP_TRANSFER_CARD_READER_STATUS_REQ:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+static int check_msg(struct sap_message *msg)
+{
+	if (!msg)
+		return -EFAULT;
+
+	switch (msg->id) {
+	case SAP_CONNECT_REQ:
+		if (msg->nparam == 0x01 &&
+				msg->param->id == SAP_PARAM_ID_MAX_MSG_SIZE &&
+				ntohs(msg->param->len) == SAP_PARAM_ID_MAX_MSG_SIZE_LEN)
+			return 0;
+		break;
+	case SAP_TRANSFER_APDU_REQ:
+		if (msg->nparam == 0x01 &&
+				(msg->param->id == SAP_PARAM_ID_COMMAND_APDU ||
+				msg->param->id == SAP_PARAM_ID_COMMAND_APDU7816) &&
+				msg->param->len != 0x00)
+			return 0;
+		break;
+	case SAP_SET_TRANSPORT_PROTOCOL_REQ:
+		if (msg->nparam == 0x01 &&
+				msg->param->id == SAP_PARAM_ID_TRANSPORT_PROTOCOL &&
+				ntohs(msg->param->len) == SAP_PARAM_ID_TRANSPORT_PROTOCOL_LEN &&
+				(*msg->param->val  == SAP_TRANSPORT_PROTOCOL_T0 ||
+				*msg->param->val == SAP_TRANSPORT_PROTOCOL_T1))
+			return 0;
+		break;
+	case SAP_DISCONNECT_REQ:
+	case SAP_TRANSFER_ATR_REQ:
+	case SAP_POWER_SIM_OFF_REQ:
+	case SAP_POWER_SIM_ON_REQ:
+	case SAP_RESET_SIM_REQ:
+	case SAP_TRANSFER_CARD_READER_STATUS_REQ:
+		if (msg->nparam == 0x00)
+			return 0;
+		break;
+	}
+
+	error("Invalid message");
+	return -EBADMSG;
+}
+
+static sdp_record_t *create_sap_record(uint8_t channel)
+{
+	sdp_list_t *apseq, *aproto, *profiles, *proto[2], *root, *svclass_id;
+	uuid_t sap_uuid, gt_uuid, root_uuid, l2cap, rfcomm;
+	sdp_profile_desc_t profile;
+	sdp_record_t *record;
+	sdp_data_t *ch;
+
+	record = sdp_record_alloc();
+	if (!record)
+		return NULL;
+
+	root = sdp_list_append(NULL, &root_uuid);
+	sdp_set_browse_groups(record, root);
+	sdp_list_free(root, NULL);
+
+	sdp_uuid16_create(&sap_uuid, SAP_SVCLASS_ID);
+	svclass_id = sdp_list_append(NULL, &sap_uuid);
+	sdp_uuid16_create(&gt_uuid, GENERIC_TELEPHONY_SVCLASS_ID);
+	svclass_id = sdp_list_append(svclass_id, &gt_uuid);
+
+	sdp_set_service_classes(record, svclass_id);
+	sdp_list_free(svclass_id, NULL);
+
+	sdp_uuid16_create(&profile.uuid, SAP_PROFILE_ID);
+	profile.version = SAP_VERSION;
+	profiles = sdp_list_append(NULL, &profile);
+	sdp_set_profile_descs(record, profiles);
+	sdp_list_free(profiles, NULL);
+
+	sdp_uuid16_create(&l2cap, L2CAP_UUID);
+	proto[0] = sdp_list_append(NULL, &l2cap);
+	apseq = sdp_list_append(NULL, proto[0]);
+
+	sdp_uuid16_create(&rfcomm, RFCOMM_UUID);
+	proto[1] = sdp_list_append(NULL, &rfcomm);
+	ch = sdp_data_alloc(SDP_UINT8, &channel);
+	proto[1] = sdp_list_append(proto[1], ch);
+	apseq = sdp_list_append(apseq, proto[1]);
+
+	aproto = sdp_list_append(NULL, apseq);
+	sdp_set_access_protos(record, aproto);
+
+	sdp_set_info_attr(record, "SIM Access Server",
+			NULL, NULL);
+
+	sdp_data_free(ch);
+	sdp_list_free(proto[0], NULL);
+	sdp_list_free(proto[1], NULL);
+	sdp_list_free(apseq, NULL);
+	sdp_list_free(aproto, NULL);
+
+	return record;
+}
+
+static int send_message(struct sap_connection *conn, void *buf, gssize size)
+{
+	gsize written = 0;
+	GError *gerr = NULL;
+	GIOStatus gstatus;
+
+	if (!conn || !buf)
+		return -1;
+
+	DBG("size = %d",(unsigned int)size);
+
+	gstatus = g_io_channel_write_chars(conn->io, buf, size, &written,
+							&gerr);
+
+	if (gstatus != G_IO_STATUS_NORMAL) {
+		if (gerr)
+			g_error_free(gerr);
+
+		error("write error (%d).", gstatus);
+		return -1;
+	}
+
+	if (written != (gsize)size)
+		error("write error.(written %d size %d)", written, size);
+
+	return 0;
+}
+
+static int disconnect_ind(void *sap_device, sap_disconnection_type_t type)
+{
+	struct sap_connection *conn = sap_device;
+	char buf[SAP_BUF_SIZE];
+	struct sap_message *msg = (struct sap_message *) buf;
+	struct sap_parameter *param = (struct sap_parameter *) msg->param;
+	size_t size = sizeof(struct sap_message);
+
+	if (!conn)
+		return -1;
+
+	DBG("data %p state %d disc_type %d",conn, conn->state, type);
+
+	if (conn->state != SAP_STATE_GRACEFUL_DISCONNECT &&
+			conn->state != SAP_STATE_IMMEDIATE_DISCONNECT) {
+		error("Processing error (state %.2X pr %.2X param)",
+			conn->state, conn->processing_req);
+		return -EPERM;
+	}
+
+	memset(buf, 0, sizeof(buf));
+	msg->id = SAP_DISCONNECT_IND;
+	msg->nparam = 0x01;
+
+	/* Add disconnection type param. */
+	param->id  = SAP_PARAM_ID_DISCONNECT_IND;
+	param->len = htons(SAP_PARAM_ID_DISCONNECT_IND_LEN);
+	*param->val = (uint8_t) type;
+	size += PARAMETER_SIZE(SAP_PARAM_ID_DISCONNECT_IND_LEN);
+
+	return send_message(sap_device, buf, size);
+}
+
+static void connect_req(struct sap_connection *conn, struct sap_parameter *param)
+{
+	uint16_t maxmsgsize, *val;
+
+	DBG("conn %p state %d", conn, conn->state);
+
+	if (!param)
+		goto error_rsp;
+
+	if (conn->state != SAP_STATE_DISCONNECTED) {
+		goto error_rsp;
+	}
+
+	stop_guard_timer(conn);
+
+	val = (uint16_t *) &param->val;
+	maxmsgsize = ntohs(*val);
+
+	DBG("Connect MaxMsgSize: 0x%04X(%d)", maxmsgsize, maxmsgsize);
+
+	conn->state = SAP_STATE_CONNECT_IN_PROGRESS;
+
+	if (maxmsgsize <= SAP_BUF_SIZE) {
+		conn->processing_req = SAP_CONNECT_REQ;
+		sap_connect_req(conn, maxmsgsize);
+	} else {
+		sap_connect_rsp(conn, SAP_STATUS_MAX_MSG_SIZE_NOT_SUPPORTED,
+								SAP_BUF_SIZE);
+	}
+
+	return;
+
+error_rsp:
+	error("Processing error (param %p state %.2X pr %.2X param)",
+		param, conn->state, conn->processing_req);
+	sap_error_rsp(conn);
+}
+
+static int disconnect_req(struct sap_connection *conn
+				, sap_disconnection_type_t disc_type)
+{
+
+	DBG("conn %p type 0x%.2X state %d", conn, disc_type, conn->state);
+
+	switch (disc_type) {
+	case SAP_DISCONNECTION_TYPE_GRACEFUL:
+
+		if (conn->state == SAP_STATE_DISCONNECTED ||
+				conn->state == SAP_STATE_CONNECT_IN_PROGRESS)
+			goto error_req;
+
+		if (conn->state == SAP_STATE_CONNECTED) {
+			conn->state = SAP_STATE_GRACEFUL_DISCONNECT;
+			conn->processing_req = SAP_NO_REQ;
+			disconnect_ind(conn, disc_type);
+
+			/* Start guard timer - timer will disconnect
+			 * connection if client doesn't do it. */
+			start_guard_timer(conn,
+					SAP_TIMER_GRACEFUL_DISCONNECT);
+
+			return 0;
+		}
+		/* Disconnection is ongoing - do nothing. */
+		return 0;
+
+	case SAP_DISCONNECTION_TYPE_IMMEDIATE:
+
+		if (conn->state == SAP_STATE_DISCONNECTED ||
+				conn->state == SAP_STATE_CONNECT_IN_PROGRESS)
+			goto error_req;
+
+		if (conn->state == SAP_STATE_CONNECTED ||
+				conn->state == SAP_STATE_GRACEFUL_DISCONNECT) {
+			conn->state = SAP_STATE_IMMEDIATE_DISCONNECT;
+			conn->processing_req = SAP_NO_REQ;
+
+			stop_guard_timer(conn);
+
+			disconnect_ind(conn, disc_type);
+			sap_disconnect_req(conn, 0);
+
+			return 0;
+		}
+		/* Disconnection is ongoing - do nothing. */
+		return 0;
+
+	case SAP_DISCONNECTION_TYPE_CLIENT:
+
+		if (conn->state != SAP_STATE_CONNECTED &&
+				conn->state != SAP_STATE_GRACEFUL_DISCONNECT)
+			goto error_rsp;
+
+		conn->state = SAP_STATE_CLIENT_DISCONNECT;
+		conn->processing_req = SAP_NO_REQ;
+
+		stop_guard_timer(conn);
+
+		sap_disconnect_req(conn, 0);
+
+		return 0;
+
+	default:
+		error("Unknown disconnection type (type %x).", disc_type);
+		return -EINVAL;
+	}
+
+error_rsp:
+	sap_error_rsp(conn);
+error_req:
+	error("Processing error (state %.2X pr %.2X param)", conn->state,
+			conn->processing_req);
+	return -EPERM;
+}
+
+static void transfer_apdu_req(struct sap_connection *conn,
+					struct sap_parameter *param)
+{
+	DBG("conn %p state %d", conn, conn->state);
+
+	if (!param)
+		goto error_rsp;
+
+	param->len = ntohs(param->len);
+
+	if (conn->state != SAP_STATE_CONNECTED &&
+			conn->state != SAP_STATE_GRACEFUL_DISCONNECT)
+		goto error_rsp;
+
+	if (conn->processing_req != SAP_NO_REQ)
+		goto error_rsp;
+
+	conn->processing_req = SAP_TRANSFER_APDU_REQ;
+	sap_transfer_apdu_req(conn, param);
+	return;
+
+error_rsp:
+	error("Processing error (param %p state %.2X pr %.2X param)", param,
+			conn->state, conn->processing_req);
+	sap_error_rsp(conn);
+}
+
+static void transfer_atr_req(struct sap_connection *conn)
+{
+	DBG("conn %p state %d", conn, conn->state);
+
+	if (conn->state != SAP_STATE_CONNECTED)
+		goto error_rsp;
+
+	if (conn->processing_req != SAP_NO_REQ)
+		goto error_rsp;
+
+	conn->processing_req = SAP_TRANSFER_ATR_REQ;
+	sap_transfer_atr_req(conn);
+	return;
+
+error_rsp:
+	error("Processing error (state %.2X pr %.2X param)", conn->state,
+		conn->processing_req);
+	sap_error_rsp(conn);
+}
+
+static void power_sim_off_req(struct sap_connection *conn)
+{
+	DBG("conn %p state %d", conn, conn->state);
+
+	if (conn->state != SAP_STATE_CONNECTED)
+		goto error_rsp;
+
+	if (!is_power_sim_off_req_allowed(conn->processing_req))
+		goto error_rsp;
+
+	conn->processing_req = SAP_POWER_SIM_OFF_REQ;
+	sap_power_sim_off_req(conn);
+	return;
+
+error_rsp:
+	error("Processing error (state %.2X pr %.2X param)", conn->state,
+		conn->processing_req);
+	sap_error_rsp(conn);
+}
+
+static void power_sim_on_req(struct sap_connection *conn)
+{
+	DBG("conn %p state %d", conn, conn->state);
+
+	if (conn->state != SAP_STATE_CONNECTED)
+		goto error_rsp;
+
+	if (conn->processing_req != SAP_NO_REQ)
+		goto error_rsp;
+
+	conn->processing_req = SAP_POWER_SIM_ON_REQ;
+	sap_power_sim_on_req(conn);
+	return;
+
+error_rsp:
+	error("Processing error (state %.2X pr %.2X param)", conn->state,
+		conn->processing_req);
+	sap_error_rsp(conn);
+}
+
+static void reset_sim_req(struct sap_connection *conn)
+{
+	DBG("conn %p state %d", conn, conn->state);
+
+	if (conn->state != SAP_STATE_CONNECTED)
+		goto error_rsp;
+
+	if (!is_reset_sim_req_allowed(conn->processing_req))
+		goto error_rsp;
+
+	conn->processing_req = SAP_RESET_SIM_REQ;
+	sap_reset_sim_req(conn);
+	return;
+
+error_rsp:
+	error("Processing error (state %.2X pr %.2X param)", conn->state,
+			conn->processing_req);
+	sap_error_rsp(conn);
+}
+
+static void transfer_card_reader_status_req(struct sap_connection *conn)
+{
+	DBG("conn %p state %d", conn, conn->state);
+
+	if (conn->state != SAP_STATE_CONNECTED)
+		goto error_rsp;
+
+	if (conn->processing_req != SAP_NO_REQ)
+		goto error_rsp;
+
+	conn->processing_req = SAP_TRANSFER_CARD_READER_STATUS_REQ;
+	sap_transfer_card_reader_status_req(conn);
+	return;
+
+error_rsp:
+	error("Processing error (state %.2X pr %.2X param)", conn->state,
+			conn->processing_req);
+	sap_error_rsp(conn);
+}
+
+static void set_transport_protocol_req(struct sap_connection *conn,
+					struct sap_parameter *param)
+{
+	if (!param)
+		goto error_rsp;
+
+	DBG("conn %p state %d param %p", conn, conn->state, param);
+
+	if (conn->state != SAP_STATE_CONNECTED)
+		goto error_rsp;
+
+	if (conn->processing_req != SAP_NO_REQ)
+		goto error_rsp;
+
+	conn->processing_req = SAP_SET_TRANSPORT_PROTOCOL_REQ;
+	sap_set_transport_protocol_req(conn, param);
+	return;
+
+error_rsp:
+	error("Processing error (param %p state %.2X pr %.2X param)", param,
+			conn->state, conn->processing_req);
+	sap_error_rsp(conn);
+}
+
+static void start_guard_timer(struct sap_connection *conn, guint interval)
+{
+	if (!conn)
+		return;
+
+	if (!conn->timer_id)
+		conn->timer_id = g_timeout_add_seconds(interval,
+							guard_timeout, conn);
+	else
+		error("Timer is already active.");
+}
+
+static void stop_guard_timer(struct sap_connection *conn)
+{
+	if (conn  && conn->timer_id) {
+		g_source_remove(conn->timer_id);
+		conn->timer_id = 0;
+	}
+}
+
+static gboolean guard_timeout(gpointer data)
+{
+	struct sap_connection *conn = data;
+
+	if (!conn)
+		return FALSE;
+
+	DBG("conn %p state: %x pr %x", conn, conn->state,
+				conn->processing_req);
+
+	conn->timer_id = 0;
+
+	switch (conn->state) {
+	case SAP_STATE_DISCONNECTED:
+		/* Client opened RFCOMM channel but didn't send CONNECT_REQ,
+		 * in fixed time or client disconnected SAP connection but
+		 * didn't closed RFCOMM channel in fixed time.*/
+		if (conn->io) {
+			g_io_channel_shutdown(conn->io, TRUE, NULL);
+			g_io_channel_unref(conn->io);
+		}
+
+		break;
+	case SAP_STATE_GRACEFUL_DISCONNECT:
+		/* Client didn't disconnect SAP connection in fixed time,
+		 * so close SAP connection immediately. */
+		disconnect_req(conn, SAP_DISCONNECTION_TYPE_IMMEDIATE);
+		break;
+	default:
+		error("Unexpected state.");
+		break;
+	}
+
+	return FALSE;
+}
+
+
+int sap_connect_rsp(void *sap_device, sap_status_t status, uint16_t maxmsgsize)
+{
+	struct sap_connection *conn = sap_device;
+	char buf[SAP_BUF_SIZE];
+	struct sap_message *msg = (struct sap_message *) buf;
+	struct sap_parameter *param = (struct sap_parameter *) msg->param;
+	size_t size = sizeof(struct sap_message);
+
+	if (!conn)
+		return -1;
+
+	DBG("state %x pr %x status %x", conn->state, conn->processing_req,
+			status);
+
+	if (conn->state != SAP_STATE_CONNECT_IN_PROGRESS)
+		return -EPERM;
+
+	memset(buf, 0, sizeof(buf));
+	msg->id = SAP_CONNECT_RESP;
+	msg->nparam = 0x01;
+
+	/* Add connection status */
+	param->id = SAP_PARAM_ID_CONN_STATUS;
+	param->len = htons(SAP_PARAM_ID_CONN_STATUS_LEN);
+	*param->val = (uint8_t)status;
+	size += PARAMETER_SIZE(SAP_PARAM_ID_CONN_STATUS_LEN);
+
+	/* Add MaxMsgSize */
+	if (maxmsgsize && (status == SAP_STATUS_MAX_MSG_SIZE_NOT_SUPPORTED ||
+			status == SAP_STATUS_MAX_MSG_SIZE_TOO_SMALL)) {
+		uint16_t *len;
+		msg->nparam++;
+		param = (struct sap_parameter *) &buf[size];
+		param->id = SAP_PARAM_ID_MAX_MSG_SIZE;
+		param->len = htons(SAP_PARAM_ID_MAX_MSG_SIZE_LEN);
+		len = (uint16_t *) &param->val;
+		*len = htons(maxmsgsize);
+		size += PARAMETER_SIZE(SAP_PARAM_ID_MAX_MSG_SIZE_LEN);
+	}
+
+	if (status == SAP_STATUS_OK) {
+		gboolean connected = TRUE;
+		emit_property_changed(connection, server->path,
+						SAP_SERVER_INTERFACE,
+			"Connected", DBUS_TYPE_BOOLEAN, &connected);
+
+		conn->state = SAP_STATE_CONNECTED;
+	} else {
+		conn->state = SAP_STATE_DISCONNECTED;
+
+		/* Timer will shutdown channel if client doesn't send
+		 * CONNECT_REQ or doesn't shutdown channel itself.*/
+		start_guard_timer(conn, SAP_TIMER_NO_ACTIVITY);
+	}
+
+	conn->processing_req = SAP_NO_REQ;
+	return send_message(sap_device, buf, size);
+}
+
+int sap_disconnect_rsp(void *sap_device)
+{
+	struct sap_connection *conn = sap_device;
+	struct sap_message msg;
+
+	if (!conn)
+		return -1;
+
+	DBG("state %x pr %x", conn->state, conn->processing_req);
+
+	switch (conn->state) {
+	case SAP_STATE_CLIENT_DISCONNECT:
+		memset(&msg, 0, sizeof(msg));
+		msg.id = SAP_DISCONNECT_RESP;
+
+		conn->state = SAP_STATE_DISCONNECTED;
+		conn->processing_req = SAP_NO_REQ;
+
+		/* Timer will close channel if client doesn't do it.*/
+		start_guard_timer(conn, SAP_TIMER_NO_ACTIVITY);
+
+		return send_message(sap_device, &msg, sizeof(msg));
+
+	case SAP_STATE_IMMEDIATE_DISCONNECT:
+		conn->state = SAP_STATE_DISCONNECTED;
+		conn->processing_req = SAP_NO_REQ;
+
+		if (conn->io) {
+			g_io_channel_shutdown(conn->io, TRUE, NULL);
+			g_io_channel_unref(conn->io);
+		}
+		return 0;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+int sap_transfer_apdu_rsp(void *sap_device, sap_result_t result,
+				uint8_t *apdu, uint16_t length)
+{
+	struct sap_connection *conn = sap_device;
+	char buf[SAP_BUF_SIZE];
+	struct sap_message *msg = (struct sap_message *) buf;
+	struct sap_parameter *param = (struct sap_parameter *) msg->param;
+	size_t size = sizeof(struct sap_message);
+
+	if (!conn)
+		return -1;
+
+	DBG("state %x pr %x", conn->state, conn->processing_req);
+
+	if (conn->processing_req != SAP_TRANSFER_APDU_REQ)
+		return 0;
+
+	if (result == SAP_RESULT_OK && (!apdu || (apdu && length == 0x00)))
+		return -EINVAL;
+
+	memset(buf, 0, sizeof(buf));
+	msg->id = SAP_TRANSFER_APDU_RESP;
+	msg->nparam = 0x01;
+	size += add_result_parameter(result, param);
+
+	/* Add APDU response. */
+	if (result == SAP_RESULT_OK) {
+		msg->nparam++;
+		param = (struct sap_parameter *) &buf[size];
+		param->id = SAP_PARAM_ID_RESPONSE_APDU;
+		param->len = htons(length);
+
+		size += PARAMETER_SIZE(length);
+		if (size > SAP_BUF_SIZE)
+			return -EOVERFLOW;
+
+		memcpy(param->val, apdu, length);
+	}
+
+	conn->processing_req = SAP_NO_REQ;
+	return send_message(sap_device, buf, size);
+}
+
+int sap_transfer_atr_rsp(void *sap_device, sap_result_t result,
+					uint8_t *atr, uint16_t length)
+{
+	struct sap_connection *conn = sap_device;
+	char buf[SAP_BUF_SIZE];
+	struct sap_message *msg = (struct sap_message *) buf;
+	struct sap_parameter *param = (struct sap_parameter *) msg->param;
+	size_t size = sizeof(struct sap_message);
+
+	if (!conn)
+		return -1;
+
+	DBG("result %x state %x pr %x len %d", result, conn->state,
+			conn->processing_req, length);
+
+	if (conn->processing_req != SAP_TRANSFER_ATR_REQ)
+		return 0;
+
+	if (result == SAP_RESULT_OK && (!atr || (atr && length == 0x00)))
+		return -EINVAL;
+
+	memset(buf, 0, sizeof(buf));
+	msg->id = SAP_TRANSFER_ATR_RESP;
+	msg->nparam = 0x01;
+	size += add_result_parameter(result, param);
+
+	/* Add ATR response */
+	if (result == SAP_RESULT_OK) {
+		msg->nparam++;
+		param = (struct sap_parameter *) &buf[size];
+		param->id = SAP_PARAM_ID_ATR;
+		param->len = htons(length);
+		size += PARAMETER_SIZE(length);
+		if (size > SAP_BUF_SIZE)
+			return -EOVERFLOW;
+
+		memcpy(param->val, atr, length);
+	}
+
+	conn->processing_req = SAP_NO_REQ;
+	return send_message(sap_device, buf, size);
+}
+
+int sap_power_sim_off_rsp(void *sap_device, sap_result_t result)
+{
+	struct sap_connection *conn = sap_device;
+	char buf[SAP_BUF_SIZE];
+	struct sap_message *msg = (struct sap_message *) buf;
+	size_t size = sizeof(struct sap_message);
+
+	if (!conn)
+		return -1;
+
+	DBG("state %x pr %x", conn->state, conn->processing_req);
+
+	if (conn->processing_req != SAP_POWER_SIM_OFF_REQ)
+		return 0;
+
+	memset(buf, 0, sizeof(buf));
+	msg->id = SAP_POWER_SIM_OFF_RESP;
+	msg->nparam = 0x01;
+	size += add_result_parameter(result, msg->param);
+
+	conn->processing_req = SAP_NO_REQ;
+	return send_message(sap_device, buf, size);
+}
+
+int sap_power_sim_on_rsp(void *sap_device, sap_result_t result)
+{
+	struct sap_connection *conn = sap_device;
+	char buf[SAP_BUF_SIZE];
+	struct sap_message *msg = (struct sap_message *) buf;
+	size_t size = sizeof(struct sap_message);
+
+	if (!conn)
+		return -1;
+
+	DBG("state %x pr %x", conn->state, conn->processing_req);
+
+	if (conn->processing_req != SAP_POWER_SIM_ON_REQ)
+		return 0;
+
+	memset(buf, 0, sizeof(buf));
+	msg->id = SAP_POWER_SIM_ON_RESP;
+	msg->nparam = 0x01;
+	size += add_result_parameter(result, msg->param);
+
+	conn->processing_req = SAP_NO_REQ;
+	return send_message(sap_device, buf, size);
+}
+
+int sap_reset_sim_rsp(void *sap_device, sap_result_t result)
+{
+	struct sap_connection *conn = sap_device;
+	char buf[SAP_BUF_SIZE];
+	struct sap_message *msg = (struct sap_message *) buf;
+	size_t size = sizeof(struct sap_message);
+
+	if (!conn)
+		return -1;
+
+	DBG("state %x pr %x result %d", conn->state, conn->processing_req,
+			result);
+
+	if (conn->processing_req != SAP_RESET_SIM_REQ)
+		return 0;
+
+	memset(buf, 0, sizeof(buf));
+	msg->id = SAP_RESET_SIM_RESP;
+	msg->nparam = 0x01;
+	size += add_result_parameter(result, msg->param);
+
+	conn->processing_req = SAP_NO_REQ;
+	return send_message(sap_device, buf, size);
+}
+
+int sap_transfer_card_reader_status_rsp(void *sap_device, sap_result_t result,
+						icc_reader_status_t status)
+{
+	struct sap_connection *conn = sap_device;
+	char buf[SAP_BUF_SIZE];
+	struct sap_message *msg = (struct sap_message *) buf;
+	struct sap_parameter *param = (struct sap_parameter *) msg->param;
+	size_t size = sizeof(struct sap_message);
+
+	if (!conn)
+		return -1;
+
+	DBG("state %x pr %x result %d", conn->state, conn->processing_req,
+			result);
+
+	if (conn->processing_req != SAP_TRANSFER_CARD_READER_STATUS_REQ)
+		return 0;
+
+	memset(buf, 0, sizeof(buf));
+	msg->id = SAP_TRANSFER_CARD_READER_STATUS_RESP;
+	msg->nparam = 0x01;
+	size += add_result_parameter(result, param);
+
+	/* Add card reader status. */
+	if (result == SAP_RESULT_OK) {
+		msg->nparam++;
+		param = (struct sap_parameter *) &buf[size];
+		param->id = SAP_PARAM_ID_CARD_READER_STATUS;
+		param->len = htons(SAP_PARAM_ID_CARD_READER_STATUS_LEN);
+		*param->val = (uint8_t) status;
+		size += PARAMETER_SIZE(SAP_PARAM_ID_CARD_READER_STATUS_LEN);
+	}
+
+	conn->processing_req = SAP_NO_REQ;
+	return send_message(sap_device, buf, size);
+}
+
+int sap_transport_protocol_rsp(void *sap_device, sap_result_t result)
+{
+	struct sap_connection *conn = sap_device;
+	char buf[SAP_BUF_SIZE];
+	struct sap_message *msg = (struct sap_message *) buf;
+	size_t size = sizeof(struct sap_message);
+
+	if (!conn)
+		return -1;
+
+	DBG("state %x pr %x result %d", conn->state, conn->processing_req,
+			result);
+
+	if (conn->processing_req != SAP_SET_TRANSPORT_PROTOCOL_REQ)
+		return 0;
+
+	memset(buf, 0, sizeof(buf));
+	msg->id = SAP_SET_TRANSPORT_PROTOCOL_RESP;
+	msg->nparam = 0x01;
+	size += add_result_parameter(result, msg->param);
+
+	conn->processing_req = SAP_NO_REQ;
+	return send_message(sap_device, buf, size);
+}
+
+int sap_error_rsp(void *sap_device)
+{
+	struct sap_message msg;
+	struct sap_connection *conn = sap_device;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.id = SAP_ERROR_RESP;
+
+	return send_message(conn, &msg, sizeof(msg));
+}
+
+int sap_status_ind(void *sap_device, sap_status_change_t status_change)
+{
+	struct sap_connection *conn = sap_device;
+	char buf[SAP_BUF_SIZE];
+	struct sap_message *msg = (struct sap_message *) buf;
+	struct sap_parameter *param = (struct sap_parameter *) msg->param;
+	size_t size = sizeof(struct sap_message);
+
+	if (!conn)
+		return -1;
+
+	DBG("state %x pr %x sc %d", conn->state, conn->processing_req,
+				status_change);
+
+	if (conn->state != SAP_STATE_CONNECTED &&
+			conn->state != SAP_STATE_GRACEFUL_DISCONNECT)
+		return 0;
+
+	memset(buf, 0, sizeof(buf));
+	msg->id = SAP_STATUS_IND;
+	msg->nparam = 0x01;
+
+	/* Add status change. */
+	param->id  = SAP_PARAM_ID_STATUS_CHANGE;
+	param->len = htons(SAP_PARAM_ID_STATUS_CHANGE_LEN);
+	*param->val = (uint8_t) status_change;
+	size += PARAMETER_SIZE(SAP_PARAM_ID_STATUS_CHANGE_LEN);
+
+	return send_message(sap_device, buf, size);
+}
+
+static int handle_cmd(void *data, void *buf, size_t size)
+{
+	struct sap_message *msg = buf;
+	struct sap_connection *conn = data;
+
+	if(!conn)
+		goto error_conn;
+
+	if (size < sizeof(struct sap_message))
+		goto error_rsp;
+
+	if (msg->nparam != 0 &&
+			size < (sizeof(struct sap_message) +
+			sizeof(struct sap_parameter) + 4))
+		goto error_rsp;
+
+	if (check_msg(msg) < 0)
+		goto error_rsp;
+
+	switch (msg->id) {
+	case SAP_CONNECT_REQ:
+		DBG("SAP Connect.");
+		connect_req(conn, msg->param);
+		return 0;
+	case SAP_DISCONNECT_REQ:
+		DBG("SAP Disconnect.");
+		disconnect_req(conn, SAP_DISCONNECTION_TYPE_CLIENT);
+		return 0;
+	case SAP_TRANSFER_APDU_REQ:
+		DBG("SAP Transfer APDU.");
+		transfer_apdu_req(conn, msg->param);
+		return 0;
+	case SAP_TRANSFER_ATR_REQ:
+		DBG("SAP Transfer ATR.");
+		transfer_atr_req(conn);
+		return 0;
+	case SAP_POWER_SIM_OFF_REQ:
+		DBG("SAP SIM off.");
+		power_sim_off_req(conn);
+		return 0;
+	case SAP_POWER_SIM_ON_REQ:
+		DBG("SAP SIM on.");
+		power_sim_on_req(conn);
+		return 0;
+	case SAP_RESET_SIM_REQ:
+		DBG("SAP SIM reset.");
+		reset_sim_req(conn);
+		return 0;
+	case SAP_TRANSFER_CARD_READER_STATUS_REQ:
+		DBG("SAP reader status.");
+		transfer_card_reader_status_req(conn);
+		return 0;
+	case SAP_SET_TRANSPORT_PROTOCOL_REQ:
+		DBG("SAP set proto request.");
+		set_transport_protocol_req(conn, msg->param);
+		return 0;
+	default:
+		DBG("SAP unknown message.");
+		break;
+	}
+
+error_rsp:
+	DBG("Bad request message format.");
+	sap_error_rsp(conn);
+	return -EBADMSG;
+
+error_conn:
+	DBG("Connection lost.");
+	return -1;
+}
+
+static void sap_conn_remove(struct sap_connection *conn)
+{
+	DBG("conn %p",conn);
+
+	if(!conn)
+		return;
+
+	if(conn->io) {
+		g_io_channel_shutdown(conn->io, TRUE, NULL);
+		g_io_channel_unref(conn->io);
+	}
+	conn->io = NULL;
+	g_free(conn);
+	server->conn = NULL;
+}
+
+static gboolean sap_io_cb(GIOChannel *io, GIOCondition cond, gpointer data)
+{
+	char buf[SAP_BUF_SIZE];
+	size_t bytes_read = 0;
+	GError *gerr = NULL;
+	GIOStatus gstatus;
+
+	DBG("io %p", io);
+
+	if (cond & G_IO_NVAL){
+		DBG("ERR (G_IO_NVAL) on rfcomm socket.");
+		return FALSE;
+	}
+
+	if (cond & G_IO_ERR) {
+		DBG("ERR (G_IO_ERR) on rfcomm socket.");
+		return FALSE;
+	}
+
+	if (cond & G_IO_HUP ) {
+		DBG("HUP on rfcomm socket.");
+		return FALSE;
+	}
+
+	gstatus = g_io_channel_read_chars(io, buf, sizeof(buf) - 1,
+				&bytes_read, &gerr);
+
+	if (gstatus != G_IO_STATUS_NORMAL) {
+		if (gerr)
+			g_error_free(gerr);
+		return TRUE;
+	}
+
+	if (handle_cmd(data, buf, bytes_read) < 0)
+		error("Invalid SAP message.");
+
+	return TRUE;
+}
+
+static void sap_io_destroy(void *data)
+{
+	struct sap_connection *conn = data;
+
+	DBG("conn %p", conn);
+
+	if (conn && conn->io) {
+		gboolean connected = FALSE;
+
+		stop_guard_timer(conn);
+
+		if (conn->state != SAP_STATE_CONNECT_IN_PROGRESS)
+			emit_property_changed(connection, server->path,
+				SAP_SERVER_INTERFACE,"Connected",
+				DBUS_TYPE_BOOLEAN, &connected);
+
+		if (conn->state == SAP_STATE_CONNECT_IN_PROGRESS ||
+				conn->state == SAP_STATE_CONNECTED ||
+				conn->state == SAP_STATE_GRACEFUL_DISCONNECT)
+		{
+				sap_disconnect_req(NULL, 1);
+		}
+
+		conn->io = NULL;
+		sap_conn_remove(conn);
+	}
+}
+
+static void sap_connect_cb(GIOChannel *io, GError *gerr, gpointer data)
+{
+	struct sap_connection *conn = data;
+
+	DBG("io %p gerr %p data %p ", io, gerr, data);
+
+	if (!conn)
+		return;
+
+	/* Timer will shutdown the channel in case of lack of client
+	   activity */
+	start_guard_timer(conn, SAP_TIMER_NO_ACTIVITY);
+
+	g_io_add_watch_full(io, G_PRIORITY_DEFAULT,
+			G_IO_IN | G_IO_ERR | G_IO_HUP| G_IO_NVAL,
+			sap_io_cb, conn, sap_io_destroy);
+}
+
+static void connect_auth_cb(DBusError *derr, void *data)
+{
+	struct sap_connection *conn = data;
+	GError *gerr = NULL;
+
+	DBG("derr %p data %p ", derr, data);
+
+	if (!conn)
+		return;
+
+	if (derr && dbus_error_is_set(derr)) {
+		error("Access denied: %s", derr->message);
+		sap_conn_remove(conn);
+		return;
+	}
+
+	if (!bt_io_accept(conn->io, sap_connect_cb, conn, NULL, &gerr)) {
+		error("bt_io_accept: %s", gerr->message);
+		g_error_free(gerr);
+		sap_conn_remove(conn);
+		return;
+	}
+
+	DBG("Client has been authorized.");
+}
+
+static void connect_confirm_cb(GIOChannel *io, gpointer data)
+{
+	struct sap_connection *conn = server->conn;
+	GError *gerr = NULL;
+	bdaddr_t src, dst;
+	int err;
+
+	DBG("io %p data %p ", io, data);
+
+	if (!io)
+		return;
+
+	if (conn) {
+		g_io_channel_shutdown(io, TRUE, NULL);
+		return;
+	}
+
+	conn = g_try_new0(struct sap_connection, 1);
+	if(!conn) {
+		error("Can't allocate memory for incomming SAP connection.");
+		g_io_channel_shutdown(io, TRUE, NULL);
+		return;
+	}
+
+	g_io_channel_set_encoding(io, NULL, NULL);
+	g_io_channel_set_buffered(io, FALSE);
+
+	server->conn = conn;
+	conn->io = g_io_channel_ref(io);
+	conn->state = SAP_STATE_DISCONNECTED;
+
+	bt_io_get(io, BT_IO_RFCOMM, &gerr,
+			BT_IO_OPT_SOURCE_BDADDR, &src,
+			BT_IO_OPT_DEST_BDADDR, &dst,
+			BT_IO_OPT_INVALID);
+
+	if (gerr) {
+		error("%s", gerr->message);
+		g_error_free(gerr);
+		sap_conn_remove(conn);
+		return;
+	}
+
+	err = btd_request_authorization(&src, &dst, SAP_UUID,
+					connect_auth_cb, conn);
+
+	if (err < 0) {
+		DBG("Authorization denied: %d %s", err,  strerror(err));
+		sap_conn_remove(conn);
+		return;
+	}
+
+	DBG("SAP incoming connection (sock %d) authorization.",
+				g_io_channel_unix_get_fd(io));
+}
+
+static inline DBusMessage *message_failed(DBusMessage *msg,
+					const char *description)
+{
+	return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
+				"%s", description);
+}
+
+static DBusMessage *disconnect(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	struct sap_server *server = data;
+
+	DBG("server %p",server);
+
+	if (!server)
+		return message_failed(msg, "Server internal error.");
+
+	DBG("conn %p",server->conn);
+	if (!server->conn)
+		return message_failed(msg, "Client already disconnected");
+
+	if (disconnect_req(server->conn, SAP_DISCONNECTION_TYPE_GRACEFUL) < 0)
+		return g_dbus_create_error(msg, ERROR_INTERFACE
+				".Failed",
+				"There is no active connection");
+
+	return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *get_properties(DBusConnection *c,
+				DBusMessage *msg, void *data)
+{
+	struct sap_connection *conn = data;
+	DBusMessage *reply;
+	DBusMessageIter iter;
+	DBusMessageIter dict;
+	dbus_bool_t connected;
+
+	if (!conn)
+		return message_failed(msg, "Server internal error.");
+
+	reply = dbus_message_new_method_return(msg);
+	if (!reply)
+		return NULL;
+
+	dbus_message_iter_init_append(reply, &iter);
+
+	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+	connected = (conn->state == SAP_STATE_CONNECTED ||
+			conn->state == SAP_STATE_GRACEFUL_DISCONNECT);
+	dict_append_entry(&dict, "Connected", DBUS_TYPE_BOOLEAN, &connected);
+
+	dbus_message_iter_close_container(&iter, &dict);
+
+	return reply;
+}
+
+static GDBusMethodTable server_methods[] = {
+	{ "GetProperties","","a{sv}",get_properties },
+	{ "Disconnect","","", disconnect },
+	{ }
+};
+
+static GDBusSignalTable server_signals[] = {
+	{ "PropertyChanged",		"sv"},
+	{ }
+};
+
+static void server_free(struct sap_server *server)
+{
+	if (!server)
+		return;
+
+	sap_conn_remove(server->conn);
+	g_free(server->path);
+	g_free(server);
+}
+
+static void destroy_sap_interface(void *data)
+{
+	struct sap_server *server = data;
+
+	DBG("Unregistered interface %s on path %s",
+			SAP_SERVER_INTERFACE, server->path);
+
+	server_free(server);
+}
+
 int sap_server_register(const char *path, bdaddr_t *src)
 {
-	DBG("Register SAP server.");
+	sdp_record_t *record = NULL;
+	GError *gerr = NULL;
+	GIOChannel *io;
+
+	if (sap_init() < 0) {
+		error("Sap driver initialization failed.");
+		return -1;
+	}
+
+	server = g_try_new0(struct sap_server, 1);
+	if (!server) {
+		sap_exit();
+		return -ENOMEM;
+	}
+
+	bacpy(&server->src, src);
+	server->path = g_strdup(path);
+
+	record = create_sap_record(SAP_SERVER_CHANNEL);
+	if (!record){
+		error("Creating SAP SDP record failed.");
+		goto sdp_err;
+	}
+
+	if (add_record_to_server(&server->src, record) < 0) {
+		error("Adding SAP SDP record to the SDP server failed.");
+		sdp_record_free(record);
+		goto sdp_err;
+	}
+
+	server->record_id = record->handle;
+
+	io = bt_io_listen(BT_IO_RFCOMM, NULL, connect_confirm_cb, server,
+			NULL, &gerr,
+			BT_IO_OPT_SOURCE_BDADDR, &server->src,
+			BT_IO_OPT_CHANNEL, SAP_SERVER_CHANNEL,
+			BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_HIGH,
+			BT_IO_OPT_MASTER, TRUE,
+			BT_IO_OPT_INVALID);
+
+	if (!io) {
+		error("Can't listen at channel %d.", SAP_SERVER_CHANNEL);
+		g_error_free(gerr);
+		goto server_err;
+	}
+
+	DBG("Listen socket 0x%.2X", g_io_channel_unix_get_fd(io));
+
+	server->listen_io = io;
+	server->conn = NULL;
+
+	if (!g_dbus_register_interface(connection, path, SAP_SERVER_INTERFACE,
+				server_methods, server_signals, NULL,
+				server, destroy_sap_interface)) {
+		error("D-Bus failed to register %s interface",
+						SAP_SERVER_INTERFACE);
+		goto server_err;
+	}
+
 	return 0;
+
+server_err:
+	remove_record_from_server(server->record_id);
+sdp_err:
+	server_free(server);
+	server = NULL;
+	sap_exit();
+
+	return -1;
 }
 
 int sap_server_unregister(const char *path)
 {
-	DBG("Unregister SAP server.");
+	if(!server)
+		return -1;
+
+	remove_record_from_server(server->record_id);
+
+	if (server->conn)
+		sap_conn_remove(server->conn);
+
+	if (server->listen_io) {
+		g_io_channel_shutdown(server->listen_io, TRUE, NULL);
+		g_io_channel_unref(server->listen_io);
+		server->listen_io = NULL;
+	}
+
+	g_dbus_unregister_interface(connection, path, SAP_SERVER_INTERFACE);
+
+	server_free(server);
+	server = NULL;
+	sap_exit();
+
 	return 0;
 }
 
 int sap_server_init(DBusConnection *conn)
 {
-	DBG("Init SAP server.");
+	connection = dbus_connection_ref(conn);
 	return 0;
 }
 
 void sap_server_exit(void)
 {
-	DBG("Exit SAP server.");
+	dbus_connection_unref(connection);
+	connection = NULL;
 }
-- 
1.7.1

^ permalink raw reply related

* [PATCH v2 2/4] Sim Access Profile Manager
From: Waldemar Rymarkiewicz @ 2011-02-24 12:13 UTC (permalink / raw)
  To: linux-bluetooth
  Cc: Johan Hedberg, padovan, Marcel Holtmann, Waldemar Rymarkiewicz
In-Reply-To: <1298549606-16594-1-git-send-email-waldemar.rymarkiewicz@tieto.com>

Add a SAP plugin main file and the plugin manager. Also include the SAP
plugin in the Makefile.
---
 Makefile.am   |    7 ++++
 acinclude.m4  |    6 ++++
 sap/main.c    |   55 +++++++++++++++++++++++++++++++++
 sap/manager.c |   93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 sap/manager.h |   22 +++++++++++++
 sap/server.c  |   48 +++++++++++++++++++++++++++++
 sap/server.h  |   26 ++++++++++++++++
 7 files changed, 257 insertions(+), 0 deletions(-)
 create mode 100644 sap/main.c
 create mode 100644 sap/manager.c
 create mode 100644 sap/manager.h
 create mode 100644 sap/server.c
 create mode 100644 sap/server.h

diff --git a/Makefile.am b/Makefile.am
index 025f6d3..49c45c1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -143,6 +143,13 @@ audio_libtelephony_a_SOURCES = audio/telephony.h audio/telephony-dummy.c \
 				audio/telephony-maemo6.c
 endif
 
+if SAPPLUGIN
+builtin_modules += sap
+builtin_sources += sap/main.c \
+			sap/manager.h sap/manager.c \
+			sap/server.h sap/server.c
+endif
+
 if INPUTPLUGIN
 builtin_modules += input
 builtin_sources += input/main.c \
diff --git a/acinclude.m4 b/acinclude.m4
index 91e0956..ebf618e 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -184,6 +184,7 @@ AC_DEFUN([AC_ARG_BLUEZ], [
 	input_enable=yes
 	serial_enable=yes
 	network_enable=yes
+	sap_enable=no
 	service_enable=yes
 	health_enable=no
 	pnat_enable=no
@@ -220,6 +221,10 @@ AC_DEFUN([AC_ARG_BLUEZ], [
 		network_enable=${enableval}
 	])
 
+	AC_ARG_ENABLE(sap, AC_HELP_STRING([--enable-sap], [enable sap plugin]), [
+		sap_enable=${enableval}
+	])
+
 	AC_ARG_ENABLE(serial, AC_HELP_STRING([--disable-serial], [disable serial plugin]), [
 		serial_enable=${enableval}
 	])
@@ -361,6 +366,7 @@ AC_DEFUN([AC_ARG_BLUEZ], [
 	AM_CONDITIONAL(INPUTPLUGIN, test "${input_enable}" = "yes")
 	AM_CONDITIONAL(SERIALPLUGIN, test "${serial_enable}" = "yes")
 	AM_CONDITIONAL(NETWORKPLUGIN, test "${network_enable}" = "yes")
+	AM_CONDITIONAL(SAPPLUGIN, test "${sap_enable}" = "yes")
 	AM_CONDITIONAL(SERVICEPLUGIN, test "${service_enable}" = "yes")
 	AM_CONDITIONAL(HEALTHPLUGIN, test "${health_enable}" = "yes")
 	AM_CONDITIONAL(MCAP, test "${health_enable}" = "yes")
diff --git a/sap/main.c b/sap/main.c
new file mode 100644
index 0000000..c9c90bd
--- /dev/null
+++ b/sap/main.c
@@ -0,0 +1,55 @@
+/*
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2010 Instituto Nokia de Tecnologia - INdT
+ *
+ *  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
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <gdbus.h>
+#include "plugin.h"
+#include "manager.h"
+
+static DBusConnection *connection;
+
+static int sap_init(void)
+{
+	connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+
+	if (!connection)
+		return -EIO;
+
+	if (sap_manager_init(connection) < 0) {
+		dbus_connection_unref(connection);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static void sap_exit(void)
+{
+	sap_manager_exit();
+
+	dbus_connection_unref(connection);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(sap, VERSION,
+		BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, sap_init, sap_exit)
diff --git a/sap/manager.c b/sap/manager.c
new file mode 100644
index 0000000..a97f434
--- /dev/null
+++ b/sap/manager.c
@@ -0,0 +1,93 @@
+/*
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2010 Instituto Nokia de Tecnologia - INdT
+ *
+ *  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
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <gdbus.h>
+
+#include "log.h"
+#include "adapter.h"
+#include "device.h"
+
+#include "manager.h"
+#include "server.h"
+
+static DBusConnection *connection = NULL;
+
+static int sap_server_probe(struct btd_adapter *adapter)
+{
+	const char *path = adapter_get_path(adapter);
+	bdaddr_t src;
+
+	DBG("path %s", path);
+
+	adapter_get_address(adapter, &src);
+
+	return sap_server_register(path, &src);
+}
+
+static void sap_server_remove(struct btd_adapter *adapter)
+{
+	const char *path = adapter_get_path(adapter);
+
+	DBG("path %s", path);
+
+	sap_server_unregister(path);
+}
+
+static struct btd_adapter_driver sap_server_driver = {
+	.name	= "sap-server",
+	.probe	= sap_server_probe,
+	.remove	= sap_server_remove,
+};
+
+int sap_manager_init(DBusConnection *conn)
+{
+	connection = dbus_connection_ref(conn);
+
+	if (sap_server_init(connection) < 0) {
+		error("Can't init SAP server");
+		dbus_connection_unref(conn);
+		return -1;
+	}
+
+	btd_register_adapter_driver(&sap_server_driver);
+
+	return 0;
+}
+
+void sap_manager_exit(void)
+{
+	btd_unregister_adapter_driver(&sap_server_driver);
+
+	dbus_connection_unref(connection);
+	connection = NULL;
+
+	sap_server_exit();
+}
diff --git a/sap/manager.h b/sap/manager.h
new file mode 100644
index 0000000..e08c882
--- /dev/null
+++ b/sap/manager.h
@@ -0,0 +1,22 @@
+/*
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2010 Instituto Nokia de Tecnologia - INdT
+ *
+ *  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
+ */
+
+int sap_manager_init(DBusConnection *conn);
+void sap_manager_exit(void);
diff --git a/sap/server.c b/sap/server.c
new file mode 100644
index 0000000..2728778
--- /dev/null
+++ b/sap/server.c
@@ -0,0 +1,48 @@
+/*
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2010 ST-Ericsson SA
+ *
+ *  Author: Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com> for ST-Ericsson.
+ *
+ *  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; version 2 of the License.
+ *
+ *  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 "bluetooth.h"
+#include "log.h"
+
+#include "server.h"
+
+int sap_server_register(const char *path, bdaddr_t *src)
+{
+	DBG("Register SAP server.");
+	return 0;
+}
+
+int sap_server_unregister(const char *path)
+{
+	DBG("Unregister SAP server.");
+	return 0;
+}
+
+int sap_server_init(DBusConnection *conn)
+{
+	DBG("Init SAP server.");
+	return 0;
+}
+
+void sap_server_exit(void)
+{
+	DBG("Exit SAP server.");
+}
diff --git a/sap/server.h b/sap/server.h
new file mode 100644
index 0000000..ef2b7b8
--- /dev/null
+++ b/sap/server.h
@@ -0,0 +1,26 @@
+/*
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2010 ST-Ericsson SA
+ *
+ *  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 <gdbus.h>
+
+int sap_server_init(DBusConnection *conn);
+void sap_server_exit(void);
+int sap_server_register(const char *path, bdaddr_t *src);
+int sap_server_unregister(const char *path);
-- 
1.7.1

^ permalink raw reply related

* [PATCH v2 1/4] Sim Access Profile API
From: Waldemar Rymarkiewicz @ 2011-02-24 12:13 UTC (permalink / raw)
  To: linux-bluetooth
  Cc: Johan Hedberg, padovan, Marcel Holtmann, Waldemar Rymarkiewicz
In-Reply-To: <1298549606-16594-1-git-send-email-waldemar.rymarkiewicz@tieto.com>

New API for Sim Access Profile.
---
 Makefile.am     |    3 ++-
 doc/sap-api.txt |   34 ++++++++++++++++++++++++++++++++++
 2 files changed, 36 insertions(+), 1 deletions(-)
 create mode 100644 doc/sap-api.txt

diff --git a/Makefile.am b/Makefile.am
index ec1ca97..025f6d3 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -359,7 +359,8 @@ EXTRA_DIST += doc/manager-api.txt \
 		doc/service-api.txt doc/agent-api.txt doc/attribute-api.txt \
 		doc/serial-api.txt doc/network-api.txt \
 		doc/input-api.txt doc/audio-api.txt doc/control-api.txt \
-		doc/hfp-api.txt doc/health-api.txt doc/assigned-numbers.txt
+		doc/hfp-api.txt doc/health-api.txt doc/sap-api.txt \
+		doc/assigned-numbers.txt
 
 AM_YFLAGS = -d
 
diff --git a/doc/sap-api.txt b/doc/sap-api.txt
new file mode 100644
index 0000000..b8b7253
--- /dev/null
+++ b/doc/sap-api.txt
@@ -0,0 +1,34 @@
+BlueZ D-Bus Sim Access Profile API description
+***********************************
+
+Copyright (C) 2010 ST-Ericsson SA
+
+
+Sim Access Profile hierarchy
+============================
+
+Service		org.bluez
+Interface	org.bluez.SimAccess
+Object path	[variable prefix]/{hci0,hci1,...}
+
+Methods		void Disconnect()
+
+			Disconnects SAP client from the server.
+
+			Possible errors: org.bluez.Error.Failed
+
+		dict GetProperties()
+
+			Return all properties for the interface. See the
+			properties section for available properties.
+
+			Possible Errors: org.bluez.Error.Failed
+
+Signals		PropertyChanged(string name, variant value)
+
+			This signal indicates a changed value of the given
+			property.
+
+Properties	boolean Connected [readonly]
+
+			Indicates if SAP client is connected to the server.
-- 
1.7.1

^ permalink raw reply related

* [PATCH v2 0/4] Sim Access Profile
From: Waldemar Rymarkiewicz @ 2011-02-24 12:13 UTC (permalink / raw)
  To: linux-bluetooth
  Cc: Johan Hedberg, padovan, Marcel Holtmann, Waldemar Rymarkiewicz

Here you are the SAP codes adjusted to previous comments and API change.

/Waldek


Waldemar Rymarkiewicz (4):
  Sim Access Profile API
  Sim Access Profile Manager
  Sim Access Profile Server
  Sim Access Profile dummy driver

 .gitignore      |    1 +
 Makefile.am     |   22 +-
 acinclude.m4    |   12 +
 doc/sap-api.txt |   34 ++
 sap/main.c      |   55 +++
 sap/manager.c   |   93 ++++
 sap/manager.h   |   22 +
 sap/sap-dummy.c |  328 +++++++++++++
 sap/sap.h       |  192 ++++++++
 sap/server.c    | 1425 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 sap/server.h    |   26 +
 11 files changed, 2208 insertions(+), 2 deletions(-)
 create mode 100644 doc/sap-api.txt
 create mode 100644 sap/main.c
 create mode 100644 sap/manager.c
 create mode 100644 sap/manager.h
 create mode 100644 sap/sap-dummy.c
 create mode 100644 sap/sap.h
 create mode 100644 sap/server.c
 create mode 100644 sap/server.h

^ permalink raw reply

* Re: [PATCH] hcitool: add discovery procedure to lescan command
From: Anderson Lizardo @ 2011-02-24 11:32 UTC (permalink / raw)
  To: Andre Guedes, linux-bluetooth; +Cc: Johan Hedberg
In-Reply-To: <20110224025437.GA6189@jh-x301>

Hi Johan,

On Wed, Feb 23, 2011 at 11:54 PM, Johan Hedberg <johan.hedberg@gmail.com> wrote:
> Hi André,
>
> On Wed, Feb 23, 2011, Andre Guedes wrote:
>> +     "\tlescan [--discovery=g|l] enable general or limited discovery"
>
> To make this consistent with the other options please default to general
> and have a --limited switch to enable limited discovery.

Note that there are actually three modes:

1) the default one, when no parameters are given: do not filter
anything, useful for debugging (this is what is currently done)
2) limited discovery
3) general discovery

limited/general are done according to the procedure description on the spec.

Regards,
-- 
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil

^ permalink raw reply

* RE: Status of MAP and AVRCP
From: sachin.athanikar @ 2011-02-24  8:58 UTC (permalink / raw)
  To: dstockwell; +Cc: linux-bluetooth
In-Reply-To: <6027B6444B774B019847152FB098B13F@freqoneremote>

Hi David,

Please let me know the status on development on AVRCP 1.3 & 1.4.

When is the release planned for BlueZ with AVRCP 1.3 support?

Thanks
Sachin

-----Original Message-----
From: linux-bluetooth-owner@vger.kernel.org [mailto:linux-bluetooth-owner@vger.kernel.org] On Behalf Of David Stockwell
Sent: Tuesday, February 08, 2011 8:13 PM
To: dsaxena@plexity.net; BlueZ devel list
Subject: Re: Status of MAP and AVRCP

Hello Deepak,


Hi,

I am wondering about the status of AVRCP and MAP profile support
in the current BlueZ tree. It looks like ther were a few GSOC
projects related to adding/extending these last year, but from
my quick skim, it does not look like these were integrated
upstream. Was an attempt made to push these changes and did
they get reject? Is someone still driving this work within the
BlueZ community to make sure it goes upstream?

+++++

I restarted work-in-earnest on an AVRCP layer a bit over two months ago (I
also have a full-time day-job that has nothing to do with Bluetooth, Linux,
Open Source, etc.). I am now resolving some issues in connecting from my
custom built AVRCP remote (hardware and firmware), which connects, pairs,
and connects with full AVRCP with my BlackBerry Torch, and the AVRCP stack
on my laptop.  After working through that issue (I expect, by later this
week), and verifying that the BB Torch can connect with my changes in place,
I will complete fairly extensive testing and begin submitting patches with
major surgery to audio/control.c, supporting the API doc worked out in the
Portland meeting, with a couple of minor extensions.  This will bring BlueZ
to AVRCP 1.3, figure by the end of this month.

I will also include message fragmentation support, which will be needed for
1.4 (not really needed for 1.3, although it is in the 1.3 spec).  However,
there are a number of issues with 1.4, the biggest being the amount of
integration between the BlueZ stack/profile (which should remain pure) and
the player(s), that are required to respond to queries for browsing track
metadata, etc.  I think there will need to be a discussion about how much of
1.4, if any, to support, and how.  I think Sander van Grieken's work with
MPRIS may be a guide.  Also, I understand ST Ericsson (Shivendra Agrawal) is
also proposing to provide 1.4 support.

Just my two cents...questions, please do not hesitate.

David Stockwell

+++++

Thanks,
~Deepak


--
"People think all we need to fix our predicament is a free source of
energy, but I think we need to change out behaviour. More energy would
just deplete the Earth's lifeblood faster." - Janine Benyius
--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth"
in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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


This message is for the designated recipient only and may contain privileged, proprietary, or otherwise private information.  If you have received it in error, please notify the sender immediately and delete the original.  Any other use of the email by you is prohibited.

^ permalink raw reply

* Re: [PATCH] Add sec-level option to interactive gattool
From: Johan Hedberg @ 2011-02-24  2:56 UTC (permalink / raw)
  To: Sheldon Demario; +Cc: linux-bluetooth
In-Reply-To: <1298496610-11705-1-git-send-email-sheldon.demario@openbossa.org>

Hi Sheldon,

On Wed, Feb 23, 2011, Sheldon Demario wrote:
> +	if (conn_state == STATE_CONNECTED) {

I think it'd be cleaner to have:

	if (conn_state != STATE_CONNECTED)
		return;

> +
> +	return;
> +}

Never have empty return statements at the end of void-functions.

Johan

^ permalink raw reply

* Re: [PATCH] hcitool: add discovery procedure to lescan command
From: Johan Hedberg @ 2011-02-24  2:54 UTC (permalink / raw)
  To: Andre Guedes; +Cc: linux-bluetooth
In-Reply-To: <1298495788-22273-1-git-send-email-andre.guedes@openbossa.org>

Hi André,

On Wed, Feb 23, 2011, Andre Guedes wrote:
> +	"\tlescan [--discovery=g|l] enable general or limited discovery"

To make this consistent with the other options please default to general
and have a --limited switch to enable limited discovery.

Johan

^ permalink raw reply

* Re: Help hcitool cmd (hci to connect)
From: haijun liu @ 2011-02-24  1:23 UTC (permalink / raw)
  To: Thibaut L; +Cc: linux-bluetooth
In-Reply-To: <AANLkTin7W9jtfAmV4vo9E+YOrkUfrWpO0-B_jzkXZChm@mail.gmail.com>

Thibaut,
I remember there is a monitor for hci connection, if nobody reference
it for a while, then it will issue a disconnect request, so you'd
better make a l2cap connection on it to keep it alive.

Haijun.Liu
skype: liu.haijun

On 2/22/11, Thibaut L <thibaut.dvr@gmail.com> wrote:
> Dear all,
>
> Please, could anyone tell me how to connect to a bluetooth device
> through hcitool (BlueZ) hci command. Like this: "hcitool cmd 0x01
> 0x0005 [parameters]". How can I input this cmd? Is the [parameters] a
> bt device MAC adress like XX:XX:XX:XX:XX:XX?
>
> I've tryed to use "hcitool cc <MAC>", but it doesn't work for me cause
> it disconnects the device a second later.
>
> I just wanna measure RSSI.
>
> Thanks in advance.
>
> Best
>
> Thibaut
> --
> 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
>


-- 
Haijun Liu

^ permalink raw reply


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