* [PATCH 1/5] Add DBG() calls to attrib_db_* functions
From: Anderson Lizardo @ 2011-03-16 20:30 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1300307416-29909-1-git-send-email-anderson.lizardo@openbossa.org>
This will help debugging issues with registration of GATT services.
---
src/attrib-server.c | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/src/attrib-server.c b/src/attrib-server.c
index b076d98..aab7829 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -1214,6 +1214,8 @@ struct attribute *attrib_db_add(uint16_t handle, bt_uuid_t *uuid, int read_reqs,
{
struct attribute *a;
+ DBG("handle=0x%04x", handle);
+
/* FIXME: handle conflicts */
a = g_malloc0(sizeof(struct attribute) + len);
@@ -1236,6 +1238,8 @@ int attrib_db_update(uint16_t handle, bt_uuid_t *uuid, const uint8_t *value,
GSList *l;
guint h = handle;
+ DBG("handle=0x%04x", handle);
+
l = g_slist_find_custom(database, GUINT_TO_POINTER(h), handle_cmp);
if (!l)
return -ENOENT;
@@ -1262,6 +1266,8 @@ int attrib_db_del(uint16_t handle)
GSList *l;
guint h = handle;
+ DBG("handle=0x%04x", handle);
+
l = g_slist_find_custom(database, GUINT_TO_POINTER(h), handle_cmp);
if (!l)
return -ENOENT;
--
1.7.0.4
^ permalink raw reply related
* [PATCH 0/5] Attribute server API fixes
From: Anderson Lizardo @ 2011-03-16 20:30 UTC (permalink / raw)
To: linux-bluetooth
Hi,
This series contains small fixes to the attribute server API. Some fixes are
required for a RFC that I will send soon.
Regards,
--
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil
^ permalink raw reply
* [PATCH] Recalculate remote SEP if the codec type changes
From: Arun Raghavan @ 2011-03-16 20:05 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Arun Raghavan
In-Reply-To: <1300299595.2192.92.camel@snowflake>
This forces recalculating the remote SEP if the local SEP's codec type
is no longer the same as the remote SEP's codec type. This can happen
after we issue a BT_STOP_STREAM+BT_CLOSE followed by a
BT_SET_CONFIGURATION with a new SEID.
---
audio/a2dp.c | 9 ++++++++-
1 files changed, 8 insertions(+), 1 deletions(-)
diff --git a/audio/a2dp.c b/audio/a2dp.c
index 3407d6f..7827cda 100644
--- a/audio/a2dp.c
+++ b/audio/a2dp.c
@@ -1058,8 +1058,15 @@ static gboolean a2dp_reconfigure(gpointer data)
struct a2dp_setup *setup = data;
struct a2dp_sep *sep = setup->sep;
int posix_err;
+ struct avdtp_media_codec_capability *rsep_codec;
+ struct avdtp_service_capability *cap;
- if (!setup->rsep)
+ if (setup->rsep) {
+ cap = avdtp_get_codec(setup->rsep);
+ rsep_codec = (struct avdtp_media_codec_capability *) cap->data;
+ }
+
+ if (!setup->rsep || sep->codec != rsep_codec->media_codec_type)
setup->rsep = avdtp_find_remote_sep(setup->session, sep->lsep);
posix_err = avdtp_set_configuration(setup->session, setup->rsep,
--
1.7.4.1
^ permalink raw reply related
* Re: [PATCH] Bluetooth: Fix HCI_RESET command syncronization
From: Justin Mattock @ 2011-03-16 20:02 UTC (permalink / raw)
To: Justin P. Mattock, Anderson Lizardo, linux-bluetooth, mmvinni,
edt
Cc: Gustavo F. Padovan
In-Reply-To: <20110316191540.GC2151@joana>
> No, it's based on bluetooth-next (2.6.39). But you can drop the hci_cmd_timer
> part while testing it. It's not needed unless you have and hci_reset cmd
> timeout.
>
> --
> Gustavo F. Padovan
> http://profusion.mobi
>
o.k. works over here..
Tested-by: Justin P. Mattock <justinmattock@gmail.com>
here is an updated patch for the current Mainline if anybody needs it:
---
include/net/bluetooth/hci.h | 1 +
net/bluetooth/hci_core.c | 1 +
net/bluetooth/hci_event.c | 4 +++-
3 files changed, 5 insertions(+), 1 deletions(-)
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 29a7a8c..c4f4c42 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -76,6 +76,7 @@ enum {
HCI_INQUIRY,
HCI_RAW,
+ HCI_RESET,
};
/* HCI ioctl defines */
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 9c4541b..07a1a4c 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -522,6 +522,7 @@ int hci_dev_open(__u16 dev)
atomic_set(&hdev->cmd_cnt, 1);
set_bit(HCI_INIT, &hdev->flags);
+ set_bit(HCI_RESET, &hdev->flags);
//__hci_request(hdev, hci_reset_req, 0, HZ);
ret = __hci_request(hdev, hci_init_req, 0,
msecs_to_jiffies(HCI_INIT_TIMEOUT));
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index a290854..a63bcf0 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -183,6 +183,8 @@ static void hci_cc_reset(struct hci_dev *hdev,
struct sk_buff *skb)
BT_DBG("%s status 0x%x", hdev->name, status);
+ clear_bit(HCI_RESET, &hdev->flags);
+
hci_req_complete(hdev, HCI_OP_RESET, status);
}
@@ -1464,7 +1466,7 @@ static inline void hci_cmd_status_evt(struct
hci_dev *hdev, struct sk_buff *skb)
break;
}
- if (ev->ncmd) {
+ if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) {
atomic_set(&hdev->cmd_cnt, 1);
if (!skb_queue_empty(&hdev->cmd_q))
tasklet_schedule(&hdev->cmd_task);
--
1.7.4.1
--
Justin P. Mattock
^ permalink raw reply related
* Re: [PATCH] Bluetooth: Fix HCI_RESET command syncronization
From: Gustavo F. Padovan @ 2011-03-16 19:15 UTC (permalink / raw)
To: Justin P. Mattock; +Cc: Anderson Lizardo, linux-bluetooth, mmvinni, edt
In-Reply-To: <4D810B4E.7040702@gmail.com>
Hi Justin,
* Justin P. Mattock <justinmattock@gmail.com> [2011-03-16 12:11:10 -0700]:
> On 03/16/2011 12:01 PM, Gustavo F. Padovan wrote:
> > Hi Anderson,
> >
> > * Anderson Lizardo<anderson.lizardo@openbossa.org> [2011-03-16 14:48:31 -0400]:
> >
> >> Hi Gustavo,
> >>
> >> On Wed, Mar 16, 2011 at 2:46 PM, Gustavo F. Padovan
> >> <padovan@profusion.mobi> wrote:
> >>>
> >>> * Gustavo F. Padovan<padovan@profusion.mobi> [2011-03-16 15:44:46 -0300]:
> >>>
> >>>> We can't send new commands before a cmd_complete for the HCI_RESET commnnd
> >>>> shows up.
> >>>>
> >>>> Reported-by: Mikko Vinni<mmvinni@yahoo.com>
> >>>> Reported-by: Justin P. Mattock<justinmattock@gmail.com>
> >>>> Reported-by: Ed Tomlinson<edt@aei.ca>
> >>>> Signed-off-by: Gustavo F. Padovan<padovan@profusion.mobi>
> >>>> ---
> >>>> include/net/bluetooth/hci.h | 2 ++
> >>>> net/bluetooth/hci_core.c | 3 +++
> >>>> net/bluetooth/hci_event.c | 4 +++-
> >>>> 3 files changed, 8 insertions(+), 1 deletions(-)
> >>>
> >>> It works for me, but can someone test this and then add a Tested-by line.
> >>> Thanks.
> >>
> >> Which hardware is needed to test this?
> >
> > I don't know, I have a dongle that can cause this issue. It's CSR 1.1.
> > I don't know which other dongles have a similar issue.
> >
>
> I started to test this out, but crapped out at hci_cmd_timer with the
> current Mainline do you have this for the current?
No, it's based on bluetooth-next (2.6.39). But you can drop the hci_cmd_timer
part while testing it. It's not needed unless you have and hci_reset cmd
timeout.
--
Gustavo F. Padovan
http://profusion.mobi
^ permalink raw reply
* Re: [PATCH] Bluetooth: Fix HCI_RESET command syncronization
From: Justin P. Mattock @ 2011-03-16 19:11 UTC (permalink / raw)
To: Anderson Lizardo, linux-bluetooth, mmvinni, edt
In-Reply-To: <20110316190154.GB2151@joana>
On 03/16/2011 12:01 PM, Gustavo F. Padovan wrote:
> Hi Anderson,
>
> * Anderson Lizardo<anderson.lizardo@openbossa.org> [2011-03-16 14:48:31 -0400]:
>
>> Hi Gustavo,
>>
>> On Wed, Mar 16, 2011 at 2:46 PM, Gustavo F. Padovan
>> <padovan@profusion.mobi> wrote:
>>>
>>> * Gustavo F. Padovan<padovan@profusion.mobi> [2011-03-16 15:44:46 -0300]:
>>>
>>>> We can't send new commands before a cmd_complete for the HCI_RESET commnnd
>>>> shows up.
>>>>
>>>> Reported-by: Mikko Vinni<mmvinni@yahoo.com>
>>>> Reported-by: Justin P. Mattock<justinmattock@gmail.com>
>>>> Reported-by: Ed Tomlinson<edt@aei.ca>
>>>> Signed-off-by: Gustavo F. Padovan<padovan@profusion.mobi>
>>>> ---
>>>> include/net/bluetooth/hci.h | 2 ++
>>>> net/bluetooth/hci_core.c | 3 +++
>>>> net/bluetooth/hci_event.c | 4 +++-
>>>> 3 files changed, 8 insertions(+), 1 deletions(-)
>>>
>>> It works for me, but can someone test this and then add a Tested-by line.
>>> Thanks.
>>
>> Which hardware is needed to test this?
>
> I don't know, I have a dongle that can cause this issue. It's CSR 1.1.
> I don't know which other dongles have a similar issue.
>
I started to test this out, but crapped out at hci_cmd_timer with the
current Mainline do you have this for the current?
^ permalink raw reply
* Re: [PATCH] Bluetooth: Fix HCI_RESET command syncronization
From: Gustavo F. Padovan @ 2011-03-16 19:01 UTC (permalink / raw)
To: Anderson Lizardo; +Cc: linux-bluetooth, mmvinni, justinmattock, edt
In-Reply-To: <AANLkTimNeqvBMnb55x10LrwXncx1CnV=OLBUCBJXaGpx@mail.gmail.com>
Hi Anderson,
* Anderson Lizardo <anderson.lizardo@openbossa.org> [2011-03-16 14:48:31 -0400]:
> Hi Gustavo,
>
> On Wed, Mar 16, 2011 at 2:46 PM, Gustavo F. Padovan
> <padovan@profusion.mobi> wrote:
> >
> > * Gustavo F. Padovan <padovan@profusion.mobi> [2011-03-16 15:44:46 -0300]:
> >
> >> We can't send new commands before a cmd_complete for the HCI_RESET commnnd
> >> shows up.
> >>
> >> Reported-by: Mikko Vinni <mmvinni@yahoo.com>
> >> Reported-by: Justin P. Mattock <justinmattock@gmail.com>
> >> Reported-by: Ed Tomlinson <edt@aei.ca>
> >> Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
> >> ---
> >> include/net/bluetooth/hci.h | 2 ++
> >> net/bluetooth/hci_core.c | 3 +++
> >> net/bluetooth/hci_event.c | 4 +++-
> >> 3 files changed, 8 insertions(+), 1 deletions(-)
> >
> > It works for me, but can someone test this and then add a Tested-by line.
> > Thanks.
>
> Which hardware is needed to test this?
I don't know, I have a dongle that can cause this issue. It's CSR 1.1.
I don't know which other dongles have a similar issue.
--
Gustavo F. Padovan
http://profusion.mobi
^ permalink raw reply
* Re: [PATCH] Bluetooth: Fix HCI_RESET command syncronization
From: Anderson Lizardo @ 2011-03-16 18:48 UTC (permalink / raw)
To: linux-bluetooth, mmvinni, justinmattock, edt; +Cc: Gustavo F. Padovan
In-Reply-To: <20110316184639.GA2151@joana>
Hi Gustavo,
On Wed, Mar 16, 2011 at 2:46 PM, Gustavo F. Padovan
<padovan@profusion.mobi> wrote:
>
> * Gustavo F. Padovan <padovan@profusion.mobi> [2011-03-16 15:44:46 -0300]:
>
>> We can't send new commands before a cmd_complete for the HCI_RESET commnnd
>> shows up.
>>
>> Reported-by: Mikko Vinni <mmvinni@yahoo.com>
>> Reported-by: Justin P. Mattock <justinmattock@gmail.com>
>> Reported-by: Ed Tomlinson <edt@aei.ca>
>> Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
>> ---
>> include/net/bluetooth/hci.h | 2 ++
>> net/bluetooth/hci_core.c | 3 +++
>> net/bluetooth/hci_event.c | 4 +++-
>> 3 files changed, 8 insertions(+), 1 deletions(-)
>
> It works for me, but can someone test this and then add a Tested-by line.
> Thanks.
Which hardware is needed to test this?
I have a 1.1 dongle which doesn't work on current mainline tree, but
I'm not sure it is this same issue. I "fixed" it by upgrading the
firmware to support 1.2, but I can downgrade it to test if this is
related to 1.1 dongles.
Regards,
--
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil
^ permalink raw reply
* Re: [PATCH] Bluetooth: Fix HCI_RESET command syncronization
From: Gustavo F. Padovan @ 2011-03-16 18:46 UTC (permalink / raw)
To: linux-bluetooth; +Cc: mmvinni, justinmattock, edt
In-Reply-To: <1300301086-22653-1-git-send-email-padovan@profusion.mobi>
* Gustavo F. Padovan <padovan@profusion.mobi> [2011-03-16 15:44:46 -0300]:
> We can't send new commands before a cmd_complete for the HCI_RESET commnnd
> shows up.
>
> Reported-by: Mikko Vinni <mmvinni@yahoo.com>
> Reported-by: Justin P. Mattock <justinmattock@gmail.com>
> Reported-by: Ed Tomlinson <edt@aei.ca>
> Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
> ---
> include/net/bluetooth/hci.h | 2 ++
> net/bluetooth/hci_core.c | 3 +++
> net/bluetooth/hci_event.c | 4 +++-
> 3 files changed, 8 insertions(+), 1 deletions(-)
It works for me, but can someone test this and then add a Tested-by line.
Thanks.
--
Gustavo F. Padovan
http://profusion.mobi
^ permalink raw reply
* [PATCH] Bluetooth: Fix HCI_RESET command syncronization
From: Gustavo F. Padovan @ 2011-03-16 18:44 UTC (permalink / raw)
To: linux-bluetooth; +Cc: mmvinni, justinmattock, edt
In-Reply-To: <4D7BB10B.3080100@gmail.com>
We can't send new commands before a cmd_complete for the HCI_RESET commnnd
shows up.
Reported-by: Mikko Vinni <mmvinni@yahoo.com>
Reported-by: Justin P. Mattock <justinmattock@gmail.com>
Reported-by: Ed Tomlinson <edt@aei.ca>
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
---
include/net/bluetooth/hci.h | 2 ++
net/bluetooth/hci_core.c | 3 +++
net/bluetooth/hci_event.c | 4 +++-
3 files changed, 8 insertions(+), 1 deletions(-)
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index ec6acf2..2c0d309 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -84,6 +84,8 @@ enum {
HCI_SERVICE_CACHE,
HCI_LINK_KEYS,
HCI_DEBUG_KEYS,
+
+ HCI_RESET,
};
/* HCI ioctl defines */
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index b372fb8..32b82e2 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -534,6 +534,8 @@ int hci_dev_open(__u16 dev)
set_bit(HCI_INIT, &hdev->flags);
hdev->init_last_cmd = 0;
+ set_bit(HCI_RESET, &hdev->flags);
+
ret = __hci_request(hdev, hci_init_req, 0,
msecs_to_jiffies(HCI_INIT_TIMEOUT));
@@ -1074,6 +1076,7 @@ static void hci_cmd_timer(unsigned long arg)
BT_ERR("%s command tx timeout", hdev->name);
atomic_set(&hdev->cmd_cnt, 1);
+ clear_bit(HCI_RESET, &hdev->flags);
tasklet_schedule(&hdev->cmd_task);
}
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 3fbfa50..cebe7588 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -183,6 +183,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG("%s status 0x%x", hdev->name, status);
+ clear_bit(HCI_RESET, &hdev->flags);
+
hci_req_complete(hdev, HCI_OP_RESET, status);
}
@@ -1847,7 +1849,7 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
if (ev->opcode != HCI_OP_NOP)
del_timer(&hdev->cmd_timer);
- if (ev->ncmd) {
+ if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) {
atomic_set(&hdev->cmd_cnt, 1);
if (!skb_queue_empty(&hdev->cmd_q))
tasklet_schedule(&hdev->cmd_task);
--
1.7.4.1
^ permalink raw reply related
* Re: Switching between SBC and MPEG audio on headsets
From: Arun Raghavan @ 2011-03-16 18:19 UTC (permalink / raw)
To: Brian Gix; +Cc: linux-bluetooth
In-Reply-To: <4D7FCF71.7080702@codeaurora.org>
On Tue, 2011-03-15 at 13:43 -0700, Brian Gix wrote:
> Hi Arun,
>
> On 3/15/2011 12:51 PM, Arun Raghavan wrote:
> > Hey Brian,
> >
>
> [...]
>
> >
> > I'm quite unfamiliar with how this works, so please excuse any wild
> > inaccuracies in terminology. I believe that I am doing it this way
> > already (mostly discovered by trial and error). When I want to
> > reconfigure, I do the following:
> >
> > - Send a BT_STOP_STREAM request, get the expected response
> > - Send a BT_CLOSE request, get the expected response
> > - Send a BT_OPEN request with the new seid, get the expected response
> > - Send a BT_SET_CONFIGURATION request with the new caps, get the
> > expected response
> > - Send a BT_START_STREAM, wait for the response
> > - Start streaming
>
> Well, with full knowledge that I *haven't* examined this part of BlueZ,
> I can say that from a protocol perspective, the AVDTP_SET_CONFIG must go
> over the air/be acknowledged before the AVDTP_OPEN can be
> sent/acknowledged. I haven't checked to see if those step are
> obfuscated at all by the BT_OPEN/BT_SET_CONFIGURATION naming convention,
> or if it is a simple mapping.
>
> On a compliant device, an Open directly following a Close should return
> a NOT_CONFIGURED error. But it may be that a less strict SNK device
> might assume the last configuration and overlook the protocol error.
You're right - the BT_OPEN doesn't result in an AVDTP_OPEN, this happens
after the SET_CONFIGURATION is done. I'll try to hack up a patch to look
up a new rsep if the media type of the lsep and currently selected rsep
do not match.
Cheers,
Arun
p.s.: FWIW, the debug log looks like this:
bluetoothd[17790]: audio/unix.c:client_cb() Audio API: BT_REQUEST <- BT_STOP_STREAM
bluetoothd[17790]: audio/avdtp.c:avdtp_ref() 0x7fc7f57aa260: ref=4
bluetoothd[17790]: audio/a2dp.c:setup_ref() 0x7fc7f57a86d0: ref=1
bluetoothd[17790]: audio/avdtp.c:session_cb()
bluetoothd[17790]: audio/avdtp.c:avdtp_parse_resp() SUSPEND request succeeded
bluetoothd[17790]: audio/avdtp.c:avdtp_sep_set_state() stream state changed: STREAMING -> OPEN
bluetoothd[17790]: audio/sink.c:sink_set_state() State changed /org/bluez/17790/hci0/dev_00_0B_E4_91_11_A1: SINK_STATE_PLAYING -> SINK_STATE_CONNECTED
bluetoothd[17790]: audio/a2dp.c:suspend_cfm() Source 0x7fc7f57869d0: Suspend_Cfm
bluetoothd[17790]: audio/unix.c:unix_ipc_sendmsg() Audio API: BT_RESPONSE -> BT_STOP_STREAM
bluetoothd[17790]: audio/a2dp.c:setup_unref() 0x7fc7f57a86d0: ref=0
bluetoothd[17790]: audio/a2dp.c:setup_free() 0x7fc7f57a86d0
bluetoothd[17790]: audio/avdtp.c:avdtp_unref() 0x7fc7f57aa260: ref=3
bluetoothd[17790]: audio/unix.c:client_cb() Audio API: BT_REQUEST <- BT_SUSPEND_STREAM
bluetoothd[17790]: audio/a2dp.c:a2dp_sep_unlock() SEP 0x7fc7f57869d0 unlocked
bluetoothd[17790]: audio/avdtp.c:avdtp_unref() 0x7fc7f57aa260: ref=2
bluetoothd[17790]: audio/unix.c:unix_ipc_sendmsg() Audio API: BT_RESPONSE -> BT_SUSPEND_STREAM
bluetoothd[17790]: audio/unix.c:client_cb() Audio API: BT_REQUEST <- BT_OPEN
bluetoothd[17790]: audio/unix.c:handle_a2dp_open() open a2dp - object=/org/bluez/17790/hci0/dev_00_0B_E4_91_11_A1 source=ANY destination=ANY lock=write
bluetoothd[17790]: audio/avdtp.c:avdtp_ref() 0x7fc7f57aa260: ref=3
bluetoothd[17790]: audio/a2dp.c:a2dp_sep_lock() SEP 0x7fc7f5787250 locked
bluetoothd[17790]: audio/unix.c:unix_ipc_sendmsg() Audio API: BT_RESPONSE -> BT_OPEN
bluetoothd[17790]: audio/unix.c:client_cb() Audio API: BT_REQUEST <- BT_SET_CONFIGURATION
bluetoothd[17790]: audio/unix.c:print_mpeg12() Media Codec: MPEG12 Channel Modes: Stereo Frequencies: 44.1Khz Layers: 3 CRC: No
bluetoothd[17790]: audio/a2dp.c:a2dp_config() a2dp_config: selected SEP 0x7fc7f5787250
bluetoothd[17790]: audio/avdtp.c:avdtp_ref() 0x7fc7f57aa260: ref=4
bluetoothd[17790]: audio/a2dp.c:setup_ref() 0x7fc7f57a86d0: ref=1
bluetoothd[17790]: audio/avdtp.c:session_cb()
bluetoothd[17790]: audio/avdtp.c:avdtp_parse_resp() CLOSE request succeeded
bluetoothd[17790]: audio/avdtp.c:avdtp_sep_set_state() stream state changed: OPEN -> CLOSING
bluetoothd[17790]: audio/a2dp.c:close_cfm() Source 0x7fc7f57869d0: Close_Cfm
bluetoothd[17790]: audio/avdtp.c:avdtp_sep_set_state() stream state changed: CLOSING -> IDLE
bluetoothd[17790]: audio/avdtp.c:avdtp_unref() 0x7fc7f57aa260: ref=3
bluetoothd[17790]: audio/avdtp.c:avdtp_set_configuration() 0x7fc7f57aa260: int_seid=2, acp_seid=2
bluetoothd[17790]: audio/avdtp.c:session_cb()
bluetoothd[17790]: audio/avdtp.c:avdtp_parse_resp() SET_CONFIGURATION request succeeded
bluetoothd[17790]: audio/a2dp.c:setconf_cfm() Source 0x7fc7f5787250: Set_Configuration_Cfm
bluetoothd[17790]: audio/avdtp.c:avdtp_ref() 0x7fc7f57aa260: ref=4
bluetoothd[17790]: audio/avdtp.c:avdtp_sep_set_state() stream state changed: IDLE -> CONFIGURED
bluetoothd[17790]: audio/avdtp.c:session_cb()
bluetoothd[17790]: audio/avdtp.c:avdtp_parse_resp() OPEN request succeeded
bluetoothd[17790]: audio/avdtp.c:avdtp_connect_cb() AVDTP: connected transport channel to 00:0B:E4:91:11:A1
bluetoothd[17790]: audio/avdtp.c:handle_transport_connect() sk 26, omtu 895, send buffer size 61440
bluetoothd[17790]: audio/a2dp.c:open_cfm() Source 0x7fc7f5787250: Open_Cfm
bluetoothd[17790]: audio/unix.c:unix_ipc_sendmsg() Audio API: BT_RESPONSE -> BT_SET_CONFIGURATION
bluetoothd[17790]: audio/a2dp.c:setup_unref() 0x7fc7f57a86d0: ref=0
bluetoothd[17790]: audio/a2dp.c:setup_free() 0x7fc7f57a86d0
bluetoothd[17790]: audio/avdtp.c:avdtp_unref() 0x7fc7f57aa260: ref=3
bluetoothd[17790]: audio/avdtp.c:avdtp_sep_set_state() stream state changed: CONFIGURED -> OPEN
bluetoothd[17790]: audio/sink.c:sink_set_state() State changed /org/bluez/17790/hci0/dev_00_0B_E4_91_11_A1: SINK_STATE_CONNECTED -> SINK_STATE_CONNECTED
bluetoothd[17790]: audio/device.c:device_set_state() state change attempted from connected to connected
bluetoothd[17790]: audio/unix.c:client_cb() Audio API: BT_REQUEST <- BT_START_STREAM
bluetoothd[17790]: audio/avdtp.c:avdtp_ref() 0x7fc7f57aa260: ref=4
bluetoothd[17790]: audio/a2dp.c:setup_ref() 0x7fc7f57a86d0: ref=1
bluetoothd[17790]: audio/avdtp.c:session_cb()
bluetoothd[17790]: audio/avdtp.c:avdtp_parse_resp() START request succeeded
bluetoothd[17790]: audio/a2dp.c:start_cfm() Source 0x7fc7f5787250: Start_Cfm
bluetoothd[17790]: audio/unix.c:unix_ipc_sendmsg() Audio API: BT_RESPONSE -> BT_START_STREAM
bluetoothd[17790]: audio/unix.c:unix_ipc_sendmsg() Audio API: BT_RESPONSE -> BT_NEW_STREAM
bluetoothd[17790]: audio/a2dp.c:setup_unref() 0x7fc7f57a86d0: ref=0
bluetoothd[17790]: audio/a2dp.c:setup_free() 0x7fc7f57a86d0
bluetoothd[17790]: audio/avdtp.c:avdtp_unref() 0x7fc7f57aa260: ref=3
bluetoothd[17790]: audio/avdtp.c:avdtp_sep_set_state() stream state changed: OPEN -> STREAMING
bluetoothd[17790]: audio/sink.c:sink_set_state() State changed /org/bluez/17790/hci0/dev_00_0B_E4_91_11_A1: SINK_STATE_CONNECTED -> SINK_STATE_PLAYING
^ permalink raw reply
* [PATCH] Add discover characteristics by uuid to gattool
From: Sheldon Demario @ 2011-03-16 17:40 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Sheldon Demario
---
attrib/client.c | 2 +-
attrib/gatt.c | 16 +++++++++++-----
attrib/gatt.h | 3 ++-
attrib/gatttool.c | 3 ++-
attrib/interactive.c | 18 ++++++++++++++++--
5 files changed, 32 insertions(+), 10 deletions(-)
diff --git a/attrib/client.c b/attrib/client.c
index 3237a6b..54bdc79 100644
--- a/attrib/client.c
+++ b/attrib/client.c
@@ -960,7 +960,7 @@ static DBusMessage *discover_char(DBusConnection *conn, DBusMessage *msg,
qchr->prim = prim;
qchr->msg = dbus_message_ref(msg);
- gatt_discover_char(gatt->attrib, att->start, att->end,
+ gatt_discover_char(gatt->attrib, att->start, att->end, NULL,
char_discovered_cb, qchr);
return NULL;
diff --git a/attrib/gatt.c b/attrib/gatt.c
index 32bd4a0..b328c72 100644
--- a/attrib/gatt.c
+++ b/attrib/gatt.c
@@ -40,7 +40,7 @@ struct discover_primary {
struct discover_char {
GAttrib *attrib;
- bt_uuid_t uuid;
+ bt_uuid_t *uuid;
uint16_t end;
GSList *characteristics;
gatt_cb_t cb;
@@ -59,6 +59,7 @@ static void discover_char_free(struct discover_char *dc)
g_slist_foreach(dc->characteristics, (GFunc) g_free, NULL);
g_slist_free(dc->characteristics);
g_attrib_unref(dc->attrib);
+ g_free(dc->uuid);
g_free(dc);
}
@@ -281,6 +282,9 @@ static void char_discovered_cb(guint8 status, const guint8 *ipdu, guint16 iplen,
goto done;
}
+ if (dc->uuid && bt_uuid_cmp(dc->uuid, &uuid))
+ break;
+
chars->handle = last;
chars->properties = value[2];
chars->value_handle = att_get_u16(&value[3]);
@@ -313,16 +317,17 @@ done:
}
guint gatt_discover_char(GAttrib *attrib, uint16_t start, uint16_t end,
- gatt_cb_t func, gpointer user_data)
+ bt_uuid_t *uuid, gatt_cb_t func,
+ gpointer user_data)
{
uint8_t pdu[ATT_DEFAULT_LE_MTU];
struct discover_char *dc;
+ bt_uuid_t type_uuid;
guint16 plen;
- bt_uuid_t uuid;
- bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
+ bt_uuid16_create(&type_uuid, GATT_CHARAC_UUID);
- plen = enc_read_by_type_req(start, end, &uuid, pdu, sizeof(pdu));
+ plen = enc_read_by_type_req(start, end, &type_uuid, pdu, sizeof(pdu));
if (plen == 0)
return 0;
@@ -334,6 +339,7 @@ guint gatt_discover_char(GAttrib *attrib, uint16_t start, uint16_t end,
dc->cb = func;
dc->user_data = user_data;
dc->end = end;
+ dc->uuid = uuid;
return g_attrib_send(attrib, 0, pdu[0], pdu, plen, char_discovered_cb,
dc, NULL);
diff --git a/attrib/gatt.h b/attrib/gatt.h
index 730de7e..c6d3843 100644
--- a/attrib/gatt.h
+++ b/attrib/gatt.h
@@ -30,7 +30,8 @@ guint gatt_discover_primary(GAttrib *attrib, bt_uuid_t *uuid, gatt_cb_t func,
gpointer user_data);
guint gatt_discover_char(GAttrib *attrib, uint16_t start, uint16_t end,
- gatt_cb_t func, gpointer user_data);
+ bt_uuid_t *uuid, gatt_cb_t func,
+ gpointer user_data);
guint gatt_read_char(GAttrib *attrib, uint16_t handle, uint16_t offset,
GAttribResultFunc func, gpointer user_data);
diff --git a/attrib/gatttool.c b/attrib/gatttool.c
index 729e18d..0dfbc04 100644
--- a/attrib/gatttool.c
+++ b/attrib/gatttool.c
@@ -206,7 +206,8 @@ static gboolean characteristics(gpointer user_data)
{
GAttrib *attrib = user_data;
- gatt_discover_char(attrib, opt_start, opt_end, char_discovered_cb, NULL);
+ gatt_discover_char(attrib, opt_start, opt_end, opt_uuid,
+ char_discovered_cb, NULL);
return FALSE;
}
diff --git a/attrib/interactive.c b/attrib/interactive.c
index b32e9e7..7e5aa4c 100644
--- a/attrib/interactive.c
+++ b/attrib/interactive.c
@@ -431,7 +431,21 @@ static void cmd_char(int argcp, char **argvp)
}
}
- gatt_discover_char(attrib, start, end, char_cb, NULL);
+ if (argcp > 3) {
+ bt_uuid_t *uuid;
+
+ uuid = g_try_new(bt_uuid_t, 1);
+ if (bt_string_to_uuid(uuid, argvp[3]) < 0) {
+ g_free(uuid);
+ printf("Invalid UUID\n");
+ return;
+ }
+
+ gatt_discover_char(attrib, start, end, uuid, char_cb, NULL);
+ return;
+ }
+
+ gatt_discover_char(attrib, start, end, NULL, char_cb, NULL);
}
static void cmd_char_desc(int argcp, char **argvp)
@@ -658,7 +672,7 @@ static struct {
"Disconnect from a remote device" },
{ "primary", cmd_primary, "[UUID]",
"Primary Service Discovery" },
- { "characteristics", cmd_char, "[start hnd] [end hnd]",
+ { "characteristics", cmd_char, "[start hnd [end hnd [UUID]]]",
"Characteristics Discovery" },
{ "char-desc", cmd_char_desc, "[start hnd] [end hnd]",
"Characteristics Descriptor Discovery" },
--
1.7.1
^ permalink raw reply related
* [PATCH 4/4] Bluetooth: mgmt: Add support for setting the local name
From: johan.hedberg @ 2011-03-16 12:29 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1300278577-23068-1-git-send-email-johan.hedberg@gmail.com>
From: Johan Hedberg <johan.hedberg@nokia.com>
This patch adds a new set_local_name management command as well as a
local_name_changed management event. With these user space can both
change the local name as well as monitor changes to it by others.
Signed-off-by: Johan Hedberg <johan.hedberg@nokia.com>
---
include/net/bluetooth/hci_core.h | 1 +
include/net/bluetooth/mgmt.h | 10 +++++
net/bluetooth/hci_event.c | 9 +++--
net/bluetooth/mgmt.c | 75 ++++++++++++++++++++++++++++++++++++++
4 files changed, 92 insertions(+), 3 deletions(-)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 9aabb14..3912c7a 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -767,6 +767,7 @@ int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr,
u8 status);
int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status);
+int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status);
/* HCI info for socket */
#define hci_pi(sk) ((struct hci_pinfo *) sk)
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 7d0749b..89e7c82 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -172,6 +172,11 @@ struct mgmt_rp_user_confirm_reply {
#define MGMT_OP_USER_CONFIRM_NEG_REPLY 0x0016
+#define MGMT_OP_SET_LOCAL_NAME 0x0017
+struct mgmt_cp_set_local_name {
+ __u8 name[MGMT_MAX_NAME_LENGTH];
+} __packed;
+
#define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete {
__le16 opcode;
@@ -239,3 +244,8 @@ struct mgmt_ev_auth_failed {
bdaddr_t bdaddr;
__u8 status;
} __packed;
+
+#define MGMT_EV_LOCAL_NAME_CHANGED 0x0011
+struct mgmt_ev_local_name_changed {
+ __u8 name[MGMT_MAX_NAME_LENGTH];
+} __packed;
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 91ef526..0def3e1 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -193,13 +193,16 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG("%s status 0x%x", hdev->name, status);
- if (status)
- return;
-
sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LOCAL_NAME);
if (!sent)
return;
+ if (test_bit(HCI_MGMT, &hdev->flags))
+ mgmt_set_local_name_complete(hdev->id, sent, status);
+
+ if (status)
+ return;
+
memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH);
}
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 67529c8..98988c8 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1258,6 +1258,45 @@ failed:
return err;
}
+static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
+ u16 len)
+{
+ struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
+ struct hci_cp_write_local_name hci_cp;
+ struct hci_dev *hdev;
+ struct pending_cmd *cmd;
+ int err;
+
+ BT_DBG("");
+
+ if (len != sizeof(*mgmt_cp))
+ return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
+
+ hdev = hci_dev_get(index);
+ if (!hdev)
+ return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
+
+ hci_dev_lock_bh(hdev);
+
+ cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
+ if (!cmd) {
+ err = -ENOMEM;
+ goto failed;
+ }
+
+ memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
+ err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
+ &hci_cp);
+ if (err < 0)
+ mgmt_pending_remove(cmd);
+
+failed:
+ hci_dev_unlock_bh(hdev);
+ hci_dev_put(hdev);
+
+ return err;
+}
+
int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
{
unsigned char *buf;
@@ -1353,6 +1392,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
case MGMT_OP_USER_CONFIRM_NEG_REPLY:
err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
break;
+ case MGMT_OP_SET_LOCAL_NAME:
+ err = set_local_name(sk, index, buf + sizeof(*hdr), len);
+ break;
default:
BT_DBG("Unknown op %u", opcode);
err = cmd_status(sk, index, opcode, 0x01);
@@ -1649,3 +1691,36 @@ int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
}
+
+int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
+{
+ struct pending_cmd *cmd;
+ struct mgmt_cp_set_local_name ev;
+ int err;
+
+ memset(&ev, 0, sizeof(ev));
+ memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
+
+ cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
+ if (!cmd)
+ goto send_event;
+
+ if (status) {
+ err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
+ goto failed;
+ }
+
+ err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
+ sizeof(ev));
+ if (err < 0)
+ goto failed;
+
+send_event:
+ err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
+ cmd ? cmd->sk : NULL);
+
+failed:
+ if (cmd)
+ mgmt_pending_remove(cmd);
+ return err;
+}
--
1.7.4.1
^ permalink raw reply related
* [PATCH 3/4] Bluetooth: mgmt: Add local name information to read_info reply
From: johan.hedberg @ 2011-03-16 12:29 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1300278577-23068-1-git-send-email-johan.hedberg@gmail.com>
From: Johan Hedberg <johan.hedberg@nokia.com>
This patch adds the name of the adapter to the reply of the read_info
management command.
The management messages reserve 249 bytes for the name instead of 248
(like in the HCI spec) so that there is always a guarantee that it is
nul-terminated. That way it can safely be passed onto string
manipulation functions.
Signed-off-by: Johan Hedberg <johan.hedberg@nokia.com>
---
include/net/bluetooth/mgmt.h | 5 +++++
net/bluetooth/mgmt.c | 4 ++++
2 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 5fabfa8..7d0749b 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -41,6 +41,10 @@ struct mgmt_rp_read_index_list {
__le16 index[0];
} __packed;
+/* Reserve one extra byte for names in management messages so that they
+ * are always guaranteed to be nul-terminated */
+#define MGMT_MAX_NAME_LENGTH (HCI_MAX_NAME_LENGTH + 1)
+
#define MGMT_OP_READ_INFO 0x0004
struct mgmt_rp_read_info {
__u8 type;
@@ -55,6 +59,7 @@ struct mgmt_rp_read_info {
__u16 manufacturer;
__u8 hci_ver;
__u16 hci_rev;
+ __u8 name[MGMT_MAX_NAME_LENGTH];
} __packed;
struct mgmt_mode {
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 4476d8e..67529c8 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -183,6 +183,8 @@ static int read_controller_info(struct sock *sk, u16 index)
set_bit(HCI_MGMT, &hdev->flags);
+ memset(&rp, 0, sizeof(rp));
+
rp.type = hdev->dev_type;
rp.powered = test_bit(HCI_UP, &hdev->flags);
@@ -204,6 +206,8 @@ static int read_controller_info(struct sock *sk, u16 index)
rp.hci_ver = hdev->hci_ver;
put_unaligned_le16(hdev->hci_rev, &rp.hci_rev);
+ memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
+
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
--
1.7.4.1
^ permalink raw reply related
* [PATCH 2/4] Bluetooth: Add define for the maximum name length on HCI level
From: johan.hedberg @ 2011-03-16 12:29 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1300278577-23068-1-git-send-email-johan.hedberg@gmail.com>
From: Johan Hedberg <johan.hedberg@nokia.com>
This patch adds a clear define for the maximum device name length in HCI
messages and thereby avoids magic numbers in the code.
Signed-off-by: Johan Hedberg <johan.hedberg@nokia.com>
---
include/net/bluetooth/hci.h | 8 +++++---
include/net/bluetooth/hci_core.h | 2 +-
net/bluetooth/hci_event.c | 4 ++--
net/bluetooth/hci_sysfs.c | 6 +++---
4 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index ec6acf2..1cd031c 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -535,15 +535,17 @@ struct hci_cp_delete_stored_link_key {
__u8 delete_all;
} __packed;
+#define HCI_MAX_NAME_LENGTH 248
+
#define HCI_OP_WRITE_LOCAL_NAME 0x0c13
struct hci_cp_write_local_name {
- __u8 name[248];
+ __u8 name[HCI_MAX_NAME_LENGTH];
} __packed;
#define HCI_OP_READ_LOCAL_NAME 0x0c14
struct hci_rp_read_local_name {
__u8 status;
- __u8 name[248];
+ __u8 name[HCI_MAX_NAME_LENGTH];
} __packed;
#define HCI_OP_WRITE_CA_TIMEOUT 0x0c16
@@ -745,7 +747,7 @@ struct hci_ev_auth_complete {
struct hci_ev_remote_name {
__u8 status;
bdaddr_t bdaddr;
- __u8 name[248];
+ __u8 name[HCI_MAX_NAME_LENGTH];
} __packed;
#define HCI_EV_ENCRYPT_CHANGE 0x08
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 441dadb..9aabb14 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -94,7 +94,7 @@ struct hci_dev {
__u8 bus;
__u8 dev_type;
bdaddr_t bdaddr;
- __u8 dev_name[248];
+ __u8 dev_name[HCI_MAX_NAME_LENGTH];
__u8 dev_class[3];
__u8 major_class;
__u8 minor_class;
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 3fbfa50..91ef526 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -200,7 +200,7 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
if (!sent)
return;
- memcpy(hdev->dev_name, sent, 248);
+ memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH);
}
static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb)
@@ -212,7 +212,7 @@ static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb)
if (rp->status)
return;
- memcpy(hdev->dev_name, rp->name, 248);
+ memcpy(hdev->dev_name, rp->name, HCI_MAX_NAME_LENGTH);
}
static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb)
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index 3c838a6..e544216 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -216,13 +216,13 @@ static ssize_t show_type(struct device *dev, struct device_attribute *attr, char
static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf)
{
struct hci_dev *hdev = dev_get_drvdata(dev);
- char name[249];
+ char name[HCI_MAX_NAME_LENGTH + 1];
int i;
- for (i = 0; i < 248; i++)
+ for (i = 0; i < HCI_MAX_NAME_LENGTH; i++)
name[i] = hdev->dev_name[i];
- name[248] = '\0';
+ name[HCI_MAX_NAME_LENGTH] = '\0';
return sprintf(buf, "%s\n", name);
}
--
1.7.4.1
^ permalink raw reply related
* [PATCH 1/4] Bluetooth: Fix missing hci_dev_lock_bh in user_confirm_reply
From: johan.hedberg @ 2011-03-16 12:29 UTC (permalink / raw)
To: linux-bluetooth
From: Johan Hedberg <johan.hedberg@nokia.com>
The code was correctly calling _unlock at the end of the function but
there was no actual _lock call anywhere.
Signed-off-by: Johan Hedberg <johan.hedberg@nokia.com>
---
net/bluetooth/mgmt.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 0054c74..4476d8e 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1230,6 +1230,8 @@ static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
if (!hdev)
return cmd_status(sk, index, mgmt_op, ENODEV);
+ hci_dev_lock_bh(hdev);
+
if (!test_bit(HCI_UP, &hdev->flags)) {
err = cmd_status(sk, index, mgmt_op, ENETDOWN);
goto failed;
--
1.7.4.1
^ permalink raw reply related
* Re: [RFC v2 0/6] LE advertising cache
From: Anderson Lizardo @ 2011-03-16 12:21 UTC (permalink / raw)
To: Ville Tervo; +Cc: ext Andre Guedes, linux-bluetooth
In-Reply-To: <20110316055357.GG4369@null>
Hi Ville,
On Wed, Mar 16, 2011 at 1:53 AM, Ville Tervo <ville.tervo@nokia.com> wrote:
> On Tue, Mar 15, 2011 at 10:41:55AM -0400, ext Anderson Lizardo wrote:
>> IIRC the connection procedure defined on the spec requires this scan.
>> See for instance the general connection establishment procedure at
>> page 1715
>
> But it makes "Direct Connection Establishment" impossible.
I can only see on the spec "Direct Connection Establishment" allowed
to be used as sub-procedures for either General or Selective
connection establishment. Correct me if you find other references
outside these two procedures.
The problem is that, unlike BR/EDR where the address is enough, for LE
you need to know the address type as well before connecting and this
information can only be obtained by means of advertising reports (from
a scanning during discovery, or from previously bonded devices, for
which we need to have stored this information).
Also see this note regarding privacy-enabled peripherals (page 1704):
"A Central may connect to a Peripheral that supports the privacy
feature using only the general connection establishment procedure."
(I'm not sure I get this sentence right, as it uses the dubious "may
... only" sentence).
> Is it needed to pass PTS for example?
Note sure. Claudio may know more about PTS requirements on GAP part.
Regards,
--
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil
^ permalink raw reply
* [PATCH v5 4/4] Sim Access Profile test scripts
From: Waldemar Rymarkiewicz @ 2011-03-16 12:10 UTC (permalink / raw)
To: Johan Hedberg; +Cc: linux-bluetooth, Waldemar Rymarkiewicz
In-Reply-To: <1300277421-8053-1-git-send-email-waldemar.rymarkiewicz@tieto.com>
Add simple SAP client python implementation and a test script.
To run test-sap.py you need Python 2.6 or newer (tested with 2.6 only)
and PyBluez package installed.
---
test/sap.py | 944 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
test/test-sap.py | 139 ++++++++
2 files changed, 1083 insertions(+), 0 deletions(-)
create mode 100644 test/sap.py
create mode 100755 test/test-sap.py
diff --git a/test/sap.py b/test/sap.py
new file mode 100644
index 0000000..5a0c711
--- /dev/null
+++ b/test/sap.py
@@ -0,0 +1,944 @@
+""" Copyright (C) 2011 Tieto """
+
+""" Szymon Janc <szymon.janc@tieto.com> """
+""" Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com> """
+
+""" This program is free software; you can redistribute it and/or modify """
+""" it under the terms of the GNU General Public License as published by """
+""" the Free Software Foundation; either version 2 of the License, or """
+""" (at your option) any later version. """
+
+""" This program is distributed in the hope that it will be useful, """
+""" but WITHOUT ANY WARRANTY; without even the implied warranty of """
+""" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the """
+""" GNU General Public License for more details. """
+
+""" You should have received a copy of the GNU General Public License """
+""" along with this program; if not, write to the Free Software """
+""" Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA """
+
+from array import array
+from bluetooth import *
+import time
+import re
+
+class SAPParam:
+ """ SAP Parameter Class """
+
+ MaxMsgSize = 0x00
+ ConnectionStatus = 0x01
+ ResultCode = 0x02
+ DisconnectionType = 0x03
+ CommandAPDU = 0x04
+ ResponseAPDU = 0x05
+ ATR = 0x06
+ CardReaderStatus = 0x07
+ StatusChange = 0x08
+ TransportProtocol = 0x09
+ CommandAPDU7816 = 0x10
+
+ def __init__(self, name, id, value = None):
+ self.name = name
+ self.id = id
+ self.value = value
+
+ def _padding(self, buf):
+ pad = array('B')
+ while ( (len(buf) + len(pad)) % 4 ) != 0:
+ pad.append(0)
+ return pad
+
+ def _basicCheck(self, buf):
+ if len(buf) < 4 or (len(buf) % 4) != 0 or buf[1] != 0:
+ return (-1, -1)
+ if buf[0] != self.id:
+ return (-1, -1)
+ plen = buf[2] * 256 + buf[3] + 4
+ if plen > len(buf):
+ return (-1, -1)
+ pad = plen
+ while (pad % 4) != 0:
+ if buf[pad] != 0:
+ return (-1, -1)
+ pad+=1
+ return (plen, pad)
+
+ def getID(self):
+ return self.id
+
+ def getValue(self):
+ return self.value
+
+ def getContent(self):
+ return "%s(id=0x%.2X), value=%s \n" % (self.name, self.id, self.value)
+
+ def serialize(self):
+ a = array('B', '\00\00\00\00')
+ a[0] = self.id
+ a[1] = 0 # reserved
+ a[2] = 0 # length
+ a[3] = 1 # length
+ a.append(self.value)
+ a.extend(self._padding(a))
+ return a
+
+ def deserialize(self, buf):
+ p = self._basicCheck(buf)
+ if p[0] == -1:
+ return -1
+ self.id = buf[0]
+ self.value = buf[4]
+ return p[1]
+
+
+class SAPParam_MaxMsgSize(SAPParam):
+ """MaxMsgSize Param """
+
+ def __init__(self, value = None):
+ SAPParam.__init__(self,"MaxMsgSize", SAPParam.MaxMsgSize, value)
+ self.__validate()
+
+ def __validate(self):
+ if self.value > 0xFFFF:
+ self.value = 0xFFFF
+
+ def serialize(self):
+ a = array('B', '\00\00\00\00')
+ a[0] = self.id
+ a[3] = 2
+ a.append(self.value / 256)
+ a.append(self.value % 256)
+ a.extend(self._padding(a))
+ return a
+
+ def deserialize(self, buf):
+ p = self._basicCheck(buf)
+ if p[0] == -1 :
+ return -1
+ self.value = buf[4] * 256 + buf[5]
+ return p[1]
+
+class SAPParam_CommandAPDU(SAPParam):
+ def __init__(self, value = None):
+ if value is None:
+ SAPParam.__init__(self, "CommandAPDU", SAPParam.CommandAPDU, array('B'))
+ else:
+ SAPParam.__init__(self, "CommandAPDU", SAPParam.CommandAPDU, array('B', value))
+
+ def serialize(self):
+ a = array('B', '\00\00\00\00')
+ a[0] = self.id
+ plen = len(self.value)
+ a[2] = plen / 256
+ a[3] = plen % 256
+ a.extend(self.value)
+ a.extend(self._padding(a))
+ return a
+
+ def deserialize(self, buf):
+ p = self._basicCheck(buf)
+ if p[0] == -1:
+ return -1
+ self.value = buf[4:p[0]]
+ return p[1]
+
+class SAPParam_ResponseAPDU(SAPParam_CommandAPDU):
+ """ResponseAPDU Param """
+
+ def __init__(self, value = None):
+ if value is None:
+ SAPParam.__init__(self, "ResponseAPDU", SAPParam.ResponseAPDU, array('B'))
+ else:
+ SAPParam.__init__(self, "ResponseAPDU", SAPParam.ResponseAPDU, array('B', value))
+
+class SAPParam_ATR(SAPParam_CommandAPDU):
+ """ATR Param """
+
+ def __init__(self, value = None):
+ if value is None:
+ SAPParam.__init__(self, "ATR", SAPParam.ATR, array('B'))
+ else:
+ SAPParam.__init__(self, "ATR", SAPParam.ATR, array('B', value))
+
+class SAPParam_CommandAPDU7816(SAPParam_CommandAPDU):
+ """Command APDU7816 Param."""
+
+ def __init__(self, value = None):
+ if value is None:
+ SAPParam.__init__(self, "CommandAPDU7816", SAPParam.CommandAPDU7816, array('B'))
+ else:
+ SAPParam.__init__(self, "CommandAPDU7816", SAPParam.CommandAPDU7816, array('B', value))
+
+
+class SAPParam_ConnectionStatus(SAPParam):
+ """Connection status Param."""
+
+ def __init__(self, value = None):
+ SAPParam.__init__(self,"ConnectionStatus", SAPParam.ConnectionStatus, value)
+ self.__validate()
+
+ def __validate(self):
+ if self.value is not None and self.value not in (0x00, 0x01, 0x02, 0x03, 0x04):
+ print "Warning. ConnectionStatus value in reserved range (0x%x)" % self.value
+
+ def deserialize(self, buf):
+ ret = SAPParam.deserialize(self, buf)
+ if ret == -1:
+ return -1
+ self.__validate()
+ return ret
+
+class SAPParam_ResultCode(SAPParam):
+ """ Result Code Param """
+
+ def __init__(self, value = None):
+ SAPParam.__init__(self,"ResultCode", SAPParam.ResultCode, value)
+ self.__validate()
+
+ def __validate(self):
+ if self.value is not None and self.value not in (0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07):
+ print "Warning. ResultCode value in reserved range (0x%x)" % self.value
+
+ def deserialize(self, buf):
+ ret = SAPParam.deserialize(self, buf)
+ if ret == -1:
+ return -1
+ self.__validate()
+ return ret
+
+class SAPParam_DisconnectionType(SAPParam):
+ """Disconnection Type Param."""
+
+ def __init__(self, value = None):
+ SAPParam.__init__(self,"DisconnectionType", SAPParam.DisconnectionType, value)
+ self.__validate()
+
+ def __validate(self):
+ if self.value is not None and self.value not in (0x00, 0x01):
+ print "Warning. DisconnectionType value in reserved range (0x%x)" % self.value
+
+ def deserialize(self, buf):
+ ret = SAPParam.deserialize(self, buf)
+ if ret == -1:
+ return -1
+ self.__validate()
+ return ret
+
+class SAPParam_CardReaderStatus(SAPParam_CommandAPDU):
+ """Card reader Status Param."""
+
+ def __init__(self, value = None):
+ if value is None:
+ SAPParam.__init__(self, "CardReaderStatus", SAPParam.CardReaderStatus, array('B'))
+ else:
+ SAPParam.__init__(self, "CardReaderStatus", SAPParam.CardReaderStatus, array('B', value))
+
+class SAPParam_StatusChange(SAPParam):
+ """Status Change Param """
+
+ def __init__(self, value = None):
+ SAPParam.__init__(self,"StatusChange", SAPParam.StatusChange, value)
+
+ def __validate(self):
+ if self.value is not None and self.value not in (0x00, 0x01, 0x02, 0x03, 0x04, 0x05):
+ print "Warning. StatusChange value in reserved range (0x%x)" % self.value
+
+ def deserialize(self, buf):
+ ret = SAPParam.deserialize(self, buf)
+ if ret == -1:
+ return -1
+ self.__validate()
+ return ret
+
+class SAPParam_TransportProtocol(SAPParam):
+ """Transport Protocol Param """
+
+ def __init__(self, value = None):
+ SAPParam.__init__(self,"TransportProtocol", SAPParam.TransportProtocol, value)
+ self.__validate()
+
+ def __validate(self):
+ if self.value is not None and self.value not in (0x00, 0x01):
+ print "Warning. TransportProtoco value in reserved range (0x%x)" % self.value
+
+ def deserialize(self, buf):
+ ret = SAPParam.deserialize(self, buf)
+ if ret == -1:
+ return -1
+ self.__validate()
+ return ret
+
+class SAPMessage:
+
+ CONNECT_REQ = 0x00
+ CONNECT_RESP = 0x01
+ DISCONNECT_REQ = 0x02
+ DISCONNECT_RESP =0x03
+ DISCONNECT_IND = 0x04
+ TRANSFER_APDU_REQ = 0x05
+ TRANSFER_APDU_RESP = 0x06
+ TRANSFER_ATR_REQ = 0x07
+ TRANSFER_ATR_RESP = 0x08
+ POWER_SIM_OFF_REQ = 0x09
+ POWER_SIM_OFF_RESP = 0x0A
+ POWER_SIM_ON_REQ = 0x0B
+ POWER_SIM_ON_RESP = 0x0C
+ RESET_SIM_REQ = 0x0D
+ RESET_SIM_RESP = 0x0E
+ TRANSFER_CARD_READER_STATUS_REQ = 0x0F
+ TRANSFER_CARD_READER_STATUS_RESP = 0x10
+ STATUS_IND = 0x11
+ ERROR_RESP = 0x12
+ SET_TRANSPORT_PROTOCOL_REQ = 0x13
+ SET_TRANSPORT_PROTOCOL_RESP = 0x14
+
+ def __init__(self, name, id):
+ self.name = name
+ self.id = id
+ self.params = []
+ self.buf = array('B')
+
+ def _basicCheck(self, buf):
+ if len(buf) < 4 or (len(buf) % 4) != 0 :
+ return False
+
+ if buf[0] != self.id:
+ return False
+
+ return True
+
+ def getID(self):
+ return self.id
+
+ def getContent(self):
+ s = "%s(id=0x%.2X) " % (self.name, self.id)
+ if len( self.buf): s = s + "[%s]" % re.sub("(.{2})", "0x\\1 " , self.buf.tostring().encode("hex").upper(), re.DOTALL)
+ s = s + "\n\t"
+ for p in self.params:
+ s = s + "\t" + p.getContent()
+ return s
+
+ def getParams(self):
+ return self.params
+
+ def addParam(self, param):
+ self.params.append(param)
+
+ def serialize(self):
+ ret = array('B', '\00\00\00\00')
+ ret[0] = self.id
+ ret[1] = len(self.params)
+ ret[2] = 0 # reserved
+ ret[3] = 0 # reserved
+ for p in self.params:
+ ret.extend(p.serialize())
+
+ self.buf = ret
+ return ret
+
+ def deserialize(self, buf):
+ self.buf = buf
+ return len(buf) == 4 and buf[1] == 0 and self._basicCheck(buf)
+
+
+class SAPMessage_CONNECT_REQ(SAPMessage):
+ def __init__(self, MaxMsgSize = None):
+ SAPMessage.__init__(self,"CONNECT_REQ", SAPMessage.CONNECT_REQ)
+ if MaxMsgSize is not None:
+ self.addParam(SAPParam_MaxMsgSize(MaxMsgSize))
+
+ def _validate(self):
+ if len(self.params) == 1:
+ if self.params[0].getID() == SAPParam.MaxMsgSize:
+ return True
+ return False
+
+ def deserialize(self, buf):
+ self.buf = buf
+ self.params[:] = []
+ if SAPMessage._basicCheck(self, buf):
+ p = SAPParam_MaxMsgSize()
+ if p.deserialize(buf[4:]) == len(buf[4:]):
+ self.addParam(p)
+ return self._validate()
+
+ return False
+
+class SAPMessage_CONNECT_RESP(SAPMessage):
+ def __init__(self, ConnectionStatus = None, MaxMsgSize = None):
+ SAPMessage.__init__(self,"CONNECT_RESP", SAPMessage.CONNECT_RESP)
+ if ConnectionStatus is not None:
+ self.addParam(SAPParam_ConnectionStatus(ConnectionStatus))
+ if MaxMsgSize is not None:
+ self.addParam(SAPParam_MaxMsgSize(MaxMsgSize))
+
+ def _validate(self):
+ if len(self.params) > 0:
+ if self.params[0] .getID() == SAPParam.ConnectionStatus:
+ if self.params[0].getValue() == 0x02:
+ if len(self.params) == 2:
+ return True
+ else:
+ if len(self.params) == 1:
+ return True
+ return False
+
+ def deserialize(self, buf):
+ self.buf = buf
+ self.params[:] = []
+
+ if SAPMessage._basicCheck(self, buf):
+ p = SAPParam_ConnectionStatus()
+ r = p.deserialize(buf[4:])
+ if r != -1:
+ self.addParam(p)
+ if buf[1] == 2:
+ p = SAPParam_MaxMsgSize()
+ r = p.deserialize(buf[4+r:])
+ if r != -1:
+ self.addParam(p)
+
+ return self._validate()
+
+ return False
+
+class SAPMessage_DISCONNECT_REQ(SAPMessage):
+ def __init__(self):
+ SAPMessage.__init__(self,"DISCONNECT_REQ", SAPMessage.DISCONNECT_REQ)
+
+class SAPMessage_DISCONNECT_RESP(SAPMessage):
+ def __init__(self):
+ SAPMessage.__init__(self,"DISCONNECT_RESP", SAPMessage.DISCONNECT_RESP)
+
+class SAPMessage_DISCONNECT_IND(SAPMessage):
+ def __init__(self, Type = None):
+ SAPMessage.__init__(self,"DISCONNECT_IND", SAPMessage.DISCONNECT_IND)
+ if Type is not None:
+ self.addParam(SAPParam_DisconnectionType(Type))
+
+ def _validate(self):
+ if len(self.params) == 1:
+ if self.params[0].getID() == SAPParam.DisconnectionType:
+ return True
+ return False
+
+ def deserialize(self, buf):
+ self.buf = buf
+ self.params[:] = []
+ if SAPMessage._basicCheck(self, buf):
+ p = SAPParam_DisconnectionType()
+ if p.deserialize(buf[4:]) == len(buf[4:]):
+ self.addParam(p)
+ return self._validate()
+
+ return False
+
+
+class SAPMessage_TRANSFER_APDU_REQ(SAPMessage):
+ def __init__(self, APDU = None, T = False):
+ SAPMessage.__init__(self,"TRANSFER_APDU_REQ", SAPMessage.TRANSFER_APDU_REQ)
+ if APDU is not None:
+ if T :
+ self.addParam(SAPParam_CommandAPDU(APDU))
+ else:
+ self.addParam(SAPParam_CommandAPDU7816(APDU))
+
+ def _validate(self):
+ if len(self.params) == 1:
+ if self.params[0].getID() == SAPParam.CommandAPDU or self.params[0].getID() == SAPParam.CommandAPDU7816:
+ return True
+ return False
+
+ def deserialize(self, buf):
+ self.buf = buf
+ self.params[:] = []
+ if SAPMessage._basicCheck(self, buf):
+
+ p = SAPParam_CommandAPDU()
+ p2 = SAPParam_CommandAPDU7816()
+ if p.deserialize(buf[4:]) == len(buf[4:]):
+ self.addParam(p)
+ return self._validate()
+ elif p2.deserialize(buf[4:]) == len(buf[4:]):
+ self.addParam(p2)
+ return self._validate()
+
+ return False
+
+class SAPMessage_TRANSFER_APDU_RESP(SAPMessage):
+ def __init__(self, ResultCode = None, Response = None):
+ SAPMessage.__init__(self,"TRANSFER_APDU_RESP", SAPMessage.TRANSFER_APDU_RESP)
+ if ResultCode is not None:
+ self.addParam(SAPParam_ResultCode(ResultCode))
+ if Response is not None:
+ self.addParam(SAPParam_ResponseAPDU(Response))
+
+ def _validate(self):
+ if len(self.params) > 0:
+ if self.params[0] .getID() == SAPParam.ResultCode:
+ if self.params[0].getValue() == 0x00:
+ if len(self.params) == 2:
+ return True
+ else:
+ if len(self.params) == 1:
+ return True
+ return False
+
+ def deserialize(self, buf):
+ self.buf = buf
+ self.params[:] = []
+
+ if SAPMessage._basicCheck(self, buf):
+ p = SAPParam_ResultCode()
+ r = p.deserialize(buf[4:])
+ if r != -1:
+ self.addParam(p)
+ if buf[1] == 2:
+ p = SAPParam_ResponseAPDU()
+ r = p.deserialize(buf[4+r:])
+ if r != -1:
+ self.addParam(p)
+
+ return self._validate()
+
+ return False
+
+class SAPMessage_TRANSFER_ATR_REQ(SAPMessage):
+ def __init__(self):
+ SAPMessage.__init__(self,"TRANSFER_ATR_REQ", SAPMessage.TRANSFER_ATR_REQ)
+
+class SAPMessage_TRANSFER_ATR_RESP(SAPMessage):
+ def __init__(self, ResultCode = None, ATR = None):
+ SAPMessage.__init__(self,"TRANSFER_ATR_RESP", SAPMessage.TRANSFER_ATR_RESP)
+ if ResultCode is not None:
+ self.addParam(SAPParam_ResultCode(ResultCode))
+ if ATR is not None:
+ self.addParam(SAPParam_ATR(ATR))
+
+ def _validate(self):
+ if len(self.params) > 0:
+ if self.params[0] .getID() == SAPParam.ResultCode:
+ if self.params[0].getValue() == 0x00:
+ if len(self.params) == 2:
+ return True
+ else:
+ if len(self.params) == 1:
+ return True
+ return False
+
+ def deserialize(self, buf):
+ self.buf = buf
+ self.params[:] = []
+
+ if SAPMessage._basicCheck(self, buf):
+
+ p = SAPParam_ResultCode()
+ r = p.deserialize(buf[4:])
+
+ if r != -1:
+
+ self.addParam(p)
+ if buf[1] == 2:
+
+ p = SAPParam_ATR()
+ r = p.deserialize(buf[4+r:])
+ if r != -1:
+ self.addParam(p)
+
+ return self._validate()
+
+ return False
+
+class SAPMessage_POWER_SIM_OFF_REQ(SAPMessage):
+ def __init__(self):
+ SAPMessage.__init__(self,"POWER_SIM_OFF_REQ", SAPMessage.POWER_SIM_OFF_REQ)
+
+class SAPMessage_POWER_SIM_OFF_RESP(SAPMessage):
+ def __init__(self, ResultCode = None):
+ SAPMessage.__init__(self,"POWER_SIM_OFF_RESP", SAPMessage.POWER_SIM_OFF_RESP)
+ if ResultCode is not None:
+ self.addParam(SAPParam_ResultCode(ResultCode))
+
+ def _validate(self):
+ if len(self.params) == 1:
+ if self.params[0].getID() == SAPParam.ResultCode:
+ return True
+ return False
+
+ def deserialize(self, buf):
+ self.buf = buf
+ self.params[:] = []
+ if SAPMessage._basicCheck(self, buf):
+ p = SAPParam_ResultCode()
+ if p.deserialize(buf[4:]) == len(buf[4:]):
+ self.addParam(p)
+ return self._validate()
+
+ return False
+
+class SAPMessage_POWER_SIM_ON_REQ(SAPMessage):
+ def __init__(self):
+ SAPMessage.__init__(self,"POWER_SIM_ON_REQ", SAPMessage.POWER_SIM_ON_REQ)
+
+class SAPMessage_POWER_SIM_ON_RESP(SAPMessage_POWER_SIM_OFF_RESP):
+ def __init__(self, ResultCode = None):
+ SAPMessage.__init__(self,"POWER_SIM_ON_RESP", SAPMessage.POWER_SIM_ON_RESP)
+ if ResultCode is not None:
+ self.addParam(SAPParam_ResultCode(ResultCode))
+
+class SAPMessage_RESET_SIM_REQ(SAPMessage):
+ def __init__(self):
+ SAPMessage.__init__(self,"RESET_SIM_REQ", SAPMessage.RESET_SIM_REQ)
+
+class SAPMessage_RESET_SIM_RESP(SAPMessage_POWER_SIM_OFF_RESP):
+ def __init__(self, ResultCode = None):
+ SAPMessage.__init__(self,"RESET_SIM_RESP", SAPMessage.RESET_SIM_RESP)
+ if ResultCode is not None:
+ self.addParam(SAPParam_ResultCode(ResultCode))
+
+class SAPMessage_STATUS_IND(SAPMessage):
+ def __init__(self, StatusChange = None):
+ SAPMessage.__init__(self,"STATUS_IND", SAPMessage.STATUS_IND)
+ if StatusChange is not None:
+ self.addParam(SAPParam_StatusChange(StatusChange))
+
+ def _validate(self):
+ if len(self.params) == 1:
+ if self.params[0].getID() == SAPParam.StatusChange:
+ return True
+ return False
+
+ def deserialize(self, buf):
+ self.buf = buf
+ self.params[:] = []
+ if SAPMessage._basicCheck(self, buf):
+ p = SAPParam_StatusChange()
+ if p.deserialize(buf[4:]) == len(buf[4:]):
+ self.addParam(p)
+ return self._validate()
+
+ return False
+
+class SAPMessage_TRANSFER_CARD_READER_STATUS_REQ(SAPMessage):
+ def __init__(self):
+ SAPMessage.__init__(self,"TRANSFER_CARD_READER_STATUS_REQ", SAPMessage.TRANSFER_CARD_READER_STATUS_REQ)
+
+class SAPMessage_TRANSFER_CARD_READER_STATUS_RESP(SAPMessage):
+ def __init__(self, ResultCode = None, Status = None):
+ SAPMessage.__init__(self,"TRANSFER_CARD_READER_STATUS_RESP", SAPMessage.TRANSFER_CARD_READER_STATUS_RESP)
+ if ResultCode is not None:
+ self.addParam(SAPParam_ResultCode(ResultCode))
+ if Status is not None:
+ self.addParam(SAPParam_CardReaderStatus(Status))
+
+ def _validate(self):
+ if len(self.params) > 0:
+ if self.params[0] .getID() == SAPParam.ResultCode:
+ if self.params[0].getValue() == 0x00:
+ if len(self.params) == 2:
+ return True
+ else:
+ if len(self.params) == 1:
+ return True
+ return False
+
+ def deserialize(self, buf):
+ self.buf = buf
+ self.params[:] = []
+
+ if SAPMessage._basicCheck(self, buf):
+ p = SAPParam_ResultCode()
+ r = p.deserialize(buf[4:])
+ if r != -1:
+ self.addParam(p)
+ if buf[1] == 2:
+ p = SAPParam_CardReaderStatus()
+ r = p.deserialize(buf[4+r:])
+ if r != -1:
+ self.addParam(p)
+
+ return self._validate()
+
+ return False
+
+class SAPMessage_ERROR_RESP(SAPMessage):
+ def __init__(self):
+ SAPMessage.__init__(self,"ERROR_RESP", SAPMessage.ERROR_RESP)
+
+
+class SAPMessage_SET_TRANSPORT_PROTOCOL_REQ(SAPMessage):
+ def __init__(self, protocol = None):
+ SAPMessage.__init__(self,"SET_TRANSPORT_PROTOCOL_REQ", SAPMessage.SET_TRANSPORT_PROTOCOL_REQ)
+ if protocol is not None:
+ self.addParam(SAPParam_TransportProtocol(protocol))
+
+ def _validate(self):
+ if len(self.params) == 1:
+ if self.params[0].getID() == SAPParam.TransportProtocol:
+ return True
+ return False
+
+ def deserialize(self, buf):
+ self.buf = buf
+ self.params[:] = []
+ if SAPMessage._basicCheck(self, buf):
+ p = SAPParam_TransportProtocol()
+ if p.deserialize(buf[4:]) == len(buf[4:]):
+ self.addParam(p)
+ return self._validate()
+
+ return False
+
+class SAPMessage_SET_TRANSPORT_PROTOCOL_RESP(SAPMessage_POWER_SIM_OFF_RESP):
+ def __init__(self, ResultCode = None):
+ SAPMessage.__init__(self,"SET_TRANSPORT_PROTOCOL_RESP", SAPMessage.SET_TRANSPORT_PROTOCOL_RESP)
+ if ResultCode is not None:
+ self.addParam(SAPParam_ResultCode(ResultCode))
+
+
+class SAPClient:
+
+ CONNECTED = 1
+ DISCONNECTED = 0
+
+ uuid = "0000112D-0000-1000-8000-00805F9B34FB"
+ bufsize = 1024
+ timeout = 20
+ state = DISCONNECTED
+
+ def __init__(self, host = None, port = None):
+ self.sock = None
+
+ if host is None or is_valid_address(host):
+ self.host = host
+ else:
+ raise BluetoothError ("%s is not a valid BT address." % host)
+ self.host = None
+ return
+
+ if port is None:
+ self.__discover()
+ else:
+ self.port = port
+
+ self.__connectRFCOMM()
+
+ def __del__(self):
+ self.__disconnectRFCOMM()
+
+ def __disconnectRFCOMM(self):
+ if self.sock is not None:
+ self.sock.close()
+ self.state = self.DISCONNECTED
+
+ def __discover(self):
+ service_matches = find_service(self.uuid, self.host)
+
+ if len(service_matches) == 0:
+ raise BluetoothError ("No SAP service found")
+ return
+
+ first_match = service_matches[0]
+ self.port = first_match["port"]
+ self.host = first_match["host"]
+
+ print "SAP Service found on %s(%s)" % first_match["name"] % self.host
+
+ def __connectRFCOMM(self):
+ self.sock=BluetoothSocket( RFCOMM )
+ self.sock.connect((self.host, self.port))
+ self.sock.settimeout(self.timeout)
+ self.state = self.CONNECTED
+
+ def __sendMsg(self, msg):
+ if isinstance(msg, SAPMessage):
+ s = msg.serialize()
+ print "\tTX: " + msg.getContent()
+ return self.sock.send(s.tostring())
+
+ def __rcvMsg(self, msg):
+ if isinstance(msg, SAPMessage):
+ print "\tRX Wait: %s(id = 0x%.2x)" % (msg.name, msg.id)
+ data = self.sock.recv(self.bufsize)
+ if data:
+ if msg.deserialize(array('B',data)):
+ print "\tRX: len(%d) %s" % (len(data), msg.getContent())
+ return msg
+ else:
+ print "msg: %s" % array('B',data)
+ raise BluetoothError ("Message deserialization failed.")
+ else:
+ raise BluetoothError ("Timeout. No data received.")
+
+ def connect(self):
+ self.__connectRFCOMM()
+
+ def disconnect(self):
+ self.__disconnectRFCOMM()
+
+ def isConnected(self):
+ return self.state
+
+ def proc_connect(self):
+ try:
+ self.__sendMsg(SAPMessage_CONNECT_REQ(self.bufsize))
+ params = self.__rcvMsg(SAPMessage_CONNECT_RESP()).getParams()
+
+ if params[0].getValue() in (0x00, 0x04):
+ pass
+ elif params[0].getValue() == 0x02:
+ self.bufsize = params[1].getValue()
+
+ self.__sendMsg(SAPMessage_CONNECT_REQ(self.bufsize))
+ params = self.__rcvMsg(SAPMessage_CONNECT_RESP()).getParams()
+
+ if params[0].getValue() not in (0x00, 0x04):
+ return False
+ else:
+ return False
+
+ params = self.__rcvMsg(SAPMessage_STATUS_IND()).getParams()
+ if params[0].getValue() == 0x00:
+ return False
+ elif params[0].getValue() == 0x01:
+ """OK, Card reset"""
+ return self.proc_transferATR()
+ elif params[0].getValue() == 0x02:
+ """T0 not supported"""
+ if self.proc_transferATR():
+ return self.proc_setTransportProtocol(1)
+ else:
+ return False
+ else:
+ return False
+ except BluetoothError , e:
+ print "Error. " +str(e)
+ return False
+
+ def proc_disconnectByClient(self, timeout=0):
+ try:
+ self.__sendMsg(SAPMessage_DISCONNECT_REQ())
+ self.__rcvMsg(SAPMessage_DISCONNECT_RESP())
+ time.sleep(timeout) # let srv to close rfcomm
+ self.__disconnectRFCOMM()
+ return True
+ except BluetoothError , e:
+ print "Error. " +str(e)
+ return False
+
+ def proc_disconnectByServer(self, timeout=0):
+ try:
+ params = self.__rcvMsg(SAPMessage_DISCONNECT_IND()).getParams()
+
+ """gracefull"""
+ if params[0].getValue() == 0x00:
+ if not self.proc_transferAPDU():
+ return False
+
+ return self.proc_disconnectByClient(timeout)
+
+ except BluetoothError , e:
+ print "Error. " +str(e)
+ return False
+
+ def proc_transferAPDU(self, apdu = "Sample APDU command"):
+ try:
+ self.__sendMsg(SAPMessage_TRANSFER_APDU_REQ(apdu))
+ params = self.__rcvMsg(SAPMessage_TRANSFER_APDU_RESP()).getParams()
+ return True
+ except BluetoothError , e:
+ print "Error. " +str(e)
+ return False
+
+ def proc_transferATR(self):
+ try:
+ self.__sendMsg(SAPMessage_TRANSFER_ATR_REQ())
+ params = self.__rcvMsg(SAPMessage_TRANSFER_ATR_RESP()).getParams()
+ return True
+ except BluetoothError , e:
+ print "Error. " +str(e)
+ return False
+
+ def proc_powerSimOff(self):
+ try:
+ self.__sendMsg(SAPMessage_POWER_SIM_OFF_REQ())
+ params = self.__rcvMsg(SAPMessage_POWER_SIM_OFF_RESP()).getParams()
+ return True
+ except BluetoothError , e:
+ print "Error. " +str(e)
+ return False
+
+ def proc_powerSimOn(self):
+ try:
+ self.__sendMsg(SAPMessage_POWER_SIM_ON_REQ())
+ params = self.__rcvMsg(SAPMessage_POWER_SIM_ON_RESP()).getParams()
+ if params[0].getValue() == 0x00:
+ return self.proc_transferATR()
+
+ return True
+ except BluetoothError , e:
+ print "Error. " +str(e)
+ return False
+
+ def proc_resetSim(self):
+ try:
+ self.__sendMsg(SAPMessage_RESET_SIM_REQ())
+ params = self.__rcvMsg(SAPMessage_RESET_SIM_RESP()).getParams()
+ if params[0].getValue() == 0x00:
+ return self.proc_transferATR()
+
+ return True
+ except BluetoothError , e:
+ print "Error. " +str(e)
+ return False
+
+ def proc_reportStatus(self):
+ try:
+ params = self.__rcvMsg(SAPMessage_STATUS_IND()).getParams()
+ except BluetoothError , e:
+ print "Error. " +str(e)
+ return False
+
+ def proc_transferCardReaderStatus(self):
+ try:
+ self.__sendMsg(SAPMessage_TRANSFER_CARD_READER_STATUS_REQ())
+ params = self.__rcvMsg(SAPMessage_TRANSFER_CARD_READER_STATUS_RESP()).getParams()
+ except BluetoothError , e:
+ print "Error. " +str(e)
+ return False
+
+ def proc_errorResponse(self):
+ try:
+ """ send malformed message, no mandatory maxmsgsize parameter"""
+ self.__sendMsg(SAPMessage_CONNECT_REQ())
+
+ params = self.__rcvMsg(SAPMessage_ERROR_RESP()).getParams()
+ except BluetoothError , e:
+ print "Error. " +str(e)
+ return False
+
+ def proc_setTransportProtocol(self, protocol = 0):
+ try:
+ self.__sendMsg(SAPMessage_SET_TRANSPORT_PROTOCOL_REQ(protocol))
+ params = self.__rcvMsg(SAPMessage_SET_TRANSPORT_PROTOCOL_RESP()).getParams()
+
+ if params[0].getValue() == 0x00:
+ params = self.__rcvMsg(SAPMessage_STATUS_IND()).getParams()
+ if params[0].getValue() in (0x01, 0x02):
+ return self.proc_transferATR()
+ else:
+ return True
+ """return False ???"""
+ elif params[0].getValue == 0x07:
+ """not supported"""
+ return True
+ """return False ???"""
+ else:
+ return False
+
+ except BluetoothError , e:
+ print "Error. " +str(e)
+ return False
+
+if __name__ == "__main__":
+ pass
diff --git a/test/test-sap.py b/test/test-sap.py
new file mode 100755
index 0000000..393f785
--- /dev/null
+++ b/test/test-sap.py
@@ -0,0 +1,139 @@
+""" Copyright (C) 2011 Tieto """
+""" Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com> """
+
+from sap import *
+import time
+
+def connect_disconnect_by_client(sap):
+
+ print "[Test] Connect - Disconnect by client \n"
+
+ try:
+ if not sap.isConnected():
+ sap.connect()
+
+ if sap.proc_connect():
+ if sap.proc_disconnectByClient():
+ print "OK"
+ return 0
+
+ print "NOT OK"
+ return 1
+
+ except BluetoothError , e:
+ print "Error " + str(e)
+
+
+def connect_disconnect_by_server_gracefully(sap, timeout=0):
+
+ print "[Test] Connect - Disconnect by server with timer \n"
+
+ try:
+ if not sap.isConnected():
+ sap.connect()
+
+ if sap.proc_connect():
+ if sap.proc_disconnectByServer(timeout):
+ print "OK"
+ return 0
+
+ print "NOT OK"
+ return 1
+
+ except BluetoothError , e:
+ print "Error " + str(e)
+
+
+def connect_txAPDU_disconnect_by_client(sap):
+
+ print "[Test] Connect - TX APDU - Disconnect by client \n"
+
+ try:
+ if not sap.isConnected():
+ sap.connect()
+
+ if sap.proc_connect():
+ if not sap.proc_transferAPDU():
+ print "NOT OK 1"
+ return 1
+
+ if not sap.proc_transferAPDU():
+ print "NOT OK 2"
+ return 1
+
+ if not sap.proc_transferAPDU():
+ print "NOT OK 3"
+ return 1
+
+ if not sap.proc_transferAPDU():
+ print "NOT OK 4"
+ return 1
+
+ if sap.proc_disconnectByClient():
+ print "OK"
+ return 0
+
+ print "NOT OK"
+ return 1
+
+ except BluetoothError , e:
+ print "Error " + str(e)
+
+def connect_rfcomm_only_and_wait_for_close_by_server(sap):
+
+ print "[Test] Connect rfcomm only - Disconnect by server timeout \n"
+
+ if not sap.isConnected():
+ sap.connect()
+
+ time.sleep(40)
+ print "OK"
+
+def power_sim_off_on(sap):
+
+ print "[Test] Powe sim off \n"
+
+ try:
+ if not sap.isConnected():
+ sap.connect()
+
+ if sap.proc_connect():
+ if not sap.proc_resetSim():
+ print "NOT OK"
+ return 1
+
+ if not sap.proc_powerSimOff():
+ print "NOT OK"
+ return 1
+
+ if not sap.proc_powerSimOn():
+ print "NOT OK"
+ return 1
+
+ if sap.proc_disconnectByClient():
+ print "OK"
+ return 0
+
+ print "NOT OK"
+ return 1
+
+ except BluetoothError , e:
+ print "Error " + str(e)
+
+
+if __name__ == "__main__":
+
+ host = "00:15:83:38:BF:18"
+ port = 8
+
+ try:
+ s = SAPClient(host, port)
+ except BluetoothError , e:
+ print "Error " +str(e)
+
+# connect_disconnect_by_client(s)
+# connect_disconnect_by_server_gracefully(s)
+# connect_disconnect_by_server_gracefully(s, 40) # wait 40 sec for srv to close rfcomm sock
+# connect_rfcomm_only_and_wait_for_close_by_server(s)
+ connect_txAPDU_disconnect_by_client(s)
+ power_sim_off_on(s)
--
1.7.1
^ permalink raw reply related
* [PATCH v5 3/4] Sim Access Profile dummy driver
From: Waldemar Rymarkiewicz @ 2011-03-16 12:10 UTC (permalink / raw)
To: Johan Hedberg; +Cc: linux-bluetooth, Waldemar Rymarkiewicz
In-Reply-To: <1300277421-8053-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 | 269 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
4 files changed, 275 insertions(+), 14 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 7267200..2994bf9 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 d07418f..faa7f7c 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -205,6 +205,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}
@@ -226,6 +227,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 b433ba3..39e1fc9 100644
--- a/sap/sap-dummy.c
+++ b/sap/sap-dummy.c
@@ -2,6 +2,7 @@
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2010 ST-Ericsson SA
+ * Copyright (C) 2011 Tieto Poland
*
* Author: Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com>
* for ST-Ericsson
@@ -21,50 +22,185 @@
* 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,
@@ -73,13 +209,122 @@ void sap_set_transport_protocol_req(void *sap_device,
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 v5 2/4] Add support for SAP protocol
From: Waldemar Rymarkiewicz @ 2011-03-16 12:10 UTC (permalink / raw)
To: Johan Hedberg; +Cc: linux-bluetooth, Waldemar Rymarkiewicz
In-Reply-To: <1300277421-8053-1-git-send-email-waldemar.rymarkiewicz@tieto.com>
Add new protocol features:
* transfer APDu request/response
* get ATR request/response
* power sim of/on request/response
* card reader status
* set transport protocol
---
sap/server.c | 415 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 399 insertions(+), 16 deletions(-)
diff --git a/sap/server.c b/sap/server.c
index 8337fe1..35abffb 100644
--- a/sap/server.c
+++ b/sap/server.c
@@ -89,6 +89,44 @@ 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(uint8_t result,
+ struct sap_parameter *param)
+{
+ param->id = SAP_PARAM_ID_RESULT_CODE;
+ param->len = htons(SAP_PARAM_ID_RESULT_CODE_LEN);
+ *param->val = 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)
@@ -375,38 +413,159 @@ error_req:
static void transfer_apdu_req(struct sap_connection *conn,
struct sap_parameter *param)
{
- DBG("SAP_APDU_REQUEST");
+ 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 %d pr 0x%02x)", param,
+ conn->state, conn->processing_req);
+ sap_error_rsp(conn);
}
static void transfer_atr_req(struct sap_connection *conn)
{
- DBG("SAP_ATR_REQUEST");
+ 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 %d pr 0x%02x)", conn->state,
+ conn->processing_req);
+ sap_error_rsp(conn);
}
static void power_sim_off_req(struct sap_connection *conn)
{
- DBG("SAP_SIM_OFF_REQUEST");
+ 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 %d pr 0x%02x)", conn->state,
+ conn->processing_req);
+ sap_error_rsp(conn);
}
static void power_sim_on_req(struct sap_connection *conn)
{
- DBG("SAP_SIM_ON_REQUEST");
+ 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 %d pr 0x%02x)", conn->state,
+ conn->processing_req);
+ sap_error_rsp(conn);
}
static void reset_sim_req(struct sap_connection *conn)
{
- DBG("SAP_RESET_SIM_REQUEST");
+ 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 %d pr 0x%02x param)", conn->state,
+ conn->processing_req);
+ sap_error_rsp(conn);
}
static void transfer_card_reader_status_req(struct sap_connection *conn)
{
- DBG("SAP_TRANSFER_CARD_READER_STATUS_REQUEST");
+ 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 %d pr 0x%02x)", conn->state,
+ conn->processing_req);
+ sap_error_rsp(conn);
}
static void set_transport_protocol_req(struct sap_connection *conn,
struct sap_parameter *param)
{
- DBG("SAP_SET_TRANSPORT_PROTOCOL_REQUEST");
+ 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 %d pr 0x%02x)", param,
+ conn->state, conn->processing_req);
+ sap_error_rsp(conn);
}
static void start_guard_timer(struct sap_connection *conn, guint interval)
@@ -572,49 +731,273 @@ int sap_disconnect_rsp(void *sap_device)
int sap_transfer_apdu_rsp(void *sap_device, uint8_t result, uint8_t *apdu,
uint16_t length)
{
- return 0;
+ 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 -EINVAL;
+
+ DBG("state %d pr 0x%02x", 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, uint8_t result, uint8_t *atr,
uint16_t length)
{
- return 0;
+ 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 -EINVAL;
+
+ DBG("result 0x%02x state %d pr 0x%02x 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, uint8_t result)
{
- return 0;
+ 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 -EINVAL;
+
+ DBG("state %d pr 0x%02x", 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, uint8_t result)
{
- return 0;
+ 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 -EINVAL;
+
+ DBG("state %d pr 0x%02x", 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, uint8_t result)
{
- return 0;
+ 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 -EINVAL;
+
+ DBG("state %d pr 0x%02x result 0x%02x", 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, uint8_t result,
uint8_t status)
{
- return 0;
+ 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 -EINVAL;
+
+ DBG("state %d pr 0x%02x result 0x%02x", 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 = 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, uint8_t result)
{
- return 0;
+ 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 -EINVAL;
+
+ DBG("state %d pr 0x%02x result 0x%02x", 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)
{
- return 0;
+ 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, uint8_t status_change)
{
- return 0;
+ 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 -EINVAL;
+
+ DBG("state %d pr 0x%02x sc 0x%02x", 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 = 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)
--
1.7.1
^ permalink raw reply related
* [PATCH v5 1/4] Sim Access Profile connect/disconnect procedures
From: Waldemar Rymarkiewicz @ 2011-03-16 12:10 UTC (permalink / raw)
To: Johan Hedberg; +Cc: linux-bluetooth, Waldemar Rymarkiewicz
Add support for SAP protocol features:
* connect and disconnect requests
* connect and disconnect responses
* disconnect indication
* timeouts for the valid connection
---
sap/sap.h | 2 +-
sap/server.c | 433 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 424 insertions(+), 11 deletions(-)
diff --git a/sap/sap.h b/sap/sap.h
index bd0f06d..24240ca 100644
--- a/sap/sap.h
+++ b/sap/sap.h
@@ -143,7 +143,7 @@ enum sap_param_id {
#define SAP_PARAM_ID_DISCONNECT_IND_LEN 0x01
#define SAP_PARAM_ID_CARD_READER_STATUS_LEN 0x01
#define SAP_PARAM_ID_STATUS_CHANGE_LEN 0x01
-#define SAP_PARAM_ID_TRANSPORT_PROTOCOL_LEN 0x01
+#define SAP_PARAM_ID_TRANSPORT_PROTO_LEN 0x01
/* Transport Protocol - SAP v1.1 section 5.2.9 */
enum sap_transport_protocol {
diff --git a/sap/server.c b/sap/server.c
index 1c62a3e..8337fe1 100644
--- a/sap/server.c
+++ b/sap/server.c
@@ -50,14 +50,28 @@
#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 {
@@ -71,6 +85,72 @@ struct sap_server {
static DBusConnection *connection;
static struct sap_server *server;
+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 int check_msg(struct sap_message *msg)
+{
+ if (!msg)
+ return -EINVAL;
+
+ switch (msg->id) {
+ case SAP_CONNECT_REQ:
+ if (msg->nparam != 0x01)
+ return -EBADMSG;
+
+ if (msg->param->id != SAP_PARAM_ID_MAX_MSG_SIZE)
+ return -EBADMSG;
+
+ if (ntohs(msg->param->len) != SAP_PARAM_ID_MAX_MSG_SIZE_LEN)
+ return -EBADMSG;
+
+ break;
+
+ case SAP_TRANSFER_APDU_REQ:
+ if (msg->nparam != 0x01)
+ return -EBADMSG;
+
+ if (msg->param->id != SAP_PARAM_ID_COMMAND_APDU)
+ if ( msg->param->id != SAP_PARAM_ID_COMMAND_APDU7816)
+ return -EBADMSG;
+
+ if (msg->param->len == 0x00)
+ return -EBADMSG;
+
+ break;
+
+ case SAP_SET_TRANSPORT_PROTOCOL_REQ:
+ if (msg->nparam != 0x01)
+ return -EBADMSG;
+
+ if (msg->param->id != SAP_PARAM_ID_TRANSPORT_PROTOCOL)
+ return -EBADMSG;
+
+ if (ntohs(msg->param->len) != SAP_PARAM_ID_TRANSPORT_PROTO_LEN)
+ return -EBADMSG;
+
+ if (*msg->param->val != SAP_TRANSPORT_PROTOCOL_T0)
+ if (*msg->param->val != SAP_TRANSPORT_PROTOCOL_T1)
+ return -EBADMSG;
+
+ 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 -EBADMSG;
+
+ break;
+ }
+
+ return 0;
+}
+
static sdp_record_t *create_sap_record(uint8_t channel)
{
sdp_list_t *apseq, *aproto, *profiles, *proto[2], *root, *svclass_id;
@@ -126,16 +206,170 @@ static sdp_record_t *create_sap_record(uint8_t channel)
return record;
}
+static int send_message(struct sap_connection *conn, void *buf, size_t size)
+{
+ size_t written = 0;
+ GError *gerr = NULL;
+ GIOStatus gstatus;
+
+ if (!conn || !buf)
+ return -EINVAL;
+
+ DBG("size %zu", 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 (0x%02x).", gstatus);
+ return -EINVAL;
+ }
+
+ if (written != size)
+ error("write error.(written %zu size %zu)", written, size);
+
+ return 0;
+}
+
+static int disconnect_ind(void *sap_device, uint8_t disc_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 -EINVAL;
+
+ DBG("data %p state %d disc_type 0x%02x", conn, conn->state, disc_type);
+
+ if (conn->state != SAP_STATE_GRACEFUL_DISCONNECT &&
+ conn->state != SAP_STATE_IMMEDIATE_DISCONNECT) {
+ error("Processing error (state %d pr 0x%02x)", 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 = disc_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)
+ struct sap_parameter *param)
{
- DBG("SAP_CONNECT_REQUEST");
+ 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 *) ¶m->val;
+ maxmsgsize = ntohs(*val);
+
+ DBG("Connect MaxMsgSize: 0x%04x", 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 %d pr 0x%02x)", param,
+ conn->state, conn->processing_req);
+ sap_error_rsp(conn);
}
static int disconnect_req(struct sap_connection *conn, uint8_t disc_type)
{
- DBG("SAP_DISCONNECT_REQUEST");
- return 0;
+ DBG("conn %p state %d disc_type 0x%02x", conn, conn->state, disc_type);
+
+ switch (disc_type) {
+ case SAP_DISCONNECTION_TYPE_GRACEFUL:
+ if (conn->state == SAP_STATE_DISCONNECTED)
+ goto error_req;
+
+ if (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);
+ /* Timer will disconnect if client won't do.*/
+ start_guard_timer(conn, SAP_TIMER_GRACEFUL_DISCONNECT);
+ }
+
+ return 0;
+
+ case SAP_DISCONNECTION_TYPE_IMMEDIATE:
+ if (conn->state == SAP_STATE_DISCONNECTED)
+ goto error_req;
+
+ if (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;
+
+ 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 (0x%02x).", disc_type);
+ return -EINVAL;
+ }
+
+error_rsp:
+ sap_error_rsp(conn);
+error_req:
+ error("Processing error (state %d pr 0x%02x)", conn->state,
+ conn->processing_req);
+ return -EPERM;
}
static void transfer_apdu_req(struct sap_connection *conn,
@@ -175,13 +409,163 @@ static void set_transport_protocol_req(struct sap_connection *conn,
DBG("SAP_SET_TRANSPORT_PROTOCOL_REQUEST");
}
+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 %d pr 0x%02x", 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 (%d).", conn->state);
+ break;
+ }
+
+ return FALSE;
+}
+
int sap_connect_rsp(void *sap_device, uint8_t status, uint16_t maxmsgsize)
{
- return 0;
+ 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 -EINVAL;
+
+ DBG("state %d pr 0x%02x status 0x%02x", 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 = 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 *) ¶m->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 -EINVAL;
+
+ DBG("state %d pr 0x%02x", 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;
}
@@ -242,11 +626,14 @@ static int handle_cmd(void *data, void *buf, size_t size)
return -EINVAL;
if (size < sizeof(struct sap_message))
- return -EINVAL;
+ goto error_rsp;
if (msg->nparam != 0 && size < (sizeof(struct sap_message) +
sizeof(struct sap_parameter) + 4))
- return -EBADMSG;
+ goto error_rsp;
+
+ if (check_msg(msg) < 0)
+ goto error_rsp;
switch (msg->id) {
case SAP_CONNECT_REQ:
@@ -278,10 +665,13 @@ static int handle_cmd(void *data, void *buf, size_t size)
return 0;
default:
DBG("SAP unknown message.");
- return -ENOMSG;
+ break;
}
- return -1;
+error_rsp:
+ DBG("Bad request message format.");
+ sap_error_rsp(conn);
+ return -EBADMSG;
}
static void sap_conn_remove(struct sap_connection *conn)
@@ -347,6 +737,20 @@ static void sap_io_destroy(void *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);
}
@@ -361,6 +765,10 @@ static void sap_connect_cb(GIOChannel *io, GError *gerr, gpointer 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);
@@ -468,6 +876,10 @@ static DBusMessage *disconnect(DBusConnection *conn, DBusMessage *msg,
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);
}
@@ -494,7 +906,8 @@ static DBusMessage *get_properties(DBusConnection *c,
DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
- connected = (conn->state == SAP_STATE_CONNECTED);
+ 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);
--
1.7.1
^ permalink raw reply related
* [PATCH] Add 'Protocol not supported' error in a2dp_add_sep
From: Dmitriy Paliy @ 2011-03-16 12:01 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Dmitriy Paliy
'Protocol not supported' error code is added to registeration of A2DP
end-points. Error response org.bluez.Error.NotSupported instead of
org.bluez.Error.InvalidArguments is used when SEP registration fails
due to disabled corresponding interface in audio.conf.
---
audio/a2dp.c | 34 ++++++++++++++++++++++++++--------
audio/a2dp.h | 2 +-
audio/media.c | 23 +++++++++++++++++------
3 files changed, 44 insertions(+), 15 deletions(-)
diff --git a/audio/a2dp.c b/audio/a2dp.c
index 3407d6f..8c3698a 100644
--- a/audio/a2dp.c
+++ b/audio/a2dp.c
@@ -1486,22 +1486,23 @@ proceed:
if (source) {
for (i = 0; i < sbc_srcs; i++)
a2dp_add_sep(src, AVDTP_SEP_TYPE_SOURCE,
- A2DP_CODEC_SBC, delay_reporting, NULL);
+ A2DP_CODEC_SBC, delay_reporting, NULL, NULL);
for (i = 0; i < mpeg12_srcs; i++)
a2dp_add_sep(src, AVDTP_SEP_TYPE_SOURCE,
- A2DP_CODEC_MPEG12, delay_reporting, NULL);
+ A2DP_CODEC_MPEG12, delay_reporting,
+ NULL, NULL);
}
server->sink_enabled = sink;
if (sink) {
for (i = 0; i < sbc_sinks; i++)
a2dp_add_sep(src, AVDTP_SEP_TYPE_SINK,
- A2DP_CODEC_SBC, delay_reporting, NULL);
+ A2DP_CODEC_SBC, delay_reporting, NULL, NULL);
for (i = 0; i < mpeg12_sinks; i++)
a2dp_add_sep(src, AVDTP_SEP_TYPE_SINK,
A2DP_CODEC_MPEG12, delay_reporting,
- NULL);
+ NULL, NULL);
}
return 0;
@@ -1541,7 +1542,7 @@ void a2dp_unregister(const bdaddr_t *src)
struct a2dp_sep *a2dp_add_sep(const bdaddr_t *src, uint8_t type,
uint8_t codec, gboolean delay_reporting,
- struct media_endpoint *endpoint)
+ struct media_endpoint *endpoint, int *err)
{
struct a2dp_server *server;
struct a2dp_sep *sep;
@@ -1551,14 +1552,23 @@ struct a2dp_sep *a2dp_add_sep(const bdaddr_t *src, uint8_t type,
struct avdtp_sep_ind *ind;
server = find_server(servers, src);
- if (server == NULL)
+ if (server == NULL) {
+ if (err)
+ *err = -EINVAL;
return NULL;
+ }
- if (type == AVDTP_SEP_TYPE_SINK && !server->sink_enabled)
+ if (type == AVDTP_SEP_TYPE_SINK && !server->sink_enabled) {
+ if (err)
+ *err = -EPROTONOSUPPORT;
return NULL;
+ }
- if (type == AVDTP_SEP_TYPE_SOURCE && !server->source_enabled)
+ if (type == AVDTP_SEP_TYPE_SOURCE && !server->source_enabled) {
+ if (err)
+ *err = -EPROTONOSUPPORT;
return NULL;
+ }
sep = g_new0(struct a2dp_sep, 1);
@@ -1575,6 +1585,8 @@ proceed:
delay_reporting, ind, &cfm, sep);
if (sep->lsep == NULL) {
g_free(sep);
+ if (err)
+ *err = -EINVAL;
return NULL;
}
@@ -1600,6 +1612,8 @@ proceed:
error("Unable to allocate new service record");
avdtp_unregister_sep(sep->lsep);
g_free(sep);
+ if (err)
+ *err = -EINVAL;
return NULL;
}
@@ -1608,6 +1622,8 @@ proceed:
sdp_record_free(record);
avdtp_unregister_sep(sep->lsep);
g_free(sep);
+ if (err)
+ *err = -EINVAL;
return NULL;
}
*record_id = record->handle;
@@ -1615,6 +1631,8 @@ proceed:
add:
*l = g_slist_append(*l, sep);
+ if (err)
+ *err = 0;
return sep;
}
diff --git a/audio/a2dp.h b/audio/a2dp.h
index 21fccaa..5c4232d 100644
--- a/audio/a2dp.h
+++ b/audio/a2dp.h
@@ -138,7 +138,7 @@ void a2dp_unregister(const bdaddr_t *src);
struct a2dp_sep *a2dp_add_sep(const bdaddr_t *src, uint8_t type,
uint8_t codec, gboolean delay_reporting,
- struct media_endpoint *endpoint);
+ struct media_endpoint *endpoint, int *err);
void a2dp_remove_sep(struct a2dp_sep *sep);
struct a2dp_sep *a2dp_get(struct avdtp *session, struct avdtp_remote_sep *sep);
diff --git a/audio/media.c b/audio/media.c
index 9cfbe0e..d5fb29c 100644
--- a/audio/media.c
+++ b/audio/media.c
@@ -185,7 +185,8 @@ static struct media_endpoint *media_endpoint_create(struct media_adapter *adapte
gboolean delay_reporting,
uint8_t codec,
uint8_t *capabilities,
- int size)
+ int size,
+ int *err)
{
struct media_endpoint *endpoint;
@@ -206,13 +207,13 @@ static struct media_endpoint *media_endpoint_create(struct media_adapter *adapte
if (strcasecmp(uuid, A2DP_SOURCE_UUID) == 0) {
endpoint->sep = a2dp_add_sep(&adapter->src,
AVDTP_SEP_TYPE_SOURCE, codec,
- delay_reporting, endpoint);
+ delay_reporting, endpoint, err);
if (endpoint->sep == NULL)
goto failed;
} else if (strcasecmp(uuid, A2DP_SINK_UUID) == 0) {
endpoint->sep = a2dp_add_sep(&adapter->src,
AVDTP_SEP_TYPE_SINK, codec,
- delay_reporting, endpoint);
+ delay_reporting, endpoint, err);
if (endpoint->sep == NULL)
goto failed;
} else if (strcasecmp(uuid, HFP_AG_UUID) == 0 ||
@@ -227,8 +228,11 @@ static struct media_endpoint *media_endpoint_create(struct media_adapter *adapte
media_endpoint_set_configuration(endpoint, dev, NULL,
0, headset_setconf_cb,
dev);
- } else
+ } else {
+ if (err)
+ *err = -EINVAL;
goto failed;
+ }
endpoint->watch = g_dbus_add_disconnect_watch(adapter->conn, sender,
media_endpoint_exit, endpoint,
@@ -237,6 +241,8 @@ static struct media_endpoint *media_endpoint_create(struct media_adapter *adapte
adapter->endpoints = g_slist_append(adapter->endpoints, endpoint);
info("Endpoint registered: sender=%s path=%s", sender, path);
+ if (err)
+ *err = 0;
return endpoint;
failed:
@@ -335,6 +341,7 @@ static DBusMessage *register_endpoint(DBusConnection *conn, DBusMessage *msg,
uint8_t codec;
uint8_t *capabilities;
int size = 0;
+ int err;
sender = dbus_message_get_sender(msg);
@@ -355,8 +362,12 @@ static DBusMessage *register_endpoint(DBusConnection *conn, DBusMessage *msg,
return btd_error_invalid_args(msg);
if (media_endpoint_create(adapter, sender, path, uuid, delay_reporting,
- codec, capabilities, size) == FALSE)
- return btd_error_invalid_args(msg);
+ codec, capabilities, size, &err) == FALSE) {
+ if (err == -EPROTONOSUPPORT)
+ return btd_error_not_supported(msg);
+ else
+ return btd_error_invalid_args(msg);
+ }
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
}
--
1.7.1
^ permalink raw reply related
* [PATCH 5/5] Add Exchange MTU in interactive gatttool
From: Bruna Moreira @ 2011-03-16 11:25 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Bruna Moreira
In-Reply-To: <1300274712-3931-1-git-send-email-bruna.moreira@openbossa.org>
---
attrib/interactive.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 62 insertions(+), 0 deletions(-)
diff --git a/attrib/interactive.c b/attrib/interactive.c
index b32e9e7..38fc75a 100644
--- a/attrib/interactive.c
+++ b/attrib/interactive.c
@@ -362,6 +362,7 @@ static void cmd_disconnect(int argcp, char **argvp)
g_attrib_unref(attrib);
attrib = NULL;
+ opt_mtu = 0;
g_io_channel_shutdown(iochannel, FALSE, NULL);
g_io_channel_unref(iochannel);
@@ -642,6 +643,65 @@ static void cmd_sec_level(int argcp, char **argvp)
}
}
+static void exchange_mtu_cb(guint8 status, const guint8 *pdu, guint16 plen,
+ gpointer user_data)
+{
+ uint16_t mtu;
+
+ if (status != 0) {
+ printf("Exchange MTU Request failed: %s\n",
+ att_ecode2str(status));
+ return;
+ }
+
+ if (!dec_mtu_resp(pdu, plen, &mtu)) {
+ printf("Protocol error\n");
+ return;
+ }
+
+ mtu = MIN(mtu, opt_mtu);
+ /* Set new value for MTU in client */
+ if (g_attrib_set_buffer(attrib, mtu))
+ printf("MTU was exchanged successfully: %d\n", mtu);
+ else
+ printf("Error exchanging MTU\n");
+}
+
+static void cmd_mtu(int argcp, char **argvp)
+{
+ if (conn_state != STATE_CONNECTED) {
+ printf("Command failed: not connected.\n");
+ return;
+ }
+
+ if (opt_psm) {
+ printf("Command failed: operation is only available for LE"
+ " transport.\n");
+ return;
+ }
+
+ if (argcp < 2) {
+ printf("Usage: mtu <value>\n");
+ return;
+ }
+
+ if (opt_mtu) {
+ printf("Command failed: MTU exchange can only occur once per"
+ " connection.\n");
+ return;
+ }
+
+ errno = 0;
+ opt_mtu = strtoll(argvp[1], NULL, 0);
+ if (errno != 0 || opt_mtu < ATT_DEFAULT_LE_MTU) {
+ printf("Invalid value. Minimum MTU size is %d\n",
+ ATT_DEFAULT_LE_MTU);
+ return;
+ }
+
+ gatt_exchange_mtu(attrib, opt_mtu, exchange_mtu_cb, NULL);
+}
+
static struct {
const char *cmd;
void (*func)(int argcp, char **argvp);
@@ -672,6 +732,8 @@ static struct {
"Characteristic Value Write (No response)" },
{ "sec-level", cmd_sec_level, "[low | medium | high]",
"Set security level. Default: low" },
+ { "mtu", cmd_mtu, "<value>",
+ "Exchange MTU for GATT/ATT" },
{ NULL, NULL, NULL}
};
--
1.7.0.4
^ permalink raw reply related
* [PATCH 4/5] Add Exchange MTU operation in GATT library
From: Bruna Moreira @ 2011-03-16 11:25 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Bruna Moreira
In-Reply-To: <1300274712-3931-1-git-send-email-bruna.moreira@openbossa.org>
---
attrib/gatt.c | 13 +++++++++++++
attrib/gatt.h | 3 +++
2 files changed, 16 insertions(+), 0 deletions(-)
diff --git a/attrib/gatt.c b/attrib/gatt.c
index d3333fd..a9863e3 100644
--- a/attrib/gatt.c
+++ b/attrib/gatt.c
@@ -528,6 +528,19 @@ guint gatt_write_char(GAttrib *attrib, uint16_t handle, uint8_t *value,
user_data, NULL);
}
+guint gatt_exchange_mtu(GAttrib *attrib, uint16_t mtu, GAttribResultFunc func,
+ gpointer user_data)
+{
+ uint8_t *buf;
+ int buflen;
+ guint16 plen;
+
+ buf = g_attrib_get_buffer(attrib, &buflen);
+ plen = enc_mtu_req(mtu, buf, buflen);
+ return g_attrib_send(attrib, 0, ATT_OP_MTU_REQ, buf, plen, func,
+ user_data, NULL);
+}
+
guint gatt_find_info(GAttrib *attrib, uint16_t start, uint16_t end,
GAttribResultFunc func, gpointer user_data)
{
diff --git a/attrib/gatt.h b/attrib/gatt.h
index 730de7e..347c1a6 100644
--- a/attrib/gatt.h
+++ b/attrib/gatt.h
@@ -47,3 +47,6 @@ guint gatt_write_cmd(GAttrib *attrib, uint16_t handle, uint8_t *value, int vlen,
guint gatt_read_char_by_uuid(GAttrib *attrib, uint16_t start, uint16_t end,
bt_uuid_t *uuid, GAttribResultFunc func,
gpointer user_data);
+
+guint gatt_exchange_mtu(GAttrib *attrib, uint16_t mtu, GAttribResultFunc func,
+ gpointer user_data);
--
1.7.0.4
^ permalink raw reply related
* [PATCH 3/5] Use GAttrib buffer for ATT protocol PDUs
From: Bruna Moreira @ 2011-03-16 11:25 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Bruna Moreira
In-Reply-To: <1300274712-3931-1-git-send-email-bruna.moreira@openbossa.org>
Prior to this commit, there were local buffers inside GATT functions.
Now, a single buffer is used, to make sure the MTU limit is respected.
---
attrib/gatt.c | 109 +++++++++++++++++++++++++++++++++-----------------------
1 files changed, 64 insertions(+), 45 deletions(-)
diff --git a/attrib/gatt.c b/attrib/gatt.c
index 32bd4a0..d3333fd 100644
--- a/attrib/gatt.c
+++ b/attrib/gatt.c
@@ -108,9 +108,9 @@ static void primary_by_uuid_cb(guint8 status, const guint8 *ipdu,
struct discover_primary *dp = user_data;
GSList *ranges, *last;
struct att_range *range;
- uint8_t opdu[ATT_DEFAULT_LE_MTU];
+ uint8_t *buf;
guint16 oplen;
- int err = 0;
+ int err = 0, buflen;
if (status) {
err = status == ATT_ECODE_ATTR_NOT_FOUND ? 0 : status;
@@ -129,13 +129,14 @@ static void primary_by_uuid_cb(guint8 status, const guint8 *ipdu,
if (range->end == 0xffff)
goto done;
+ buf = g_attrib_get_buffer(dp->attrib, &buflen);
oplen = encode_discover_primary(range->end + 1, 0xffff, &dp->uuid,
- opdu, sizeof(opdu));
+ buf, buflen);
if (oplen == 0)
goto done;
- g_attrib_send(dp->attrib, 0, opdu[0], opdu, oplen, primary_by_uuid_cb,
+ g_attrib_send(dp->attrib, 0, buf[0], buf, oplen, primary_by_uuid_cb,
dp, NULL);
return;
@@ -196,12 +197,13 @@ static void primary_all_cb(guint8 status, const guint8 *ipdu, guint16 iplen,
err = 0;
if (end != 0xffff) {
- uint8_t opdu[ATT_DEFAULT_LE_MTU];
+ int buflen;
+ uint8_t *buf = g_attrib_get_buffer(dp->attrib, &buflen);
guint16 oplen = encode_discover_primary(end + 1, 0xffff, NULL,
- opdu, sizeof(opdu));
+ buf, buflen);
- g_attrib_send(dp->attrib, 0, opdu[0], opdu, oplen,
- primary_all_cb, dp, NULL);
+ g_attrib_send(dp->attrib, 0, buf[0], buf, oplen, primary_all_cb,
+ dp, NULL);
return;
}
@@ -215,11 +217,12 @@ guint gatt_discover_primary(GAttrib *attrib, bt_uuid_t *uuid, gatt_cb_t func,
gpointer user_data)
{
struct discover_primary *dp;
- uint8_t pdu[ATT_DEFAULT_LE_MTU];
+ int buflen;
+ uint8_t *buf = g_attrib_get_buffer(attrib, &buflen);
GAttribResultFunc cb;
guint16 plen;
- plen = encode_discover_primary(0x0001, 0xffff, uuid, pdu, sizeof(pdu));
+ plen = encode_discover_primary(0x0001, 0xffff, uuid, buf, buflen);
if (plen == 0)
return 0;
@@ -237,7 +240,7 @@ guint gatt_discover_primary(GAttrib *attrib, bt_uuid_t *uuid, gatt_cb_t func,
} else
cb = primary_all_cb;
- return g_attrib_send(attrib, 0, pdu[0], pdu, plen, cb, dp, NULL);
+ return g_attrib_send(attrib, 0, buf[0], buf, plen, cb, dp, NULL);
}
static void char_discovered_cb(guint8 status, const guint8 *ipdu, guint16 iplen,
@@ -246,7 +249,8 @@ static void char_discovered_cb(guint8 status, const guint8 *ipdu, guint16 iplen,
struct discover_char *dc = user_data;
struct att_data_list *list;
unsigned int i, err;
- uint8_t opdu[ATT_DEFAULT_LE_MTU];
+ int buflen;
+ uint8_t *buf;
guint16 oplen;
bt_uuid_t uuid;
uint16_t last = 0;
@@ -293,15 +297,17 @@ static void char_discovered_cb(guint8 status, const guint8 *ipdu, guint16 iplen,
err = 0;
if (last != 0) {
+ buf = g_attrib_get_buffer(dc->attrib, &buflen);
+
bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
- oplen = enc_read_by_type_req(last + 1, dc->end, &uuid, opdu,
- sizeof(opdu));
+ oplen = enc_read_by_type_req(last + 1, dc->end, &uuid, buf,
+ buflen);
if (oplen == 0)
return;
- g_attrib_send(dc->attrib, 0, opdu[0], opdu, oplen,
+ g_attrib_send(dc->attrib, 0, buf[0], buf, oplen,
char_discovered_cb, dc, NULL);
return;
@@ -315,14 +321,15 @@ done:
guint gatt_discover_char(GAttrib *attrib, uint16_t start, uint16_t end,
gatt_cb_t func, gpointer user_data)
{
- uint8_t pdu[ATT_DEFAULT_LE_MTU];
+ int buflen;
+ uint8_t *buf = g_attrib_get_buffer(attrib, &buflen);
struct discover_char *dc;
guint16 plen;
bt_uuid_t uuid;
bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
- plen = enc_read_by_type_req(start, end, &uuid, pdu, sizeof(pdu));
+ plen = enc_read_by_type_req(start, end, &uuid, buf, buflen);
if (plen == 0)
return 0;
@@ -335,7 +342,7 @@ guint gatt_discover_char(GAttrib *attrib, uint16_t start, uint16_t end,
dc->user_data = user_data;
dc->end = end;
- return g_attrib_send(attrib, 0, pdu[0], pdu, plen, char_discovered_cb,
+ return g_attrib_send(attrib, 0, buf[0], buf, plen, char_discovered_cb,
dc, NULL);
}
@@ -343,15 +350,16 @@ guint gatt_read_char_by_uuid(GAttrib *attrib, uint16_t start, uint16_t end,
bt_uuid_t *uuid, GAttribResultFunc func,
gpointer user_data)
{
- uint8_t pdu[ATT_DEFAULT_LE_MTU];
+ int buflen;
+ uint8_t *buf = g_attrib_get_buffer(attrib, &buflen);
guint16 plen;
- plen = enc_read_by_type_req(start, end, uuid, pdu, sizeof(pdu));
+ plen = enc_read_by_type_req(start, end, uuid, buf, buflen);
if (plen == 0)
return 0;
return g_attrib_send(attrib, 0, ATT_OP_READ_BY_TYPE_REQ,
- pdu, plen, func, user_data, NULL);
+ buf, plen, func, user_data, NULL);
}
struct read_long_data {
@@ -382,7 +390,8 @@ static void read_blob_helper(guint8 status, const guint8 *rpdu, guint16 rlen,
gpointer user_data)
{
struct read_long_data *long_read = user_data;
- uint8_t pdu[ATT_DEFAULT_LE_MTU];
+ uint8_t *buf;
+ int buflen;
guint8 *tmp;
guint16 plen;
guint id;
@@ -403,13 +412,14 @@ static void read_blob_helper(guint8 status, const guint8 *rpdu, guint16 rlen,
long_read->buffer = tmp;
long_read->size += rlen - 1;
- if (rlen < ATT_DEFAULT_LE_MTU)
+ buf = g_attrib_get_buffer(long_read->attrib, &buflen);
+ if (rlen < buflen)
goto done;
plen = enc_read_blob_req(long_read->handle, long_read->size - 1,
- pdu, sizeof(pdu));
+ buf, buflen);
id = g_attrib_send(long_read->attrib, long_read->id,
- ATT_OP_READ_BLOB_REQ, pdu, plen,
+ ATT_OP_READ_BLOB_REQ, buf, plen,
read_blob_helper, long_read, read_long_destroy);
if (id != 0) {
@@ -428,11 +438,12 @@ static void read_char_helper(guint8 status, const guint8 *rpdu,
guint16 rlen, gpointer user_data)
{
struct read_long_data *long_read = user_data;
- uint8_t pdu[ATT_DEFAULT_LE_MTU];
+ int buflen;
+ uint8_t *buf = g_attrib_get_buffer(long_read->attrib, &buflen);
guint16 plen;
guint id;
- if (status != 0 || rlen < ATT_DEFAULT_LE_MTU)
+ if (status != 0 || rlen < buflen)
goto done;
long_read->buffer = g_malloc(rlen);
@@ -443,9 +454,9 @@ static void read_char_helper(guint8 status, const guint8 *rpdu,
memcpy(long_read->buffer, rpdu, rlen);
long_read->size = rlen;
- plen = enc_read_blob_req(long_read->handle, rlen - 1, pdu, sizeof(pdu));
+ plen = enc_read_blob_req(long_read->handle, rlen - 1, buf, buflen);
id = g_attrib_send(long_read->attrib, long_read->id,
- ATT_OP_READ_BLOB_REQ, pdu, plen, read_blob_helper,
+ ATT_OP_READ_BLOB_REQ, buf, plen, read_blob_helper,
long_read, read_long_destroy);
if (id != 0) {
@@ -462,7 +473,8 @@ done:
guint gatt_read_char(GAttrib *attrib, uint16_t handle, uint16_t offset,
GAttribResultFunc func, gpointer user_data)
{
- uint8_t pdu[ATT_DEFAULT_LE_MTU];
+ uint8_t *buf;
+ int buflen;
guint16 plen;
guint id;
struct read_long_data *long_read;
@@ -477,14 +489,15 @@ guint gatt_read_char(GAttrib *attrib, uint16_t handle, uint16_t offset,
long_read->user_data = user_data;
long_read->handle = handle;
+ buf = g_attrib_get_buffer(attrib, &buflen);
if (offset > 0) {
- plen = enc_read_blob_req(long_read->handle, offset, pdu,
- sizeof(pdu));
- id = g_attrib_send(attrib, 0, ATT_OP_READ_BLOB_REQ, pdu, plen,
+ plen = enc_read_blob_req(long_read->handle, offset, buf,
+ buflen);
+ id = g_attrib_send(attrib, 0, ATT_OP_READ_BLOB_REQ, buf, plen,
read_blob_helper, long_read, read_long_destroy);
} else {
- plen = enc_read_req(handle, pdu, sizeof(pdu));
- id = g_attrib_send(attrib, 0, ATT_OP_READ_REQ, pdu, plen,
+ plen = enc_read_req(handle, buf, buflen);
+ id = g_attrib_send(attrib, 0, ATT_OP_READ_REQ, buf, plen,
read_char_helper, long_read, read_long_destroy);
}
@@ -501,39 +514,45 @@ guint gatt_read_char(GAttrib *attrib, uint16_t handle, uint16_t offset,
guint gatt_write_char(GAttrib *attrib, uint16_t handle, uint8_t *value,
int vlen, GAttribResultFunc func, gpointer user_data)
{
- uint8_t pdu[ATT_DEFAULT_LE_MTU];
+ uint8_t *buf;
+ int buflen;
guint16 plen;
+ buf = g_attrib_get_buffer(attrib, &buflen);
if (func)
- plen = enc_write_req(handle, value, vlen, pdu, sizeof(pdu));
+ plen = enc_write_req(handle, value, vlen, buf, buflen);
else
- plen = enc_write_cmd(handle, value, vlen, pdu, sizeof(pdu));
+ plen = enc_write_cmd(handle, value, vlen, buf, buflen);
- return g_attrib_send(attrib, 0, pdu[0], pdu, plen, func,
+ return g_attrib_send(attrib, 0, buf[0], buf, plen, func,
user_data, NULL);
}
guint gatt_find_info(GAttrib *attrib, uint16_t start, uint16_t end,
GAttribResultFunc func, gpointer user_data)
{
- uint8_t pdu[ATT_DEFAULT_LE_MTU];
+ uint8_t *buf;
+ int buflen;
guint16 plen;
- plen = enc_find_info_req(start, end, pdu, sizeof(pdu));
+ buf = g_attrib_get_buffer(attrib, &buflen);
+ plen = enc_find_info_req(start, end, buf, buflen);
if (plen == 0)
return 0;
- return g_attrib_send(attrib, 0, ATT_OP_FIND_INFO_REQ, pdu, plen, func,
+ return g_attrib_send(attrib, 0, ATT_OP_FIND_INFO_REQ, buf, plen, func,
user_data, NULL);
}
guint gatt_write_cmd(GAttrib *attrib, uint16_t handle, uint8_t *value, int vlen,
GDestroyNotify notify, gpointer user_data)
{
- uint8_t pdu[ATT_DEFAULT_LE_MTU];
+ uint8_t *buf;
+ int buflen;
guint16 plen;
- plen = enc_write_cmd(handle, value, vlen, pdu, sizeof(pdu));
- return g_attrib_send(attrib, 0, ATT_OP_WRITE_CMD, pdu, plen, NULL,
+ buf = g_attrib_get_buffer(attrib, &buflen);
+ plen = enc_write_cmd(handle, value, vlen, buf, buflen);
+ return g_attrib_send(attrib, 0, ATT_OP_WRITE_CMD, buf, plen, NULL,
user_data, notify);
}
--
1.7.0.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox