* Re: [PATCH] Fix problem with invalid read from array
From: Johan Hedberg @ 2010-10-06 13:32 UTC (permalink / raw)
To: Lukasz Pawlik; +Cc: linux-bluetooth
In-Reply-To: <1286369566-1453-1-git-send-email-lucas.pawlik@gmail.com>
Hi Lukasz,
On Wed, Oct 06, 2010, Lukasz Pawlik wrote:
> This patch fix problem with reading data from out of the array range in
> function used to create EIR response.
You'll need to explain in more detail exactly what was wrong with the
old code and how your patch fixes it (and why it is the correct fix).
> - uint8_t data[240];
> + uint8_t data[242];
Why 242? The core spec defines the EIR data as a 240 byte field.
> - uuid128_data[SIZEOF_UUID128 - k])
> + uuid128_data[SIZEOF_UUID128 - 1 - k])
This change looks fine (the index of the last byte is sizeof(uuid128) - 1).
Johan
^ permalink raw reply
* RE: Sim Access profile server implementation
From: Waldemar.Rymarkiewicz @ 2010-10-06 13:22 UTC (permalink / raw)
To: suraj
Cc: Suraj.Sumangala, marcel, linux-bluetooth, Jothikumar.Mothilal,
joakim.xj.ceder, arunkr.singh
In-Reply-To: <4CAC6E61.20708@Atheros.com>
Hi Suraj,
=20
>
>So basically your implementation does not use d-bus for basic=20
>SAP operations and the SIM access driver is compiled as part=20
>of bluetoothd right?
>
>>
>>> Correct me if my understanding is wrong.
>>>
Exactly.
Regards,
/Waldek
^ permalink raw reply
* [PATCH] Fix problem with invalid read from array
From: Lukasz Pawlik @ 2010-10-06 12:52 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Lukasz Pawlik
This patch fix problem with reading data from out of the array range in
function used to create EIR response.
---
src/adapter.c | 2 +-
src/sdpd-service.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/adapter.c b/src/adapter.c
index 73ea6e4..bf32e19 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -205,7 +205,7 @@ static void dev_info_free(struct remote_dev_info *dev)
static void update_ext_inquiry_response(struct btd_adapter *adapter)
{
- uint8_t data[240];
+ uint8_t data[242];
struct hci_dev *dev = &adapter->dev;
int ret;
diff --git a/src/sdpd-service.c b/src/sdpd-service.c
index 26ab9a5..67dd9af 100644
--- a/src/sdpd-service.c
+++ b/src/sdpd-service.c
@@ -204,7 +204,7 @@ static void eir_generate_uuid128(sdp_list_t *list,
for (i = 0; i < index; i++) {
for (k = 0; k < SIZEOF_UUID128; k++) {
if (uuid128[i * SIZEOF_UUID128 + k] !=
- uuid128_data[SIZEOF_UUID128 - k])
+ uuid128_data[SIZEOF_UUID128 - 1 - k])
break;
}
if (k == SIZEOF_UUID128)
--
1.7.0.4
^ permalink raw reply related
* Re: Sim Access profile server implementation
From: Suraj Sumangala @ 2010-10-06 12:41 UTC (permalink / raw)
To: Waldemar.Rymarkiewicz@tieto.com
Cc: Suraj Sumangala, marcel@holtmann.org,
linux-bluetooth@vger.kernel.org, Jothikumar Mothilal,
joakim.xj.ceder@stericsson.com, arunkr.singh@stericsson.com
In-Reply-To: <99B09243E1A5DA4898CDD8B700111448097D01B868@EXMB04.eu.tieto.com>
Hi Waldek,
On 10/6/2010 3:43 PM, Waldemar.Rymarkiewicz@tieto.com wrote:
> Hi suraj,
>
>> Which part of this is the driver and which is the agent here?
>
> sap-ste.c is a driver for u8500 platform. The agent is not involved in this design.
>
>> If I am not mistaken, you are sending the responses directly
>>from code here, how can we extend this to another
>> hardware/agent without source code change?
>
> You are right. You can add a new driver that implements interfaces in sap.h then configure with ./configure --enable-sap=yes --with-sap=DRIVER
> You don't have to modify the code, but you have to rebuild with your driver. Usually, there will be one driver per platform so it shoudl not be a problem.
>
>> I don't see D-bus being used other than for set/get property.
>
> We use D-bus only for enable/disable sap server. Data flow to sim is done over unix sockets (for u8500) as I have doubts to dbus reliability. However, it's good option to do tests with dbus oriented design as discussed before.
So basically your implementation does not use d-bus for basic SAP
operations and the SIM access driver is compiled as part of bluetoothd
right?
>
>> Correct me if my understanding is wrong.
>>
>
> Regards,
> /Waldek
Regards
Suraj
^ permalink raw reply
* Re: SCO Socket input.
From: Pepe Aracil @ 2010-10-06 11:53 UTC (permalink / raw)
To: Pepe Aracil, linux-bluetooth
In-Reply-To: <20101006095919.GA3066@jh-x301>
Hi.
I test DisablePlugins=audio with the same result :(.
SCO input connection only works in this order:
1 - application turns UP hci0 interface.
1 - application opens SCO socket for listen.
2 - application launch bluetoothd.
3 - application open rfcomm to AG profile on mobile phone.
(I can't open rfcomm connection without bluetoothd because pin
and key exchange issues)
If my application opens SCO socket for listen after the launch of
bluetoothd, SCO socket never gets an incoming connection.
Thanks.
2010/10/6 Johan Hedberg <johan.hedberg@gmail.com>:
> Hi,
>
> On Wed, Oct 06, 2010, Pepe Aracil wrote:
>> I have compiled bluez without audio support to avoid SCO socket be
>> blocked by bluetoothd. Without positive results.
>>
>> ¿Some idea?
>
> Just to be sure you could add DisablePlugins=audio to
> /etc/bluetooth/main.conf.
>
> Johan
>
^ permalink raw reply
* RE: Sim Access profile server implementation
From: Waldemar.Rymarkiewicz @ 2010-10-06 10:13 UTC (permalink / raw)
To: suraj
Cc: marcel, Suraj.Sumangala, linux-bluetooth, Jothikumar.Mothilal,
joakim.xj.ceder, arunkr.singh
In-Reply-To: <4A2A3D7B.60701@Atheros.com>
Hi suraj,=20
>Which part of this is the driver and which is the agent here?
sap-ste.c is a driver for u8500 platform. The agent is not involved in this=
design.
>If I am not mistaken, you are sending the responses directly=20
>from code here, how can we extend this to another=20
>hardware/agent without source code change?
You are right. You can add a new driver that implements interfaces in sap.h=
then configure with ./configure --enable-sap=3Dyes --with-sap=3DDRIVER
You don't have to modify the code, but you have to rebuild with your driver=
. Usually, there will be one driver per platform so it shoudl not be a prob=
lem.
>I don't see D-bus being used other than for set/get property.
We use D-bus only for enable/disable sap server. Data flow to sim is done o=
ver unix sockets (for u8500) as I have doubts to dbus reliability. However,=
it's good option to do tests with dbus oriented design as discussed before=
.
>Correct me if my understanding is wrong.
>
Regards,
/Waldek=
^ permalink raw reply
* Re: Sim Access profile server implementation
From: Suraj Sumangala @ 2010-10-06 10:00 UTC (permalink / raw)
To: Waldemar.Rymarkiewicz@tieto.com
Cc: marcel@holtmann.org, Suraj Sumangala,
linux-bluetooth@vger.kernel.org, Jothikumar Mothilal,
joakim.xj.ceder@stericsson.com, arunkr.singh@stericsson.com
In-Reply-To: <99B09243E1A5DA4898CDD8B700111448097D01B814@EXMB04.eu.tieto.com>
Hi Waldek,
On 10/6/2010 3:02 PM, Waldemar.Rymarkiewicz@tieto.com wrote:
>
> Hi Marcel,
>
>>>
>>> Can you share that code with us. And also hardware if you. We
>> are still
>>> having hard time to find proper hardware to test this on.
>>
>> Will send a patch soon. I use
>> http://www.stericsson.com/platforms/U8500.jsp hw, but need to
>> check if I can share one with you.
>>
>
> Here you are the patch. Just note that it is based on an old bluez 4.4x
> If you consider to accept the design I will update the patch upon the latest release.
>
> Will appreciate any comments.
>
> Thanks,
> /Waldek
Which part of this is the driver and which is the agent here?
If I am not mistaken, you are sending the responses directly from code
here, how can we extend this to another hardware/agent without source
code change?
I don't see D-bus being used other than for set/get property.
Correct me if my understanding is wrong.
Regards
Suraj
^ permalink raw reply
* Re: SCO Socket input.
From: Johan Hedberg @ 2010-10-06 9:59 UTC (permalink / raw)
To: Pepe Aracil; +Cc: linux-bluetooth
In-Reply-To: <AANLkTikqpge1KU4w4aQhtxz21097iQjWTKekdgg_+JeX@mail.gmail.com>
Hi,
On Wed, Oct 06, 2010, Pepe Aracil wrote:
> I have compiled bluez without audio support to avoid SCO socket be
> blocked by bluetoothd. Without positive results.
>
> ¿Some idea?
Just to be sure you could add DisablePlugins=audio to
/etc/bluetooth/main.conf.
Johan
^ permalink raw reply
* SCO Socket input.
From: Pepe Aracil @ 2010-10-06 9:53 UTC (permalink / raw)
To: linux-bluetooth
Hello.
If I create SCO socket listening input connections it not works if
bluetoothd is running but if I kill bluetoothd SCO input connections
works fine.
I need bluetoothd running for (mobile rfcomm connection) keys exchange
purposes but I must kill bluetoothd after rfcomm connection if i want
SCO input socket connections works well.
I have compiled bluez without audio support to avoid SCO socket be
blocked by bluetoothd. Without positive results.
¿Some idea?
Thanks
^ permalink raw reply
* RE: Sim Access profile server implementation
From: Waldemar.Rymarkiewicz @ 2010-10-06 9:32 UTC (permalink / raw)
To: marcel
Cc: suraj, linux-bluetooth, Jothikumar.Mothilal, joakim.xj.ceder,
arunkr.singh
In-Reply-To: <99B09243E1A5DA4898CDD8B700111448097D01B6CF@EXMB04.eu.tieto.com>
[-- Attachment #1: Type: text/plain, Size: 516 bytes --]
Hi Marcel,
>>
>>Can you share that code with us. And also hardware if you. We
>are still
>>having hard time to find proper hardware to test this on.
>
>Will send a patch soon. I use
>http://www.stericsson.com/platforms/U8500.jsp hw, but need to
>check if I can share one with you.
>
Here you are the patch. Just note that it is based on an old bluez 4.4x
If you consider to accept the design I will update the patch upon the latest release.
Will appreciate any comments.
Thanks,
/Waldek
[-- Attachment #2: 0001-Add-Sim-Access-plugin.patch --]
[-- Type: application/octet-stream, Size: 95321 bytes --]
From 12f560c28fd3fe926d10639156e10d089dd26506 Mon Sep 17 00:00:00 2001
From: Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com>
Date: Tue, 28 Sep 2010 17:24:19 +0200
Subject: [PATCH] Add Sim Access plugin
Sim Access plugin implements Sim Access Profile server role
according to the Bluetooth Sim Access Profile v1.1 specification.
Change-Id: I55e86dda969ae18339a134686ebf0b31a74ff335
---
Makefile.am | 2 +-
acinclude.m4 | 13 +
configure.ac | 1 +
sap/Android.mk | 33 ++
sap/Makefile.am | 25 +
sap/main.c | 57 +++
sap/manager.c | 98 ++++
sap/manager.h | 23 +
sap/sap-dummy.c | 76 +++
sap/sap-ste.c | 1309 +++++++++++++++++++++++++++++++++++++++++++++++++
sap/sap.h | 200 ++++++++
sap/server.c | 1459 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
sap/server.h | 25 +
13 files changed, 3320 insertions(+), 1 deletions(-)
mode change 100644 => 100755 Makefile.am
mode change 100644 => 100755 acinclude.m4
mode change 100644 => 100755 configure.ac
create mode 100644 sap/Android.mk
create mode 100644 sap/Makefile.am
create mode 100644 sap/main.c
create mode 100644 sap/manager.c
create mode 100644 sap/manager.h
create mode 100644 sap/sap-dummy.c
create mode 100644 sap/sap-ste.c
create mode 100644 sap/sap.h
create mode 100644 sap/server.c
create mode 100644 sap/server.h
diff --git a/Makefile.am b/Makefile.am
old mode 100644
new mode 100755
index c4c6322..acea6bb
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,6 +1,6 @@
SUBDIRS = include lib sbc gdbus common plugins src client\
- network serial input audio tools \
+ network serial input audio tools sap\
rfcomm compat cups test scripts doc
EXTRA_DIST = bluez.m4
diff --git a/acinclude.m4 b/acinclude.m4
old mode 100644
new mode 100755
index 248fed3..68962bc
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -197,6 +197,7 @@ AC_DEFUN([AC_ARG_BLUEZ], [
input_enable=yes
serial_enable=yes
network_enable=yes
+ sap_enable=yes
service_enable=yes
tools_enable=yes
hidd_enable=no
@@ -212,6 +213,7 @@ AC_DEFUN([AC_ARG_BLUEZ], [
udevrules_enable=yes
configfiles_enable=yes
telephony_driver=dummy
+ sap_driver=dummy
AC_ARG_ENABLE(optimization, AC_HELP_STRING([--disable-optimization], [disable code optimization]), [
optimization_enable=${enableval}
@@ -241,6 +243,10 @@ AC_DEFUN([AC_ARG_BLUEZ], [
audio_enable=${enableval}
])
+ AC_ARG_ENABLE(sap, AC_HELP_STRING([--disable-sap], [disable sap plugin]), [
+ sap_enable=${enableval}
+ ])
+
AC_ARG_ENABLE(service, AC_HELP_STRING([--disable-service], [disable service plugin]), [
service_enable=${enableval}
])
@@ -323,6 +329,12 @@ AC_DEFUN([AC_ARG_BLUEZ], [
AC_SUBST([TELEPHONY_DRIVER], [telephony-${telephony_driver}.c])
+ AC_ARG_WITH(sap, AC_HELP_STRING([--with-sap=DRIVER], [select SIM Access driver]), [
+ sap_driver=${withval}
+ ])
+
+ AC_SUBST([SAP_DRIVER], [sap-${sap_driver}.c])
+
if (test "${fortify_enable}" = "yes"); then
CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2"
fi
@@ -363,6 +375,7 @@ AC_DEFUN([AC_ARG_BLUEZ], [
AM_CONDITIONAL(INPUTPLUGIN, test "${input_enable}" = "yes")
AM_CONDITIONAL(SERIALPLUGIN, test "${serial_enable}" = "yes")
AM_CONDITIONAL(NETWORKPLUGIN, test "${network_enable}" = "yes")
+ AM_CONDITIONAL(SAPPLUGIN, test "${sap_enable}" = "yes")
AM_CONDITIONAL(SERVICEPLUGIN, test "${service_enable}" = "yes")
AM_CONDITIONAL(HIDD, test "${hidd_enable}" = "yes")
AM_CONDITIONAL(PAND, test "${pand_enable}" = "yes")
diff --git a/configure.ac b/configure.ac
old mode 100644
new mode 100755
index 85e1dae..512d032
--- a/configure.ac
+++ b/configure.ac
@@ -71,4 +71,5 @@ AC_OUTPUT([
src/bluetoothd.8
src/hcid.conf.5
bluez.pc
+ sap/Makefile
])
diff --git a/sap/Android.mk b/sap/Android.mk
new file mode 100644
index 0000000..d46837a
--- /dev/null
+++ b/sap/Android.mk
@@ -0,0 +1,33 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ manager.c \
+ server.c \
+ main.c \
+ sap-ste.c
+
+LOCAL_CFLAGS:= \
+ -DVERSION=\"4.47\"
+
+LOCAL_C_INCLUDES:= \
+ $(LOCAL_PATH)/../include \
+ $(LOCAL_PATH)/../common \
+ $(LOCAL_PATH)/../gdbus \
+ $(LOCAL_PATH)/../src \
+ $(call include-path-for, glib) \
+ $(call include-path-for, dbus)
+
+LOCAL_SHARED_LIBRARIES := \
+ libbluetoothd \
+ libbluetooth \
+ libdbus
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/bluez-plugin
+LOCAL_UNSTRIPPED_PATH := $(TARGET_OUT_SHARED_LIBRARIES_UNSTRIPPED)/bluez-plugin
+LOCAL_MODULE := sap
+LOCAL_PRELINK_MODULE := false
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/sap/Makefile.am b/sap/Makefile.am
new file mode 100644
index 0000000..2166cfc
--- /dev/null
+++ b/sap/Makefile.am
@@ -0,0 +1,25 @@
+if SAPPLUGIN
+plugindir = $(libdir)/bluetooth/plugins
+
+plugin_LTLIBRARIES = sap.la
+
+sap_la_SOURCES = server.c manager.h sap.c \
+ server.h manager.c \
+ sap.h main.c
+
+LDADD = $(top_builddir)/common/libhelper.a \
+ @GDBUS_LIBS@ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@
+endif
+
+AM_LDFLAGS = -module -avoid-version -no-undefined
+
+AM_CFLAGS = -fvisibility=hidden \
+ @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ @GDBUS_CFLAGS@
+
+INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/src
+
+MAINTAINERCLEANFILES = Makefile.in
+
+sap.c: @SAP_DRIVER@
+ @if [ ! -e $@ ] ; then $(LN_S) $< $@ ; fi
+
diff --git a/sap/main.c b/sap/main.c
new file mode 100644
index 0000000..541951b
--- /dev/null
+++ b/sap/main.c
@@ -0,0 +1,57 @@
+/*
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 ST-Ericsson SA
+ * Copyright (C) 2010 Claudio Takahasi<claudio.takahasi@openbossa.org>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+
+#include <gdbus.h>
+
+#include "plugin.h"
+#include "manager.h"
+
+static DBusConnection *connection;
+
+static int sap_init(void)
+{
+ connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+ if (connection == NULL)
+ return -EIO;
+
+ if (sap_manager_init(connection) < 0) {
+ dbus_connection_unref(connection);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void sap_exit(void)
+{
+ sap_manager_exit();
+
+ dbus_connection_unref(connection);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(sap, VERSION,
+ BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, sap_init, sap_exit)
+
diff --git a/sap/manager.c b/sap/manager.c
new file mode 100644
index 0000000..4a249a9
--- /dev/null
+++ b/sap/manager.c
@@ -0,0 +1,98 @@
+/*
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 ST-Ericsson SA
+ * Copyright (C) 2010 Claudio Takahasi<claudio.takahasi@openbossa.org>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <gdbus.h>
+
+#include "logging.h"
+#include "adapter.h"
+#include "device.h"
+
+#include "manager.h"
+
+#include "server.h"
+
+#define SAP_UUID_STR "0000112D-0000-1000-8000-00805F9B34FB"
+
+static DBusConnection *connection = NULL;
+
+
+static int sap_server_probe(struct btd_adapter *adapter)
+{
+ const gchar *path = adapter_get_path(adapter);
+ bdaddr_t src;
+
+ DBG("path %s", path);
+
+ adapter_get_address(adapter, &src);
+
+ return sap_server_register(path, &src);
+}
+
+static void sap_server_remove(struct btd_adapter *adapter)
+{
+ const gchar *path = adapter_get_path(adapter);
+
+ DBG("path %s", path);
+
+ sap_server_unregister(path);
+}
+
+static struct btd_adapter_driver sap_server_driver = {
+ .name = "sap-server",
+ .probe = sap_server_probe,
+ .remove = sap_server_remove,
+};
+
+int sap_manager_init(DBusConnection *conn)
+{
+ connection = dbus_connection_ref(conn);
+
+ if (sap_server_init(connection) < 0) {
+ error("Can't init SAP server");
+ dbus_connection_unref(conn);
+ return -1;
+ }
+
+ btd_register_adapter_driver(&sap_server_driver);
+
+ return 0;
+}
+
+void sap_manager_exit(void)
+{
+ btd_unregister_adapter_driver(&sap_server_driver);
+
+ dbus_connection_unref(connection);
+ connection = NULL;
+
+ sap_server_exit();
+}
+
diff --git a/sap/manager.h b/sap/manager.h
new file mode 100644
index 0000000..5c1c02a
--- /dev/null
+++ b/sap/manager.h
@@ -0,0 +1,23 @@
+/*
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 ST-Ericsson SA
+ * Copyright (C) 2010 Claudio Takahasi<claudio.takahasi@openbossa.org>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+int sap_manager_init(DBusConnection *conn);
+void sap_manager_exit(void);
+
diff --git a/sap/sap-dummy.c b/sap/sap-dummy.c
new file mode 100644
index 0000000..6a93900
--- /dev/null
+++ b/sap/sap-dummy.c
@@ -0,0 +1,76 @@
+/*
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 ST-Ericsson SA
+ * Copyright (C) 2010 Claudio Takahasi<claudio.takahasi@openbossa.org>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "sap.h"
+
+void sap_connect_req(void *sap_device, uint16_t maxmsgsize)
+{
+ sap_connect_rsp(sap_device, SAP_STATUS_OK, maxmsgsize);
+ sap_status_ind(sap_device, SAP_STATUS_CHANGE_CARD_RESET);
+}
+
+void sap_disconnect_req(void *sap_device)
+{
+ sap_disconnect_rsp(sap_device, SAP_RESULT_OK);
+}
+
+void sap_transfer_apdu_req(void *sap_device, sap_parameter *param)
+{
+ sap_transfer_apdu_rsp(sap_device, SAP_RESULT_OK, NULL, 0);
+}
+
+void sap_transfer_atr_req(void * sap_device)
+{
+ uint8_t atr[] = {0x3b, 0x9a, 0x96, 0x00, 0x92, 0x01, 0x98, 0x93, 0x17, 0x00, 0x02, 0x28, 0x03, 0x00};
+ sap_transfer_atr_rsp(sap_device, SAP_RESULT_OK, atr, 0x0E);
+}
+
+void sap_power_sim_off_req(void *sap_device)
+{
+ sap_power_sim_off_rsp(sap_device, SAP_RESULT_OK);
+}
+
+void sap_power_sim_on_req(void *sap_device)
+{
+ sap_power_sim_on_rsp(sap_device, SAP_RESULT_OK);
+}
+
+void sap_reset_sim_req(void *sap_device)
+{
+ sap_reset_sim_rsp(sap_device, SAP_RESULT_OK);
+}
+
+void sap_transfer_card_reader_status_req(void * sap_device)
+{
+ sap_transfer_card_reader_status_rsp(sap_device, SAP_RESULT_OK, 0xF1);
+}
+
+void sap_set_transport_protocol_req(void * sap_device,sap_parameter * param)
+{
+
+}
diff --git a/sap/sap-ste.c b/sap/sap-ste.c
new file mode 100644
index 0000000..2298e61
--- /dev/null
+++ b/sap/sap-ste.c
@@ -0,0 +1,1309 @@
+/*
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 ST-Ericsson SA
+ *
+ * Author: Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com> for
+ * ST-Ericsson.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include <glib.h>
+#include <assert.h>
+#include "logging.h"
+
+#include "sap.h"
+
+/** STE_SIM_MAX_MSG_SIZE - Maximum size of Sim Access Profile message
+ * supported by the server.
+ */
+#define STE_SIM_MAX_MSG_SIZE 1024
+
+/** STE_SIM_MIN_MSG_SIZE - Minimal size of Sim Access Profile message
+ * supported by the server.
+ */
+#define STE_SIM_MIN_MSG_SIZE 512
+
+/** STE_SIM_UNIX_SOCKET_NAME - Unix socket name used to communicate with
+ * SIM daemon.
+ */
+#define STE_SIM_UNIX_SOCKET_NAME "/dev/socket/catd_a"
+
+/*Sizes of SIM message fields.*/
+#define STE_SIM_MSG_LEN_SIZE 0x0002
+#define STE_SIM_MSG_TYPE_SIZE 0x0002
+#define STE_SIM_MSG_CLIENT_TAG_SIZE 0x0004
+#define STE_SIM_MSG_STATUS_SIZE 0x0004
+
+/*Header size of SIM message */
+#define STE_SIM_MSG_HEADER_SIZE ((STE_SIM_MSG_LEN_SIZE) + \
+ (STE_SIM_MSG_TYPE_SIZE) + (STE_SIM_MSG_CLIENT_TAG_SIZE))
+
+#define STE_SIM_CLIENT_TAG 0x0000
+
+#define STE_UICC_RANGE_REQ_SAP (0x2D00)
+#define STE_UICC_RANGE_RSP_SAP (0x2E00)
+#define STE_UICC_RANGE_IND_SAP (0x2F00)
+
+/** ste_sim_protocol_t - protocol used in communication with SIM daemon.*/
+typedef enum {
+ STE_SIM_START_SAP_REQ = (STE_UICC_RANGE_REQ_SAP | 0x0001),
+ STE_SIM_START_SAP_RSP = (STE_UICC_RANGE_RSP_SAP | 0x0001),
+
+ STE_SIM_END_SAP_REQ = (STE_UICC_RANGE_REQ_SAP | 0x0002),
+ STE_SIM_END_SAP_RSP = (STE_UICC_RANGE_RSP_SAP | 0x0002),
+
+ STE_SIM_POWER_ON_REQ = (STE_UICC_RANGE_REQ_SAP | 0x0004),
+ STE_SIM_POWER_ON_RSP = (STE_UICC_RANGE_RSP_SAP | 0x0004),
+
+ STE_SIM_POWER_OFF_REQ = (STE_UICC_RANGE_REQ_SAP | 0x0003),
+ STE_SIM_POWER_OFF_RSP = (STE_UICC_RANGE_RSP_SAP | 0x0003),
+
+ STE_SIM_RESET_REQ = (STE_UICC_RANGE_REQ_SAP | 0x0005),
+ STE_SIM_RESET_RSP = (STE_UICC_RANGE_RSP_SAP | 0x0005),
+
+ STE_SIM_GET_ATR_REQ = (STE_UICC_RANGE_REQ_SAP | 0x0007),
+ STE_SIM_GET_ATR_RSP = (STE_UICC_RANGE_RSP_SAP | 0x0007),
+
+ STE_SIM_SEND_APDU_REQ = (STE_UICC_RANGE_REQ_SAP | 0x0006),
+ STE_SIM_SEND_APDU_RSP = (STE_UICC_RANGE_RSP_SAP | 0x0006),
+
+ STE_SIM_GET_STATUS_REQ = (STE_UICC_RANGE_REQ_SAP | 0x0008),
+ STE_SIM_GET_STATUS_RSP = (STE_UICC_RANGE_RSP_SAP | 0x0008),
+
+ STE_SIM_STATUS_IND = (STE_UICC_RANGE_IND_SAP | 0x0002)
+} ste_sim_protocol_t;
+
+/** ste_sim_msg_t - Type of SIM message.*/
+typedef enum {
+ STE_SIM_SEND_APDU_MSG = 0,
+ STE_SIM_GET_ATR_MSG,
+ STE_SIM_POWER_OFF_MSG,
+ STE_SIM_POWER_ON_MSG,
+ STE_SIM_RESET_MSG,
+ STE_SIM_GET_STATUS_MSG,
+ STE_SIM_MSG_MAX,
+} ste_sim_msg_t;
+
+/** ste_sim_status_t - Status of a request.*/
+typedef enum {
+ STE_SIM_STATUS_OK = 0x00000000,
+ STE_SIM_STATUS_UNDEFINED_FAILURE = 0xFFFFFFFF,
+} ste_sim_status_t;
+
+/** ste_sim_card_status_t - Sim card status.*/
+typedef enum {
+ STE_SIM_CARD_STATUS_UNKNOWN = 0x00,
+ STE_SIM_CARD_STATUS_READY = 0x01,
+ STE_SIM_CARD_STATUS_NOT_READY = 0x02,
+ STE_SIM_CARD_STATUS_MISSING = 0x03,
+ STE_SIM_CARD_STATUS_INVALID = 0x04
+} ste_sim_card_status_t;
+
+/** ste_sim_reader_status_t - Sim card reader status.*/
+typedef enum {
+ STE_SIM_READER_UNSPECIFIED_ERROR = 0x0000,
+ STE_SIM_READER_NOT_PRESENT = 0x0001,
+ STE_SIM_READER_BUSY = 0x0002,
+ STE_SIM_READER_CARD_POWERED_ON = 0x0003,
+ STE_SIM_READER_DEACTIVATED = 0x0004,
+ STE_SIM_READER_CARD_POWERED_OFF = 0x0005,
+ STE_SIM_READER_NO_CARD = 0x0006
+}ste_sim_reader_status_t;
+
+/** ste_sim_state_t - Sim connection state.*/
+typedef enum {
+ STE_SIM_DISABLED, /* Reader not presend or removed */
+ STE_SIM_POWERED_OFF, /* Card in the reader but powered off */
+ STE_SIM_NO_CARD, /* No card in the reader */
+ STE_SIM_ENABLED, /* Card in the reader and powered on */
+ STE_SIM_STATE_MAX
+} ste_sim_state_t;
+
+/** ste_sim_message - Sim message format.
+ * @len; Length of the message minus sizeof(len).
+ * @id; Request type id.
+ * @client_tag; SAP server cleint id.
+ * @payload; Data.
+ */
+typedef struct {
+ uint16_t len;
+ uint16_t id;
+ uint32_t client_tag;
+ uint8_t payload[0];
+} __attribute__ ((packed)) ste_sim_message;
+
+/** ste_sim_connection - main admin structure that keeps data about connection
+ * with Sim daemon.
+ */
+struct ste_sim_connection {
+ GIOChannel *io;
+ ste_sim_state_t state;
+ void *sap_data;
+};
+
+static struct ste_sim_connection *simd_conn = NULL;
+
+/** sim2sap_result - Conversion table of sap result which varies with
+ * connection state and the message type.
+ */
+static sap_result_t sim2sap_result[STE_SIM_MSG_MAX][STE_SIM_STATE_MAX] = {
+ /* SAP results for SEND APDU message */
+ {SAP_RESULT_ERROR_NOT_ACCESSIBLE,/*for STE_SIM_DISABLED state */
+ SAP_RESULT_ERROR_POWERED_OFF, /*for STE_SIM_POWERED_OFF state */
+ SAP_RESULT_ERROR_CARD_REMOVED, /*for STE_SIM_NO_CARD state */
+ SAP_RESULT_ERROR_NO_REASON}, /*for STE_SIM_ENABLED state */
+ /* SAP results for GET_ATR message */
+ {SAP_RESULT_ERROR_NO_REASON,
+ SAP_RESULT_ERROR_POWERED_OFF,
+ SAP_RESULT_ERROR_CARD_REMOVED,
+ SAP_RESULT_ERROR_NO_REASON},
+ /* SAP results POWER OFF message */
+ {SAP_RESULT_ERROR_NO_REASON,
+ SAP_RESULT_ERROR_POWERED_OFF,
+ SAP_RESULT_ERROR_CARD_REMOVED,
+ SAP_RESULT_ERROR_NO_REASON},
+ /* SAP results POWER ON message */
+ {SAP_RESULT_ERROR_NO_REASON,
+ SAP_RESULT_ERROR_NOT_ACCESSIBLE,
+ SAP_RESULT_ERROR_CARD_REMOVED,
+ SAP_RESULT_ERROR_POWERED_ON},
+ /* SAP results SIM RESET message */
+ {SAP_RESULT_ERROR_NO_REASON,
+ SAP_RESULT_ERROR_POWERED_OFF,
+ SAP_RESULT_ERROR_CARD_REMOVED,
+ SAP_RESULT_ERROR_NOT_ACCESSIBLE},
+ /* SAP results GET STATUS message */
+ {SAP_RESULT_ERROR_NO_REASON,
+ SAP_RESULT_ERROR_NO_REASON,
+ SAP_RESULT_ERROR_NO_REASON,
+ SAP_RESULT_ERROR_NO_REASON}
+ };
+
+static void simd_conn_uninit(struct ste_sim_connection *c);
+static int simd_conn_watch(int sock, void *sap_data);
+
+/**
+ * get_sap_result - Convert STE sim status to sap result.
+ * @c; Connection info structure.
+ * @msg; Sim message type.
+ * @status; Sim status.
+ *
+ * Returns:
+ * SAP result.
+ */
+static sap_result_t get_sap_result(struct ste_sim_connection *c,
+ ste_sim_msg_t msg, ste_sim_status_t status)
+{
+ if (!c)
+ return SAP_RESULT_ERROR_NO_REASON;
+
+ switch (status){
+ case STE_SIM_STATUS_OK:
+ return SAP_RESULT_OK;
+
+ case STE_SIM_STATUS_UNDEFINED_FAILURE:
+ return sim2sap_result[msg][c->state];
+
+ default:
+ error("Cannot convert ste_sim_status [status: %d] \
+ to sap_result.", status);
+ return SAP_RESULT_ERROR_NO_REASON;
+ }
+}
+
+/**
+ * get_sap_reader_status - Convert STE sim reader status to sap reader result.
+ * @status; Sim card reader status.
+ *
+ * Returns:
+ * SAP reader status.
+ */
+static icc_reader_status_t get_sap_reader_status(ste_sim_reader_status_t status)
+{
+ switch (status){
+ case STE_SIM_READER_UNSPECIFIED_ERROR:
+ return ICC_READER_UNSPECIFIED_ERROR;
+
+ case STE_SIM_READER_NOT_PRESENT:
+ return ICC_READER_NOT_PRESENT;
+
+ case STE_SIM_READER_BUSY:
+ return ICC_READER_BUSY;
+
+ case STE_SIM_READER_CARD_POWERED_ON:
+ return ICC_READER_CARD_POWERED_ON;
+
+ case STE_SIM_READER_DEACTIVATED:
+ return ICC_READER_DEACTIVATED;
+
+ case STE_SIM_READER_CARD_POWERED_OFF:
+ return ICC_READER_CARD_POWERED_OFF;
+
+ case STE_SIM_READER_NO_CARD:
+ return ICC_READER_NO_CARD;
+
+ default:
+ error("Cannot convert ste_sim_reader_status [status: %d]\
+ to icc_sap_reader_status.", status);
+ return ICC_READER_UNSPECIFIED_ERROR;
+ }
+}
+
+/**
+ * sap_status_change - Convert STE sim card status to sap change event.
+ * @c; Connection info structure.
+ * @status; Sim card status.
+ *
+ * This also updates Sim connection state.
+ *
+ * Returns:
+ * SAP change event.
+ */
+static sap_status_change_t sap_status_change(struct ste_sim_connection *c,
+ ste_sim_card_status_t status)
+{
+ if (!c)
+ return SAP_STATUS_CHANGE_UNKNOWN_ERROR;
+
+ switch (status){
+ case STE_SIM_CARD_STATUS_UNKNOWN:
+ return SAP_STATUS_CHANGE_UNKNOWN_ERROR;
+
+ case STE_SIM_CARD_STATUS_READY:
+ c->state = STE_SIM_ENABLED;
+ return SAP_STATUS_CHANGE_CARD_RESET;
+
+ case STE_SIM_CARD_STATUS_NOT_READY:
+ c->state = STE_SIM_DISABLED;
+ return SAP_STATUS_CHANGE_CARD_NOT_ACCESSIBLE;
+
+ case STE_SIM_CARD_STATUS_MISSING:
+ c->state = STE_SIM_DISABLED;
+ return SAP_STATUS_CHANGE_CARD_REMOVED;
+
+ case STE_SIM_CARD_STATUS_INVALID:
+ c->state = STE_SIM_DISABLED;
+ return SAP_STATUS_CHANGE_CARD_NOT_ACCESSIBLE;
+
+ default:
+ error("Cannot convert ste_sim_status_change to \
+ sap_status_change.");
+ return SAP_STATUS_CHANGE_UNKNOWN_ERROR;
+ }
+}
+/**
+ * send_message - Send Sim message to Sim daemon.
+ * @c; Connection info structure.
+ * @buf; Sim message.
+ * @size; Size of Sim message
+ *
+ * Returns:
+ * O if success or negaive integer if error occured.
+ */
+static int send_message(struct ste_sim_connection *c,
+ ste_sim_message *buf, gsize size)
+{
+ gsize written = 0;
+ GIOError gerr;
+
+ debug("[STE_DRV] send_message: c %p, buf %p size %d", c, buf,
+ (int) size);
+
+ gerr = g_io_channel_write(c->io, (const gchar *) buf, size, &written);
+
+ if (written != size) {
+ error("[STE_DRV] send_message: written only %d bytes out of %d"
+ , (int)written, (int)size);
+ return -1;
+ }
+
+ if (gerr != G_IO_ERROR_NONE) {
+ int err = errno;
+ error("write error: %s(%d)", strerror(err), err);
+ return -err;
+ }
+
+ return 0;
+}
+
+/**
+ * ste_sim_start_sap_req - Create and send start SAP request message.
+ * @c; Connection info structure.
+ *
+ * Returns:
+ * O if success or negaive integer in case of error.
+ */
+static int ste_sim_start_sap_req(struct ste_sim_connection *c)
+{
+ int err;
+ ste_sim_message *msg = NULL;
+ gsize msg_size = STE_SIM_MSG_HEADER_SIZE;
+
+ debug("[STE_DRV] ste_sim_start_sap_req: c %p", c);
+
+ msg = (ste_sim_message *)g_malloc0(msg_size);
+ if (msg == NULL)
+ return -1;
+
+ msg->len = msg_size - STE_SIM_MSG_LEN_SIZE;
+ msg->id = STE_SIM_START_SAP_REQ;
+ msg->client_tag = STE_SIM_CLIENT_TAG;
+
+ err = send_message(c, msg, msg_size);
+ if (err < 0)
+ return err;
+
+ g_free(msg);
+ return 0;
+}
+
+/**
+ * ste_sim_end_sap_req - Create and send end SAP request message.
+ * @c; Connection info structure.
+ *
+ * Returns:
+ * O if success or negaive integer in case of error.
+ */
+static int ste_sim_end_sap_req(struct ste_sim_connection *c)
+{
+ int err;
+ ste_sim_message *msg = NULL;
+ gsize msg_size = STE_SIM_MSG_HEADER_SIZE;
+
+ debug("[STE_DRV] ste_sim_end_sap_req: c %p", c);
+
+ msg = (ste_sim_message *)g_malloc0(msg_size);
+ if (msg == NULL)
+ return -1;
+
+ msg->len = msg_size - STE_SIM_MSG_LEN_SIZE;
+ msg->id = STE_SIM_END_SAP_REQ;
+ msg->client_tag = STE_SIM_CLIENT_TAG;
+
+ err = send_message(c, msg, msg_size);
+ if (err < 0)
+ return err;
+
+ g_free(msg);
+ return 0;
+}
+
+/**
+ * ste_sim_end_sap_req - Create and send transfer apdu request message.
+ * @c; Connection info structure.
+ *
+ * Returns:
+ * O if success or negaive integer in case of error.
+ */
+static int ste_sim_send_apdu_req(struct ste_sim_connection *c,
+ sap_parameter *param)
+{
+ int err;
+ ste_sim_message *msg = NULL;
+ gsize msg_size = STE_SIM_MSG_HEADER_SIZE + param->len;
+
+ debug("[STE_DRV] ste_sim_send_apdu_req: c %p param %p len %d",
+ c, param, param->len);
+
+ msg = (ste_sim_message *)g_malloc0(msg_size);
+ if (msg == NULL)
+ return -1;
+
+ msg->len = msg_size - STE_SIM_MSG_LEN_SIZE;
+ msg->id = STE_SIM_SEND_APDU_REQ;
+ msg->client_tag = STE_SIM_CLIENT_TAG;
+ memcpy(msg->payload, param->val, param->len);
+
+ err = send_message(c, msg, msg_size);
+ if (err < 0)
+ return err;
+
+ g_free(msg);
+ return 0;
+}
+
+/**
+ * ste_sim_get_atr_req - Create and send get ATR request message.
+ * @c; Connection info structure.
+ *
+ * Returns:
+ * O if success or negaive integer in case of error.
+ */
+static int ste_sim_get_atr_req(struct ste_sim_connection *c)
+{
+ int err;
+ ste_sim_message *msg = NULL;
+ gsize msg_size = STE_SIM_MSG_HEADER_SIZE;
+
+ debug("[STE_DRV] ste_sim_get_atr_req: c %p", c);
+
+ msg = (ste_sim_message *)g_malloc0(msg_size);
+ if (msg == NULL)
+ return -1;
+
+ msg->len = msg_size - STE_SIM_MSG_LEN_SIZE;
+ msg->id = STE_SIM_GET_ATR_REQ;
+ msg->client_tag = STE_SIM_CLIENT_TAG;
+
+ err = send_message(c, msg, msg_size);
+ if (err < 0)
+ return err;
+
+ g_free(msg);
+ return 0;
+}
+
+/**
+ * ste_sim_power_off_req - Create and send power off request message.
+ * @c; Connection info structure.
+ *
+ * Returns:
+ * O if success or negaive integer in case of error.
+ */
+static int ste_sim_power_off_req(struct ste_sim_connection *c)
+{
+ int err;
+ ste_sim_message *msg = NULL;
+ gsize msg_size = STE_SIM_MSG_HEADER_SIZE;
+
+ debug("[STE_DRV] ste_sim_power_off_req: c %p", c);
+
+ msg = (ste_sim_message *)g_malloc0(msg_size);
+ if (msg == NULL)
+ return -1;
+
+ msg->len = msg_size - STE_SIM_MSG_LEN_SIZE;
+ msg->id = STE_SIM_POWER_OFF_REQ;
+ msg->client_tag = STE_SIM_CLIENT_TAG;
+
+ err = send_message(c, msg, msg_size);
+ if (err < 0)
+ return err;
+
+ g_free(msg);
+ return 0;
+}
+
+/**
+ * ste_sim_power_on_req - Create and send power on request message.
+ * @c; Connection info structure.
+ *
+ * Returns:
+ * O if success or negaive integer in case of error.
+ */
+static int ste_sim_power_on_req(struct ste_sim_connection *c)
+{
+ int err;
+ ste_sim_message *msg = NULL;
+ gsize msg_size = STE_SIM_MSG_HEADER_SIZE;
+
+ debug("[STE_DRV] ste_sim_power_on_req: c %p", c);
+
+ msg = (ste_sim_message *)g_malloc0(msg_size);
+ if (msg == NULL)
+ return -1;
+
+ msg->len = msg_size - STE_SIM_MSG_LEN_SIZE;
+ msg->id = STE_SIM_POWER_ON_REQ;
+ msg->client_tag = STE_SIM_CLIENT_TAG;
+
+ err = send_message(c, msg, msg_size);
+ if (err < 0)
+ return err;
+
+ g_free(msg);
+ return 0;
+}
+
+/**
+ * ste_sim_reset_req - Create and send card reset request message.
+ * @c; Connection info structure.
+ *
+ * Returns:
+ * O if success or negaive integer in case of error.
+ */
+static int ste_sim_reset_req(struct ste_sim_connection *c)
+{
+ int err;
+ ste_sim_message *msg = NULL;
+ gsize msg_size = STE_SIM_MSG_HEADER_SIZE;
+
+ debug("[STE_DRV] ste_sim_reset_req: c %p", c);
+
+ msg = (ste_sim_message *)g_malloc0(msg_size);
+ if (msg == NULL)
+ return -1;
+
+ msg->len = msg_size - STE_SIM_MSG_LEN_SIZE;
+ msg->id = STE_SIM_RESET_REQ;
+ msg->client_tag = STE_SIM_CLIENT_TAG;
+
+ err = send_message(c, msg, msg_size);
+ if (err < 0)
+ return err;
+
+ g_free(msg);
+ return 0;
+}
+
+/**
+ * ste_sim_get_status_req - Create and send card status request message.
+ * @c; Connection info structure.
+ *
+ * Returns:
+ * O if success or negaive integer in case of error.
+ */
+static int ste_sim_get_status_req(struct ste_sim_connection *c)
+{
+ int err;
+ ste_sim_message *msg = NULL;
+ gsize msg_size = STE_SIM_MSG_HEADER_SIZE;
+
+ debug("[STE_DRV] ste_sim_get_status_req: c %p", c);
+
+ msg = (ste_sim_message *)g_malloc0(msg_size);
+ if (msg == NULL)
+ return -1;
+
+ msg->len = msg_size - STE_SIM_MSG_LEN_SIZE;
+ msg->id = STE_SIM_GET_STATUS_REQ;
+ msg->client_tag = STE_SIM_CLIENT_TAG;
+
+ err = send_message(c, msg, msg_size);
+ if (err < 0)
+ return err;
+
+ g_free(msg);
+ return 0;
+}
+
+/**
+ * ste_sim_start_sap_rsp - Handle start SAP response message.
+ * @c; Connection info structure.
+ * @msg; Response message.
+ */
+static void ste_sim_start_sap_rsp(struct ste_sim_connection *c,
+ ste_sim_message * msg)
+{
+ uint32_t *status;
+ sap_status_t ss;
+ sap_status_change_t sc;
+
+ assert(msg && c);
+
+ debug("[STE_DRV] ste_sim_start_sap_rsp: c %p (conn %p) msg %p",
+ c, simd_conn, msg );
+
+ status = (uint32_t*) msg->payload;
+ if (*status == STE_SIM_STATUS_OK)
+ sap_connect_rsp(c->sap_data, SAP_STATUS_OK, 0);
+ else {
+ sap_connect_rsp(c->sap_data, SAP_STATUS_CONNECTION_FAILED, 0);
+ simd_conn_uninit(c);
+ }
+}
+
+/**
+ * ste_sim_end_sap_rsp - Handle end SAP response message.
+ * @c; Connection info structure.
+ * @msg; Response message.
+ */
+static void ste_sim_end_sap_rsp(struct ste_sim_connection *c,
+ ste_sim_message * msg)
+{
+ debug("[STE_DRV] ste_sim_end_sap_rsp: c %p (conn %p) msg %p",
+ c, simd_conn, msg );
+ assert(msg && c);
+
+ sap_disconnect_rsp(c->sap_data);
+ simd_conn_uninit(c);
+}
+
+/**
+ * ste_sim_send_apdu_rsp - Handle transfer apdu response message.
+ * @c; Connection info structure.
+ * @msg; Response message.
+ */
+static void ste_sim_send_apdu_rsp(struct ste_sim_connection *c,
+ ste_sim_message * msg)
+{
+ uint32_t *status;
+ sap_result_t sr;
+ uint8_t *apdu = NULL;
+ uint16_t len = 0;
+
+ debug("[STE_DRV] ste_sim_send_apdu_rsp: c %p (conn %p) msg %p",
+ c, simd_conn, msg );
+
+ assert(msg && c);
+
+ status = (uint32_t*) msg->payload;
+ if (*status == STE_SIM_STATUS_OK) {
+ apdu = (uint8_t *)(msg->payload + STE_SIM_MSG_STATUS_SIZE);
+ len = msg->len - (STE_SIM_MSG_HEADER_SIZE) +
+ STE_SIM_MSG_LEN_SIZE - STE_SIM_MSG_STATUS_SIZE;
+ }
+
+ sr = get_sap_result(c, STE_SIM_SEND_APDU_MSG, *status);
+ sap_transfer_apdu_rsp(c->sap_data, sr, apdu, len);
+}
+
+/**
+ * ste_sim_get_atr_rsp - Handle get ATR response message.
+ * @c; Connection info structure.
+ * @msg; Response message.
+ */
+static void ste_sim_get_atr_rsp(struct ste_sim_connection *c,
+ ste_sim_message * msg)
+{
+ uint32_t *status;
+ sap_result_t sr;
+ uint8_t *atr = NULL;
+ uint16_t len = 0;
+
+ debug("[STE_DRV] ste_sim_get_atr_rsp: c %p (conn %p) msg %p",
+ c, simd_conn, msg );
+
+ assert(msg && c);
+
+ status = (uint32_t*) msg->payload;
+ if (*status == STE_SIM_STATUS_OK) {
+ atr = (uint8_t *)(msg->payload + STE_SIM_MSG_STATUS_SIZE);
+ len = msg->len - (STE_SIM_MSG_HEADER_SIZE) +
+ STE_SIM_MSG_LEN_SIZE;
+ }
+
+ sr = get_sap_result(c, STE_SIM_GET_ATR_MSG, *status);
+ sap_transfer_atr_rsp(c->sap_data, sr, atr, len);
+}
+
+/**
+ * ste_sim_power_off_rsp - Handle power off response message.
+ * @c; Connection info structure.
+ * @msg; Response message.
+ */
+static void ste_sim_power_off_rsp(struct ste_sim_connection *c,
+ ste_sim_message * msg)
+{
+ uint32_t *status;
+ sap_result_t sr;
+
+ debug("[STE_DRV] ste_sim_power_off_rsp: c %p (conn %p) msg %p",
+ c, simd_conn, msg );
+
+ assert(msg && c);
+
+ status = (uint32_t *) msg->payload;
+ if (*status == STE_SIM_STATUS_OK)
+ c->state = STE_SIM_POWERED_OFF;
+
+ sr = get_sap_result(c, STE_SIM_POWER_OFF_MSG, *status);
+ sap_power_sim_off_rsp(c->sap_data, sr);
+}
+
+/**
+ * ste_sim_power_on_rsp - Handle power on response message.
+ * @c; Connection info structure.
+ * @msg; Response message.
+ */
+static void ste_sim_power_on_rsp(struct ste_sim_connection *c,
+ ste_sim_message * msg)
+{
+ uint32_t *status;
+ sap_result_t sr;
+
+ debug("[STE_DRV] ste_sim_power_on_rsp: c %p (conn %p) msg %p",
+ c, simd_conn, msg );
+
+ assert(msg && c);
+
+ status = (uint32_t *) msg->payload;
+ if (*status == STE_SIM_STATUS_OK)
+ c->state = STE_SIM_ENABLED;
+
+ sr = get_sap_result(c, STE_SIM_POWER_ON_MSG, *status);
+ sap_power_sim_on_rsp(c->sap_data, sr);
+}
+
+/**
+ * ste_sim_reset_rsp - Handle reset response message.
+ * @c; Connection info structure.
+ * @msg; Response message.
+ */
+static void ste_sim_reset_rsp(struct ste_sim_connection *c,
+ ste_sim_message * msg)
+{
+ uint32_t *status;
+ sap_result_t sr;
+
+ debug("[STE_DRV] ste_sim_reset_rsp: c %p (conn %p) msg %p",
+ c, simd_conn, msg );
+
+ assert(msg && c);
+
+ status = (uint32_t *) msg->payload;
+ if (*status == STE_SIM_STATUS_OK)
+ c->state = STE_SIM_ENABLED;
+
+ sr = get_sap_result(c, STE_SIM_RESET_MSG, *status);
+ sap_reset_sim_rsp(c->sap_data, sr);
+}
+
+/**
+ * ste_sim_get_status_rsp - Handle card status response message.
+ * @c; Connection info structure.
+ * @msg; Response message.
+ */
+static void ste_sim_get_status_rsp(struct ste_sim_connection *c,
+ ste_sim_message * msg)
+{
+ uint8_t *p = NULL;
+ uint32_t *status;
+ sap_result_t sr;
+ ste_sim_reader_status_t rs;
+ icc_reader_status_t iccrs;
+
+ debug("[STE_DRV] ste_sim_get_status_rsp: c %p (conn %p) msg %p",
+ c, simd_conn, msg );
+
+ assert(msg && c);
+
+ p = msg->payload;
+
+ status = (uint32_t *)p; p += sizeof(uint32_t);
+ rs = *((uint16_t *)p);
+
+ iccrs = get_sap_reader_status(rs);
+ sr = get_sap_result(c, STE_SIM_GET_STATUS_MSG, *status);
+ sap_transfer_card_reader_status_rsp(c->sap_data, sr, iccrs);
+}
+
+/**
+ * ste_sim_status_ind - Handle status indication message.
+ * @c; Connection info structure.
+ * @msg; Response message.
+ */
+static void ste_sim_status_ind(struct ste_sim_connection *c,
+ ste_sim_message * msg)
+{
+ sap_status_change_t sc;
+ ste_sim_card_status_t cs;
+
+ debug("[STE_DRV] ste_sim_status_ind: c %p (conn %p) msg %p",
+ c, simd_conn, msg );
+
+ assert(msg && c);
+
+ cs = *((uint32_t *) msg->payload);
+ sc = sap_status_change(c, cs);
+
+ sap_status_ind(c->sap_data, sc);
+}
+
+/**
+ * handle_msg - Handle messages from Sim daemon.
+ * @c; Connection info structure.
+ * @buf; Data buffer.
+ * @size; Size of data buffer.
+ *
+ * Returns:
+ * 0 if success or EBADMSG in case of bad message format.
+ */
+static int handle_msg(struct ste_sim_connection *c, unsigned char *buf,
+ gsize size)
+{
+ unsigned char *iter = buf;
+ ste_sim_message * msg = (ste_sim_message *) buf;
+ gsize msize = size;
+
+ assert(c);
+
+ do {
+ debug("[STE_DRV] handle_msg: msize %d msg->len %d.",
+ (int)msize, msg->len);
+
+ /* Message must be at least size of header len */
+ if (msize < STE_SIM_MSG_HEADER_SIZE) {
+ error("[STE_DRV] Invalid message size.");
+ return -EBADMSG;
+ }
+
+ /* Message must be completed. */
+ if (msize < (STE_SIM_MSG_LEN_SIZE + msg->len)) {
+ error("[STE_DRV] Not complete message.");
+ return -EBADMSG;
+ }
+
+ switch (msg->id){
+ case STE_SIM_START_SAP_RSP:
+ ste_sim_start_sap_rsp(c, msg);
+ break;
+
+ case STE_SIM_END_SAP_RSP:
+ ste_sim_end_sap_rsp(c, msg);
+ break;
+
+ case STE_SIM_SEND_APDU_RSP:
+ ste_sim_send_apdu_rsp(c, msg);
+ break;
+
+ case STE_SIM_GET_ATR_RSP:
+ ste_sim_get_atr_rsp(c, msg);
+ break;
+
+ case STE_SIM_POWER_OFF_RSP:
+ ste_sim_power_off_rsp(c, msg);
+ break;
+
+ case STE_SIM_POWER_ON_RSP:
+ ste_sim_power_on_rsp(c, msg);
+ break;
+
+ case STE_SIM_RESET_RSP:
+ ste_sim_reset_rsp(c, msg);
+ break;
+
+ case STE_SIM_GET_STATUS_RSP:
+ ste_sim_get_status_rsp(c, msg);
+ break;
+
+ case STE_SIM_STATUS_IND:
+ ste_sim_status_ind(c, msg);
+ break;
+
+ default:
+ error("[STE_DRV] Invalid or not supported \
+ frame [0x%02x].", msg->id);
+ }
+
+ /* Reduce total buffer size of just handled frame size*/
+ msize -= (STE_SIM_MSG_HEADER_SIZE +
+ (msg->len - (STE_SIM_MSG_HEADER_SIZE) +
+ STE_SIM_MSG_LEN_SIZE));
+
+ /* Move msg ponter to then next message if any */
+ iter += (msg->len + STE_SIM_MSG_LEN_SIZE);
+ msg = (ste_sim_message *)iter;
+
+ } while (msg && (msize > 0));
+
+ return 0;
+}
+
+/**
+ * simd_io_data_cb - Handle data on socket to Sim daemon.
+ * @io; Connection info structure.
+ * @cond; Conndition that triggered this callback.
+ * @data; Data buffor.
+ *
+ * Returns:
+ * True if @data was handled, False otherwise.
+ */
+static gboolean simd_io_data_cb(GIOChannel *io, GIOCondition cond,
+ gpointer data)
+{
+ GIOError err = G_IO_ERROR_NONE;
+ unsigned char buf[STE_SIM_MAX_MSG_SIZE];
+ gsize read_bytes = 0;
+
+ if (cond & G_IO_NVAL) {
+ debug("[STE_DRV] NVAL on sim socket");
+ return FALSE;
+ }
+
+ if (cond & G_IO_HUP) {
+ debug("[STE_DRV] HUP on sim socket");
+ return FALSE;
+ }
+
+ if (cond & G_IO_ERR) {
+ debug("[STE_DRV] ERR on sim socket");
+ return FALSE;
+ }
+
+ /* TODO: consider to read bytes in a while loop just in case if one read
+ operation won't read all data. while(read_data!=0)
+ */
+
+ err = g_io_channel_read(io, (gchar *)buf, sizeof(buf), &read_bytes);
+ if (err != G_IO_ERROR_NONE) {
+ error("[STE_DRV] Error while reading from channel \
+ [err 0x%x io %p].", err, io);
+ return FALSE;
+ }
+
+ if (handle_msg(data, buf, read_bytes) < 0)
+ error("[STE_DRV] Invalid STE Sim message.");
+
+ return TRUE;
+}
+
+/**
+ * simd_io_destroy_cb - Clean up the SAP serer in case of socket closure.
+ * @data; Private data.
+ *
+ * The callback is run if the connection with Sim daemon has been lost.
+ */
+static void simd_io_destroy_cb(void *data)
+{
+ struct ste_sim_connection *c = (struct ste_sim_connection *)data;
+
+ debug("[STE_DRV] simd_io_destroy_cb: c %p conn %p io %p", c,
+ simd_conn, c->io);
+
+ if (c && simd_conn) {
+ g_io_channel_unref(c->io);
+ g_io_channel_shutdown(c->io, TRUE, NULL);
+ g_free(c);
+ simd_conn = NULL;
+ }
+}
+
+/**
+ * simd_conn_init - Initialize connection with Sim Daemon.
+ * @sap_data; Private data of SAP Server.
+ *
+ * Returns:
+ * 0 if success, negative number in case of an error.
+ */
+static int simd_conn_init(void * sap_data)
+{
+ int sock;
+ int len = 0;
+ struct sockaddr_un addr;
+ ssize_t addr_len;
+
+ /* Create a socket to communicate with SIMD*/
+ sock = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (sock < 0) {
+ error("[STE_DRV] Create socket failed: %s", strerror(errno));
+ return -errno;
+ }
+
+ /*Connect to SIMD*/
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ len = sprintf(addr.sun_path, STE_SIM_UNIX_SOCKET_NAME);
+ addr_len = sizeof(addr.sun_family) + len;
+ if (connect(sock, (struct sockaddr *) &addr, addr_len) < 0) {
+ error("[STE_DRV] Connect to the socket failed: %s",
+ strerror(errno));
+ goto drop;
+ }
+
+ if (fcntl(sock, F_SETFL, O_NONBLOCK) > 0) {
+ error("[STE_DRV] fcntl() failed: %s", strerror(errno));
+ goto drop;
+ }
+
+ debug("[STE_DRV] simd_conn_init: sock %d ",sock);
+
+ /* Start watching incoming data */
+ if (simd_conn_watch(sock, sap_data) < 0)
+ goto drop;
+
+ return 0;
+
+drop:
+ debug("[STE_DRV] simd_conn_init: drop!");
+ close(sock);
+ return -errno;
+}
+
+/**
+ * simd_conn_uninit - Disconnect from Sim daemon.
+ * @c; Connection info structure.
+ */
+static void simd_conn_uninit(struct ste_sim_connection *c)
+{
+ debug("[STE_DRV] simd_conn_uninit: c %p simd_conn %p", c, simd_conn);
+
+ if (!c)
+ return;
+
+ g_io_channel_shutdown(c->io, TRUE, NULL);
+ g_io_channel_unref(c->io);
+ g_free(c);
+
+ simd_conn = NULL;
+}
+
+
+/**
+ * simd_conn_watch - Start watching Sim daemon connection.
+ * @sap_data; Private data of SAP Server.
+ *
+ * Returns:
+ * 0 if success, negative number in case of an error.
+ */
+static int simd_conn_watch(int sock, void *sap_data)
+{
+ GIOChannel *io = NULL;
+
+ debug("[STE_DRV] simd_conn_watch: sock %d, sap_data %p ", sock,
+ sap_data);
+
+ if (sock < 0)
+ return -1;
+
+ io = g_io_channel_unix_new(sock);
+ g_io_channel_set_close_on_unref(io, TRUE);
+
+
+ simd_conn = g_new0(struct ste_sim_connection, 1);
+ if (!simd_conn) {
+ error("[STE_DRV] simd_conn_watch: simd_conn %p io %p",
+ simd_conn, io);
+ g_io_channel_shutdown(io, TRUE, NULL);
+ g_io_channel_unref(io);
+ return -1;
+ }
+
+ simd_conn->io = io;
+ simd_conn->sap_data = sap_data;
+ simd_conn->state = STE_SIM_DISABLED;
+
+ g_io_add_watch_full(io, G_PRIORITY_DEFAULT,
+ G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ simd_io_data_cb, simd_conn, simd_io_destroy_cb);
+
+ return 0;
+}
+
+/**
+ * sap_connect_req - Handle SAP connect request.
+ * @sap_data; Private data of SAP Server.
+ * @maxmsgsize; Message size supported by the SAP client.
+ */
+void sap_connect_req(void *sap_device, uint16_t maxmsgsize)
+{
+
+ debug("[STE_DRV] sap_connect_req: conn %p sap_device %p maxmsgsize %d",
+ simd_conn, sap_device, maxmsgsize);
+
+ if (maxmsgsize < STE_SIM_MIN_MSG_SIZE) {
+ sap_connect_rsp(sap_device, SAP_STATUS_MAX_MSG_SIZE_TOO_SMALL,
+ STE_SIM_MAX_MSG_SIZE);
+ return;
+ }
+
+ if (maxmsgsize > STE_SIM_MAX_MSG_SIZE) {
+ sap_connect_rsp(sap_device, SAP_STATUS_MAX_MSG_SIZE_NOT_SUPPORTED,
+ STE_SIM_MAX_MSG_SIZE);
+ return;
+ }
+
+ if (simd_conn_init(sap_device) < 0) {
+ debug("[STE_DRV] simd_conn_init: failed!");
+ sap_connect_rsp(sap_device, SAP_STATUS_CONNECTION_FAILED, 0);
+ return;
+ }
+
+ if (simd_conn && simd_conn->state == STE_SIM_DISABLED) {
+ if (ste_sim_start_sap_req(simd_conn) < 0) {
+ sap_connect_rsp(sap_device, SAP_STATUS_CONNECTION_FAILED,
+ STE_SIM_MAX_MSG_SIZE);
+ simd_conn_uninit(simd_conn);
+ }
+ } else {
+ debug("[STE_DRV] Connection failed! (simd_conn %p) ", simd_conn);
+ sap_connect_rsp(sap_device, SAP_STATUS_CONNECTION_FAILED, 0);
+ }
+}
+
+/**
+ * sap_disconnect_req - Handle SAP disconnect request.
+ * @sap_data; Private data of SAP Server.
+ * @linkloss; Indicates thet link is being disconnected due to link loss.
+ */
+void sap_disconnect_req(void *sap_device, uint8_t linkloss)
+{
+ debug("[STE_DRV] sap_disconnect_req: conn %p sap_device %p linkloss %d",
+ simd_conn, sap_device, linkloss);
+ if (simd_conn && linkloss) {
+ simd_conn_uninit(simd_conn);
+ return;
+ }
+
+ if (simd_conn && simd_conn->state != STE_SIM_DISABLED) {
+ if (ste_sim_end_sap_req(simd_conn) < 0) {
+ sap_disconnect_rsp(sap_device);
+ }
+ } else {
+ sap_disconnect_rsp(sap_device);
+ }
+}
+
+/**
+ * sap_transfer_apdu_req - Handle SAP transfer apdu request.
+ * @sap_data; Private data of SAP Server.
+ * @param; SAP parameter of the request.
+ */
+void sap_transfer_apdu_req(void *sap_device, sap_parameter *param)
+{
+ sap_result_t sr;
+
+ debug("[STE_DRV] sap_transfer_apdu_req: conn %p sap_device %p param %p\
+ param len %d", simd_conn, sap_device, param, param->len);
+
+ if (simd_conn && simd_conn->state == STE_SIM_ENABLED) {
+ if (ste_sim_send_apdu_req(simd_conn, param) < 0)
+ sap_transfer_apdu_rsp(sap_device,
+ SAP_RESULT_ERROR_NO_REASON, NULL, 0);
+ } else {
+ sr = get_sap_result(simd_conn, STE_SIM_SEND_APDU_MSG,
+ STE_SIM_STATUS_UNDEFINED_FAILURE);
+ sap_transfer_apdu_rsp(sap_device, sr, NULL, 0);
+ }
+}
+
+/**
+ * sap_transfer_atr_req - Handle SAP ATR request.
+ * @sap_data; Private data of SAP Server.
+ */
+void sap_transfer_atr_req(void * sap_device)
+{
+ sap_result_t sr;
+
+ debug("[STE_DRV] sap_transfer_atr_req: conn %p, sap_device %p",
+ simd_conn, sap_device);
+
+ if (simd_conn && simd_conn->state == STE_SIM_ENABLED) {
+ if (ste_sim_get_atr_req(simd_conn) < 0)
+ sap_transfer_atr_rsp(sap_device,
+ SAP_RESULT_ERROR_NO_DATA, NULL, 0);
+ } else {
+ sr = get_sap_result(simd_conn, STE_SIM_GET_ATR_MSG,
+ STE_SIM_STATUS_UNDEFINED_FAILURE);
+ sap_transfer_atr_rsp(sap_device, sr, NULL, 0);
+ }
+}
+
+/**
+ * sap_power_sim_off_req - Handle SAP power off request.
+ * @sap_data; Private data of SAP Server.
+ */
+void sap_power_sim_off_req(void *sap_device)
+{
+ sap_result_t sr;
+
+ debug("[STE_DRV] sap_power_sim_off_req: conn %p, sap_device %p",
+ simd_conn, sap_device);
+
+ if (simd_conn && simd_conn->state == STE_SIM_ENABLED) {
+ if (ste_sim_power_off_req(simd_conn) < 0)
+ sap_power_sim_off_rsp(sap_device,
+ SAP_RESULT_ERROR_NO_REASON);
+ } else {
+ sr = get_sap_result(simd_conn, STE_SIM_POWER_OFF_MSG,
+ STE_SIM_STATUS_UNDEFINED_FAILURE);
+ sap_power_sim_off_rsp(sap_device, sr);
+ }
+}
+
+/**
+ * sap_power_sim_on_req - Handle SAP power on request.
+ * @sap_data; Private data of SAP Server.
+ */
+void sap_power_sim_on_req(void *sap_device)
+{
+ sap_result_t sr;
+
+ debug("[STE_DRV] sap_power_sim_on_req: conn %p, sap_device %p",
+ simd_conn, sap_device);
+
+ if (simd_conn && simd_conn->state == STE_SIM_POWERED_OFF) {
+ if (ste_sim_power_on_req(simd_conn) < 0)
+ sap_power_sim_on_rsp(sap_device,
+ SAP_RESULT_ERROR_NO_REASON);
+ } else {
+ sr = get_sap_result(simd_conn, STE_SIM_POWER_ON_MSG,
+ STE_SIM_STATUS_UNDEFINED_FAILURE);
+ sap_power_sim_on_rsp(sap_device, sr);
+ }
+}
+
+/**
+ * sap_reset_sim_req - Handle SAP reset request.
+ * @sap_data; Private data of SAP Server.
+ */
+void sap_reset_sim_req(void *sap_device)
+{
+ sap_result_t sr;
+
+ debug("[STE_DRV] sap_reset_sim_req: conn %p, sap_device %p",
+ simd_conn, sap_device);
+
+ if (simd_conn && simd_conn->state == STE_SIM_ENABLED) {
+ if (ste_sim_reset_req(simd_conn) < 0)
+ sap_reset_sim_rsp(sap_device,
+ SAP_RESULT_ERROR_NO_REASON);
+ } else {
+ sr = get_sap_result(simd_conn, STE_SIM_RESET_MSG,
+ STE_SIM_STATUS_UNDEFINED_FAILURE);
+ sap_reset_sim_rsp(sap_device, sr);
+ }
+}
+
+/**
+ * sap_transfer_card_reader_status_req - Handle get card reader status request.
+ * @sap_data; Private data of SAP Server.
+ */
+void sap_transfer_card_reader_status_req(void * sap_device)
+{
+ sap_result_t sr;
+
+ debug("[STE_DRV] sap_transfer_card_reader_status_req: conn %p, \
+ sap_device %p", simd_conn, sap_device);
+
+ if (simd_conn && simd_conn->state != STE_SIM_DISABLED) {
+ if (ste_sim_get_status_req(simd_conn) < 0)
+ sap_transfer_card_reader_status_rsp(sap_device,
+ SAP_RESULT_ERROR_NO_DATA,
+ ICC_READER_UNSPECIFIED_ERROR);
+ } else {
+ sr = get_sap_result(simd_conn, STE_SIM_GET_STATUS_MSG,
+ STE_SIM_STATUS_UNDEFINED_FAILURE);
+ sap_transfer_card_reader_status_rsp(sap_device, sr,
+ ICC_READER_UNSPECIFIED_ERROR);
+ }
+}
+
+/**
+ * sap_set_transport_protocol_req - Handle set transport protocol request.
+ * @sap_data; Private data of SAP Server.
+ */
+void sap_set_transport_protocol_req(void * sap_device,sap_parameter * param)
+{
+ debug("[STE_DRV] Not supported.");
+}
+
diff --git a/sap/sap.h b/sap/sap.h
new file mode 100644
index 0000000..d0a1b99
--- /dev/null
+++ b/sap/sap.h
@@ -0,0 +1,200 @@
+/*
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 ST-Ericsson SA
+ * Copyright (C) 2010 Claudio Takahasi<claudio.takahasi@openbossa.org>
+ *
+ * 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.
+ *
+ * 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
+ */
+
+/* SAP 1.1 section 5.2.2 */
+typedef enum {
+ SAP_STATUS_OK = 0x00,
+ SAP_STATUS_CONNECTION_FAILED = 0x01,
+ SAP_STATUS_MAX_MSG_SIZE_NOT_SUPPORTED = 0x02,
+ SAP_STATUS_MAX_MSG_SIZE_TOO_SMALL = 0x03,
+ SAP_STATUS_OK_ONGOING_CALL = 0x04
+} sap_status_t;
+
+/* SAP 1.1 section 5.2.3 */
+typedef enum {
+ SAP_DISCONNECTION_TYPE_GRACEFUL = 0x00,
+ SAP_DISCONNECTION_TYPE_IMMEDIATE = 0x01,
+ SAP_DISCONNECTION_TYPE_CLIENT = 0xFF
+} sap_disconnection_type_t;
+
+/* SAP 1.1 section 5.2.4 */
+typedef enum {
+ SAP_RESULT_OK = 0x00,
+ SAP_RESULT_ERROR_NO_REASON = 0x01,
+ SAP_RESULT_ERROR_NOT_ACCESSIBLE = 0x02,
+ SAP_RESULT_ERROR_POWERED_OFF = 0x03,
+ SAP_RESULT_ERROR_CARD_REMOVED = 0x04,
+ SAP_RESULT_ERROR_POWERED_ON = 0x05,
+ SAP_RESULT_ERROR_NO_DATA = 0x06,
+ SAP_RESULT_NOT_SUPPORTED = 0x07
+} sap_result_t;
+
+/* SAP 1.1 section 5.2.8 Status Change */
+typedef enum {
+ SAP_STATUS_CHANGE_UNKNOWN_ERROR = 0x00,
+ SAP_STATUS_CHANGE_CARD_RESET = 0x01,
+ SAP_STATUS_CHANGE_CARD_NOT_ACCESSIBLE = 0x02,
+ SAP_STATUS_CHANGE_CARD_REMOVED = 0x03,
+ SAP_STATUS_CHANGE_CARD_INSERTED = 0x04,
+ SAP_STATUS_CHANGE_CARD_RECOVERED = 0x05
+} sap_status_change_t;
+
+
+/* SAP 1.1 section 5.1 Message formats */
+typedef struct {
+ uint8_t id;
+ uint8_t reserved;
+ uint16_t len;
+ uint8_t val[0];
+ /*
+ * Padding bytes 0-3 bytes
+ */
+} __attribute__ ((packed)) sap_parameter;
+
+typedef struct {
+ uint8_t id;
+ uint8_t nparam;
+ uint16_t reserved;
+ sap_parameter param[0];
+} __attribute__ ((packed)) sap_message;
+
+
+typedef enum {
+ ICC_READER_UNSPECIFIED_ERROR, /* No further information available */
+ ICC_READER_NOT_PRESENT, /* Card Reader removed or not present */
+ ICC_READER_BUSY, /* Card Reader in use */
+ ICC_READER_CARD_POWERED_ON, /* Card in reader and is powered on */
+ ICC_READER_DEACTIVATED, /* Card Reader deactivated */
+ ICC_READER_CARD_POWERED_OFF, /* Card in reader, but powered off */
+ ICC_READER_NO_CARD, /* No card in reader */
+ ICC_READER_LAST
+} icc_reader_status_t;
+
+
+#define SAP_BUF_SIZE 512
+
+#define SAP_MSG_HEADER_SIZE 4
+
+typedef enum {
+ SAP_CONNECT_REQ = 0x00, /* Client -> Server */
+ SAP_CONNECT_RESP = 0x01, /* Server -> Client */
+
+ SAP_DISCONNECT_REQ = 0x02, /* Client -> Server */
+ SAP_DISCONNECT_RESP = 0x03, /* Server -> Client */
+ SAP_DISCONNECT_IND = 0x04, /* Server -> Client */
+
+ SAP_TRANSFER_APDU_REQ = 0x05, /* Client -> Server */
+ SAP_TRANSFER_APDU_RESP = 0x06, /* Server -> Client */
+
+ SAP_TRANSFER_ATR_REQ = 0x07, /* Client -> Server */
+ SAP_TRANSFER_ATR_RESP = 0x08, /* Server -> Client */
+
+ SAP_POWER_SIM_OFF_REQ = 0x09, /* Client -> Server */
+ SAP_POWER_SIM_OFF_RESP = 0x0A, /* Server -> Client */
+
+ SAP_POWER_SIM_ON_REQ = 0x0B, /* Client -> Server */
+ SAP_POWER_SIM_ON_RESP = 0x0C, /* Server -> Client */
+
+ SAP_RESET_SIM_REQ = 0x0D, /* Client -> Server */
+ SAP_RESET_SIM_RESP = 0x0E, /* Server -> Client */
+
+ SAP_TRANSFER_CARD_READER_STATUS_REQ = 0x0F, /* Client -> Server */
+ SAP_TRANSFER_CARD_READER_STATUS_RESP = 0x10, /* Server -> Client */
+
+ SAP_STATUS_IND = 0x11, /* Server -> Client */
+ SAP_ERROR_RESP = 0x12, /* Server -> Client */
+
+ SAP_SET_TRANSPORT_PROTOCOL_REQ = 0x13, /* Client -> Server */
+ SAP_SET_TRANSPORT_PROTOCOL_RESP = 0x14, /* Server -> Client */
+} sap_protocol;
+
+/* SAP 1.1 section 5.2 Parameters IDs and Coding */
+#define SAP_PARAM_ID_MAXMSGSIZE 0x00
+#define SAP_PARAM_ID_MAXMSGSIZE_LEN 0x02
+
+#define SAP_PARAM_ID_CONN_STATUS 0x01
+#define SAP_PARAM_ID_CONN_STATUS_LEN 0x01
+
+#define SAP_PARAM_ID_RESULT_CODE 0x02
+#define SAP_PARAM_ID_RESULT_CODE_LEN 0x01
+
+#define SAP_PARAM_ID_DISCONNECT_IND 0x03
+#define SAP_PARAM_ID_DISCONNECT_IND_LEN 0x01
+
+#define SAP_PARAM_ID_COMMAND_APDU 0x04
+
+#define SAP_PARAM_ID_RESPONSE_APDU 0x05
+
+#define SAP_PARAM_ID_ATR 0x06
+
+#define SAP_PARAM_ID_CARD_READER_STATUS 0x07
+#define SAP_PARAM_ID_CARD_READER_STATUS_LEN 0x01
+
+#define SAP_PARAM_ID_STATUS_CHANGE 0x08
+#define SAP_PARAM_ID_STATUS_CHANGE_LEN 0x01
+
+#define SAP_PARAM_ID_TRANSPORT_PROTOCOL 0x09
+#define SAP_PARAM_ID_TRANSPORT_PROTOCOL_LEN 0x01
+
+#define SAP_PARAM_ID_COMMAND_APDU7816 0x10
+
+/* SAP 1.1 section 5.2.9 Possible Values for TransportProtocol */
+#define SAP_TRANSPORT_PROTOCOL_T0 0x00
+#define SAP_TRANSPORT_PROTOCOL_T1 0x01
+
+
+/*
+ * Drivers must implement the following functions.
+ * Blocking operations are not allowed, results must be
+ * reported using the functions defined in the next section.
+ * Functions implemented on sap.c
+ */
+void sap_connect_req(void *sap_device, uint16_t maxmsgsize);
+void sap_disconnect_req(void *sap_device, uint8_t linkloss);
+void sap_transfer_apdu_req(void *sap_device, sap_parameter *param);
+void sap_transfer_atr_req(void *sap_device);
+void sap_power_sim_off_req(void *sap_device);
+void sap_power_sim_on_req(void *sap_device);
+void sap_reset_sim_req(void *sap_device);
+void sap_transfer_card_reader_status_req(void *sap_device);
+void sap_set_transport_protocol_req(void *sap_device, sap_parameter *param);
+
+
+/*
+ * Drivers must use the following functions to report operation results.
+ * Functions implemented on server.c
+ */
+int sap_connect_rsp(void *sap_device, sap_status_t status, uint16_t maxmsgsize);
+int sap_disconnect_rsp(void *sap_device);
+int sap_transfer_apdu_rsp(void *sap_device, sap_result_t result, uint8_t *sap_apdu_resp, uint16_t length);
+int sap_transfer_atr_rsp(void *sap_device, sap_result_t result, uint8_t *sap_atr, uint16_t length);
+int sap_power_sim_off_rsp(void *sap_device, sap_result_t result);
+int sap_power_sim_on_rsp(void *sap_device, sap_result_t result);
+int sap_reset_sim_rsp(void *sap_device, sap_result_t result);
+int sap_transfer_card_reader_status_rsp(void *sap_device, sap_result_t result, icc_reader_status_t status);
+int sap_error_rsp(void *sap_device);
+int sap_transport_protocol_resp(void *sap_device, sap_result_t resul);
+
+/*
+ * Asynchronous Driver events notification.
+ * Functions implemented on server.c
+ */
+int sap_status_ind(void *sap_device, sap_status_change_t status_change);
+
diff --git a/sap/server.c b/sap/server.c
new file mode 100644
index 0000000..a8d098a
--- /dev/null
+++ b/sap/server.c
@@ -0,0 +1,1459 @@
+/*
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 ST-Ericsson SA
+ * Copyright (C) 2010 Claudio Takahasi<claudio.takahasi@openbossa.org>
+ *
+ * Author: Marek Skowron <marek.skowron@tieto.com> for ST-Ericsson.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+#include <assert.h>
+#include <glib.h>
+#include <gdbus.h>
+
+#include "adapter.h"
+#include "dbus-common.h"
+#include "btio.h"
+#include "sdpd.h"
+
+#include "logging.h"
+#include "error.h"
+
+#include "sap.h"
+#include "server.h"
+
+#define SAP_PROFILE_VERSION 0x0101
+
+#define SAP_SERVER_INTERFACE "org.bluez.SimAccess"
+#define SAP_SERVER_CHANNEL 8
+#define SAP_UUID "0000112D-0000-1000-8000-00805F9B34FB"
+#define SAP_BUF_SIZE 512
+#define PADDING4(x) (4 - (x & 0x03))
+#define PARAMETER_SIZE(x) (sizeof(sap_parameter) + x + PADDING4(x))
+
+#define SAP_NO_REQ 0xFF
+
+#define SAP_TIMER_GRACEFUL_DISCONNECT 30
+#define SAP_TIMER_NO_ACTIVITY 30
+
+typedef enum {
+ SAP_STATE_DISCONNECTED,
+ SAP_STATE_CONNECT_IN_PROGRESS,
+ SAP_STATE_CONNECTED,
+ SAP_STATE_GRACEFUL_DISCONNECT,
+ SAP_STATE_IMMEDIATE_DISCONNECT,
+ SAP_STATE_CLIENT_DISCONNECT
+} sap_state_t;
+
+struct sap_server {
+ bdaddr_t src;
+ char *path;
+ gboolean enable; /* Enable flag */
+ uint32_t record_id; /* Service record id */
+ GIOChannel *listen_io;
+ GIOChannel *io; /* Active client channel */
+ sap_state_t state; /* State of the SAP server */
+ uint8_t processing_req; /* Processing request in Connected state */
+ guint timer_id; /* Guard timer */
+};
+
+static DBusConnection *connection = NULL;
+
+static void connect_req(void *data, sap_parameter *param);
+static int disconnect_req(void *data, sap_disconnection_type_t disc_type);
+static void transfer_apdu_req(void *data, sap_parameter *param);
+static void transfer_atr_req(void *data);
+static void power_sim_off_req(void *data);
+static void power_sim_on_req(void *data);
+static void reset_sim_req(void *data);
+static void transfer_card_reader_status_req(void *data);
+static void set_transport_protocol_req(void *data, sap_parameter *param);
+static int disconnect_ind(void *sap_device, sap_disconnection_type_t type);
+
+static gsize add_result_parameter(sap_result_t result, sap_parameter *param);
+
+static int is_power_sim_off_req_allowed(uint8_t processing_req);
+static int is_reset_sim_req_allowed(uint8_t processing_req);
+
+static int check_msg(sap_message *msg);
+
+static void start_guard_timer(struct sap_server *ss, guint interval);
+static void stop_guard_timer(struct sap_server *ss);
+static gboolean guard_timeout(gpointer data);
+
+static gsize add_result_parameter(sap_result_t result, sap_parameter *param)
+{
+ param->id = SAP_PARAM_ID_RESULT_CODE;
+ param->len = htons(SAP_PARAM_ID_RESULT_CODE_LEN);
+ *param->val = (uint8_t) result;
+ return PARAMETER_SIZE(SAP_PARAM_ID_RESULT_CODE_LEN);
+}
+
+
+static inline 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 inline 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(sap_message *msg)
+{
+ assert(msg);
+
+ switch(msg->id) {
+ case SAP_CONNECT_REQ:
+ if (msg->nparam == 0x01 &&
+ msg->param->id == SAP_PARAM_ID_MAXMSGSIZE &&
+ ntohs(msg->param->len) == SAP_PARAM_ID_MAXMSGSIZE_LEN)
+ return 0;
+ break;
+ case SAP_TRANSFER_APDU_REQ:
+ if (msg->nparam == 0x01 &&
+ (msg->param->id == SAP_PARAM_ID_COMMAND_APDU ||
+ msg->param->id == SAP_PARAM_ID_COMMAND_APDU7816) &&
+ msg->param->len != 0x00)
+ return 0;
+ break;
+ case SAP_SET_TRANSPORT_PROTOCOL_REQ:
+ if (msg->nparam == 0x01 &&
+ msg->param->id == SAP_PARAM_ID_TRANSPORT_PROTOCOL &&
+ ntohs(msg->param->len) == SAP_PARAM_ID_TRANSPORT_PROTOCOL_LEN &&
+ (*msg->param->val == SAP_TRANSPORT_PROTOCOL_T0 ||
+ *msg->param->val == SAP_TRANSPORT_PROTOCOL_T1))
+ return 0;
+ break;
+ case SAP_DISCONNECT_REQ:
+ case SAP_TRANSFER_ATR_REQ:
+ case SAP_POWER_SIM_OFF_REQ:
+ case SAP_POWER_SIM_ON_REQ:
+ case SAP_RESET_SIM_REQ:
+ case SAP_TRANSFER_CARD_READER_STATUS_REQ:
+ if (msg->nparam == 0x00)
+ return 0;
+ break;
+ }
+
+ error("Invalid message");
+ return -EBADMSG;
+}
+
+
+static void start_guard_timer(struct sap_server *ss, guint interval)
+{
+ assert(ss);
+
+ if (!ss->timer_id)
+ ss->timer_id = g_timeout_add_seconds(interval, guard_timeout, ss);
+ else
+ error("[%s::%s] Timer is already active", __FILE__, __FUNCTION__);
+}
+
+static void stop_guard_timer(struct sap_server *ss)
+{
+ if (ss && ss->timer_id) {
+ g_source_remove(ss->timer_id);
+ ss->timer_id = 0x00;
+ }
+}
+
+static gboolean guard_timeout(gpointer data)
+{
+ struct sap_server *ss = data;
+
+ assert(ss);
+
+ debug("[%s::%s] state: %#x processing_req: %#x",
+ __FILE__, __FUNCTION__, ss->state, ss->processing_req);
+
+ /* Set timer ID to zero because timer will be destroyed. */
+ ss->timer_id = 0;
+
+ switch(ss->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. Shutdown RFCOMM channel immediately. */
+ if (ss->io)
+ g_io_channel_shutdown(ss->io, TRUE, NULL);
+ break;
+ case SAP_STATE_GRACEFUL_DISCONNECT:
+ /* Client didn't disconnect SAP connection in fixed time,
+ * so close SAP connection immediately. */
+ disconnect_req(ss, SAP_DISCONNECTION_TYPE_IMMEDIATE);
+ break;
+ default:
+ error("[%s::%s] Unexpected state: %#x processing_req: %#x",
+ __FILE__, __FUNCTION__, ss->state, ss->processing_req);
+ break;
+ }
+
+ return FALSE;
+}
+
+static void server_free(struct sap_server *ss)
+{
+ if (!ss)
+ return;
+
+ g_free(ss->path);
+ g_free(ss);
+ debug("[%s::%s]", __FILE__, __FUNCTION__);
+}
+
+static sdp_record_t *sap_record(uint8_t channel)
+{
+ sdp_list_t *apseq, *aproto, *profiles, *proto[2], *root, *svclass_id;
+ uuid_t sap_uuid, gt_uuid, root_uuid, l2cap, rfcomm;
+ sdp_profile_desc_t profile;
+ sdp_record_t *record;
+ sdp_data_t *ch;
+
+ record = sdp_record_alloc();
+ if (!record)
+ return NULL;
+
+ root = sdp_list_append(NULL, &root_uuid);
+ sdp_set_browse_groups(record, root);
+ sdp_list_free(root, NULL);
+
+ sdp_uuid16_create(&sap_uuid, SAP_SVCLASS_ID);
+ svclass_id = sdp_list_append(NULL, &sap_uuid);
+ sdp_uuid16_create(>_uuid, GENERIC_TELEPHONY_SVCLASS_ID);
+ svclass_id = sdp_list_append(svclass_id, >_uuid);
+
+ sdp_set_service_classes(record, svclass_id);
+ sdp_list_free(svclass_id, NULL);
+
+ sdp_uuid16_create(&profile.uuid, SAP_PROFILE_ID);
+ profile.version = SAP_PROFILE_VERSION;
+ profiles = sdp_list_append(NULL, &profile);
+ sdp_set_profile_descs(record, profiles);
+ sdp_list_free(profiles, NULL);
+
+ sdp_uuid16_create(&l2cap, L2CAP_UUID);
+ proto[0] = sdp_list_append(NULL, &l2cap);
+ apseq = sdp_list_append(NULL, proto[0]);
+
+ sdp_uuid16_create(&rfcomm, RFCOMM_UUID);
+ proto[1] = sdp_list_append(NULL, &rfcomm);
+ ch = sdp_data_alloc(SDP_UINT8, &channel);
+ proto[1] = sdp_list_append(proto[1], ch);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ aproto = sdp_list_append(NULL, apseq);
+ sdp_set_access_protos(record, aproto);
+
+ sdp_set_info_attr(record, "SIM Access Server",
+ NULL, NULL);
+
+ sdp_data_free(ch);
+ sdp_list_free(proto[0], NULL);
+ sdp_list_free(proto[1], NULL);
+ sdp_list_free(apseq, NULL);
+ sdp_list_free(aproto, NULL);
+
+ return record;
+}
+
+static int send_message(struct sap_server *ss,
+ unsigned char *buf, gsize size)
+{
+ gsize written = 0;
+ GIOError gerr;
+
+ assert(ss && buf);
+
+ debug("[%s::%s] size=%#x", __FILE__, __FUNCTION__, (unsigned int)size);
+ gerr = g_io_channel_write(ss->io, (const gchar *) buf, size, &written);
+ debug("[%s::%s] written=%#x", __FILE__, __FUNCTION__, (unsigned int)written);
+ if (gerr != G_IO_ERROR_NONE) {
+ int err = errno;
+ error("write error: %s(%d)", strerror(err), err);
+ return -err;
+ }
+
+ return 0;
+}
+
+static void connect_req(void *data, sap_parameter *param)
+{
+ struct sap_server *ss = data;
+ uint16_t maxmsgsize, *val;
+
+ assert(ss && param);
+
+ if (ss->state != SAP_STATE_DISCONNECTED)
+ goto error_rsp;
+
+ stop_guard_timer(ss);
+
+ val = (uint16_t *) ¶m->val;
+ maxmsgsize = ntohs(*val);
+
+ debug("Connect MaxMsgSize: 0x%04X(%d)", maxmsgsize, maxmsgsize);
+
+ ss->state = SAP_STATE_CONNECT_IN_PROGRESS;
+
+ if (maxmsgsize <= SAP_BUF_SIZE){
+ ss->processing_req = SAP_CONNECT_REQ;
+ sap_connect_req(ss, maxmsgsize);
+ }else{
+ sap_connect_rsp(ss, SAP_STATUS_MAX_MSG_SIZE_NOT_SUPPORTED, htons(SAP_BUF_SIZE));
+ }
+
+ return;
+
+error_rsp:
+ error("Unexpected request state: %#x processing_req: %#x", ss->state, ss->processing_req);
+ sap_error_rsp(data);
+}
+
+static int disconnect_req(void *data, sap_disconnection_type_t disc_type)
+{
+ struct sap_server *ss = data;
+
+ assert(ss);
+ debug("disconnect_req: type 0x%x state %d", disc_type, ss->state);
+
+ switch(disc_type) {
+ case SAP_DISCONNECTION_TYPE_GRACEFUL:
+
+ if (ss->state == SAP_STATE_DISCONNECTED || ss->state == SAP_STATE_CONNECT_IN_PROGRESS)
+ goto error_req;
+
+ if (ss->state == SAP_STATE_CONNECTED) {
+ ss->state = SAP_STATE_GRACEFUL_DISCONNECT;
+ ss->processing_req = SAP_NO_REQ;
+ disconnect_ind(ss, disc_type);
+
+ /* Start guard timer - timer will disconnect connection if client doesn't do it. */
+ start_guard_timer(ss, SAP_TIMER_GRACEFUL_DISCONNECT);
+
+ return 0;
+ }
+
+ /* Disconnection is ongoing - do nothing. */
+ return 0;
+
+ case SAP_DISCONNECTION_TYPE_IMMEDIATE:
+
+ if (ss->state == SAP_STATE_DISCONNECTED || ss->state == SAP_STATE_CONNECT_IN_PROGRESS)
+ goto error_req;
+
+ if (ss->state == SAP_STATE_CONNECTED ||
+ ss->state == SAP_STATE_GRACEFUL_DISCONNECT) {
+ ss->state = SAP_STATE_IMMEDIATE_DISCONNECT;
+ ss->processing_req = SAP_NO_REQ;
+
+ /* Stop timer if it is run. */
+ stop_guard_timer(ss);
+
+ disconnect_ind(ss, disc_type);
+ sap_disconnect_req(ss, 0);
+
+ return 0;
+ }
+
+ /* Disconnection is ongoing - do nothing. */
+ return 0;
+
+ case SAP_DISCONNECTION_TYPE_CLIENT:
+
+ if (ss->state != SAP_STATE_CONNECTED && ss->state != SAP_STATE_GRACEFUL_DISCONNECT)
+ goto error_rsp;
+
+ ss->state = SAP_STATE_CLIENT_DISCONNECT;
+ ss->processing_req = SAP_NO_REQ;
+
+ /* Stop timer if it is run. */
+ stop_guard_timer(ss);
+
+ sap_disconnect_req(ss, 0);
+
+ return 0;
+
+ default:
+ error("Unexpected disconnection type: %#x", disc_type);
+ return -EINVAL;
+ }
+
+error_rsp:
+ sap_error_rsp(ss);
+error_req:
+ error("Unexpected request state: %#x processing_req: %#x", ss->state, ss->processing_req);
+ return -EPERM;
+}
+
+static void transfer_apdu_req(void * data, sap_parameter * param)
+{
+ struct sap_server *ss = data;
+
+ assert(ss && param);
+ param->len = ntohs(param->len);
+
+ debug("transfer_apdu_req: data %p state %d", data, ss->state);
+ debug("transfer_apdu_req: apdu param id %d val %s len %d ", param->id, param->val, param->len);
+
+ if (ss->state != SAP_STATE_CONNECTED && ss->state != SAP_STATE_GRACEFUL_DISCONNECT)
+ goto error_rsp;
+
+ if (ss->processing_req != SAP_NO_REQ)
+ goto error_rsp;
+
+ ss->processing_req = SAP_TRANSFER_APDU_REQ;
+ sap_transfer_apdu_req(ss, param);
+
+ return;
+
+error_rsp:
+ error("Unexpected request state: %#x processing_req: %#x", ss->state, ss->processing_req);
+ sap_error_rsp(ss);
+}
+
+
+static void transfer_atr_req(void * data)
+{
+ struct sap_server *ss = data;
+
+ assert(ss);
+ debug("transfer_atr_req: data %p state %d", data, ss->state);
+
+ if (ss->state != SAP_STATE_CONNECTED)
+ goto error_rsp;
+
+ if (ss->processing_req != SAP_NO_REQ)
+ goto error_rsp;
+
+ ss->processing_req = SAP_TRANSFER_ATR_REQ;
+ sap_transfer_atr_req(ss);
+
+ return;
+
+error_rsp:
+ error("Unexpected request state: %#x processing_req: %#x", ss->state, ss->processing_req);
+ sap_error_rsp(ss);
+}
+
+
+static void power_sim_off_req(void *data)
+{
+ struct sap_server *ss = data;
+
+ assert(ss);
+ debug("power_sim_off_req: data %p state %d", data, ss->state);
+
+ if (ss->state != SAP_STATE_CONNECTED)
+ goto error_rsp;
+
+ if (!is_power_sim_off_req_allowed(ss->processing_req))
+ goto error_rsp;
+
+ ss->processing_req = SAP_POWER_SIM_OFF_REQ;
+ sap_power_sim_off_req(ss);
+
+ return;
+
+error_rsp:
+ error("Unexpected request state: %#x processing_req: %#x", ss->state, ss->processing_req);
+ sap_error_rsp(ss);
+}
+
+static void power_sim_on_req(void *data)
+{
+ struct sap_server *ss = data;
+
+ assert(ss);
+ debug("power_sim_on_req: data %p state %d", data, ss->state);
+
+ if (ss->state != SAP_STATE_CONNECTED)
+ goto error_rsp;
+
+ if (ss->processing_req != SAP_NO_REQ)
+ goto error_rsp;
+
+ ss->processing_req = SAP_POWER_SIM_ON_REQ;
+ sap_power_sim_on_req(ss);
+
+ return;
+
+error_rsp:
+ error("Unexpected request state: %#x processing_req: %#x", ss->state, ss->processing_req);
+ sap_error_rsp(ss);
+}
+
+static void reset_sim_req(void *data)
+{
+ struct sap_server *ss = data;
+
+ assert(ss);
+ debug("reset_sim_req: data %p state %d", data, ss->state);
+
+ if (ss->state != SAP_STATE_CONNECTED)
+ goto error_rsp;
+
+ if (!is_reset_sim_req_allowed(ss->processing_req))
+ goto error_rsp;
+
+ ss->processing_req = SAP_RESET_SIM_REQ;
+ sap_reset_sim_req(ss);
+
+ return;
+
+error_rsp:
+ error("Unexpected request state: %#x processing_req: %#x", ss->state, ss->processing_req);
+ sap_error_rsp(ss);
+}
+
+static void transfer_card_reader_status_req(void * data)
+{
+ struct sap_server *ss = data;
+
+ assert(ss);
+ debug("transfer_card_reader_status_req: data %p state %d", data, ss->state);
+
+
+ if (ss->state != SAP_STATE_CONNECTED)
+ goto error_rsp;
+
+ if (ss->processing_req != SAP_NO_REQ)
+ goto error_rsp;
+
+ ss->processing_req = SAP_TRANSFER_CARD_READER_STATUS_REQ;
+ sap_transfer_card_reader_status_req(ss);
+
+ return;
+
+error_rsp:
+ error("Unexpected request state: %#x processing_req: %#x", ss->state, ss->processing_req);
+ sap_error_rsp(ss);
+}
+
+static void set_transport_protocol_req(void *data, sap_parameter *param)
+{
+ struct sap_server *ss = data;
+
+ assert(ss && param);
+ debug("set_transport_protocol_req: data %p state %d param %p", data, ss->state, param);
+
+ if (ss->state != SAP_STATE_CONNECTED)
+ goto error_rsp;
+
+ if (ss->processing_req != SAP_NO_REQ)
+ goto error_rsp;
+
+ ss->processing_req = SAP_SET_TRANSPORT_PROTOCOL_REQ;
+ sap_set_transport_protocol_req(ss, param);
+
+ return;
+
+error_rsp:
+ error("Unexpected request state: %#x processing_req: %#x", ss->state, ss->processing_req);
+ sap_error_rsp(ss);
+}
+
+static int disconnect_ind(void *sap_device, sap_disconnection_type_t type)
+{
+ struct sap_server *ss = sap_device;
+ unsigned char buf[SAP_BUF_SIZE];
+ sap_message *msg = (sap_message *) buf;
+ sap_parameter *param = (sap_parameter *) msg->param;
+ gsize size = sizeof(sap_message);
+
+ assert(ss);
+ debug("disconnect_ind: data %p state %d disc_type %d", ss, ss->state, type);
+
+
+ if (ss->state != SAP_STATE_CONNECTED && ss->state != SAP_STATE_GRACEFUL_DISCONNECT)
+ goto error_ind;
+
+ if (ss->state == SAP_STATE_GRACEFUL_DISCONNECT && type == SAP_DISCONNECTION_TYPE_GRACEFUL)
+ goto error_ind;
+
+ memset(buf, 0, sizeof(buf));
+ msg->id = SAP_DISCONNECT_IND;
+ msg->nparam = 0x01;
+
+ /* Adding disconnection type. */
+ param->id = SAP_PARAM_ID_DISCONNECT_IND;
+ param->len = htons(SAP_PARAM_ID_DISCONNECT_IND_LEN);
+ *param->val = (uint8_t) type;
+ size += PARAMETER_SIZE(SAP_PARAM_ID_DISCONNECT_IND_LEN);
+
+ debug("[%s::%s] buf=%s size=%#x", __FILE__, __FUNCTION__, buf, (unsigned int)size);
+ return send_message(sap_device, buf, size);
+
+error_ind:
+ error("Unexpected indication state: %#x processing_req: %#x", ss->state, ss->processing_req);
+ return -EPERM;
+}
+
+static int handle_cmd(void *data, unsigned char *buf, gsize size)
+{
+ sap_message *msg = (sap_message *) buf;
+
+ /* Avoiding invalid memory access */
+ if (size < sizeof(sap_message))
+ goto error_rsp;
+
+ /* When number of parameters != 0 make sure that it has the min size */
+ if (msg->nparam != 0 &&
+ size < (sizeof(sap_message) + sizeof(sap_parameter) + 4))
+ goto error_rsp;
+
+ if (check_msg(msg) < 0)
+ goto error_rsp;
+
+ switch(msg->id) {
+ case SAP_CONNECT_REQ:
+ debug("SAP Connect");
+ connect_req(data, msg->param);
+ return 0;
+ case SAP_DISCONNECT_REQ:
+ debug("SAP Disconnect");
+ disconnect_req(data, SAP_DISCONNECTION_TYPE_CLIENT);
+ return 0;
+ case SAP_TRANSFER_APDU_REQ:
+ debug("SAP Transfer APDU");
+ transfer_apdu_req(data, msg->param);
+ return 0;
+ case SAP_TRANSFER_ATR_REQ:
+ debug("SAP Transfer ATR");
+ transfer_atr_req(data);
+ return 0;
+ case SAP_POWER_SIM_OFF_REQ:
+ debug("SAP SIM off");
+ power_sim_off_req(data);
+ return 0;
+ case SAP_POWER_SIM_ON_REQ:
+ debug("SAP SIM on");
+ power_sim_on_req(data);
+ return 0;
+ case SAP_RESET_SIM_REQ:
+ debug("SAP SIM reset");
+ reset_sim_req(data);
+ return 0;
+ case SAP_TRANSFER_CARD_READER_STATUS_REQ:
+ debug("SAP reader status");
+ transfer_card_reader_status_req(data);
+ return 0;
+ case SAP_SET_TRANSPORT_PROTOCOL_REQ:
+ debug("SAP set proto request");
+ set_transport_protocol_req(data, msg->param);
+ return 0;
+ }
+
+error_rsp:
+ debug("SAP ERROR RSP");
+ sap_error_rsp(data);
+ return -EBADMSG;
+}
+
+static gboolean sap_io_cb(GIOChannel *chan, GIOCondition cond, void *data)
+{
+ unsigned char buf[SAP_BUF_SIZE];
+ gsize bytes_read = 0;
+
+ debug("[%s::%s]", __FILE__, __FUNCTION__);
+
+ if (cond & G_IO_NVAL)
+ return FALSE;
+
+ if (cond & G_IO_ERR) {
+ debug("ERR on RFCOMM socket");
+ goto failed;
+ }
+
+ if (cond & G_IO_HUP ) {
+ debug("HUP on RFCOMM socket");
+ goto failed;
+ }
+
+ if (g_io_channel_read(chan, (gchar *) buf, sizeof(buf) - 1,
+ &bytes_read) != G_IO_ERROR_NONE)
+ return TRUE;
+
+ if (handle_cmd(data, buf, bytes_read) < 0) {
+ debug("Invalid SAP message");
+ }
+
+ return TRUE;
+
+failed:
+ return FALSE;
+}
+
+static void sap_io_destroy(void *data)
+{
+ struct sap_server *ss = data;
+
+ assert(ss);
+
+ if (ss && ss->io) {
+ gboolean connected = FALSE;
+
+ /* Stop timer if it is run. */
+ stop_guard_timer(ss);
+
+ g_io_channel_shutdown(ss->io, TRUE, NULL);
+ g_io_channel_unref(ss->io);
+
+ ss->io = NULL;
+
+ if (ss->state != SAP_STATE_CONNECT_IN_PROGRESS)
+ emit_property_changed(connection, ss->path, SAP_SERVER_INTERFACE,
+ "Connected", DBUS_TYPE_BOOLEAN, &connected);
+
+ if (ss->state == SAP_STATE_CONNECT_IN_PROGRESS ||
+ ss->state == SAP_STATE_CONNECTED ||
+ ss->state == SAP_STATE_GRACEFUL_DISCONNECT ){
+ sap_disconnect_req(NULL, 1);
+ }
+
+ ss->state = SAP_STATE_DISCONNECTED;
+ }
+
+ debug("[%s::%s]", __FILE__, __FUNCTION__);
+}
+
+static void sap_connect_cb(GIOChannel *chan, GError *gerr, gpointer data)
+{
+ struct sap_server *ss = data;
+
+ assert(ss);
+
+ debug("[%s::%s]", __FILE__, __FUNCTION__);
+
+ /* Start timer which will shutdown channel if client doesn't send CONNECT_REQ. */
+ start_guard_timer(ss, SAP_TIMER_NO_ACTIVITY);
+
+ g_io_add_watch_full(chan, G_PRIORITY_DEFAULT,
+ G_IO_IN | G_IO_ERR | G_IO_HUP| G_IO_NVAL,
+ (GIOFunc) sap_io_cb, ss, sap_io_destroy);
+}
+
+static void sap_auth_cb(DBusError *derr, void *data)
+{
+ GError *gerr = NULL;
+ struct sap_server *ss = data;
+
+ assert(ss && ss->io);
+
+ debug("[%s::%s]", __FILE__, __FUNCTION__);
+
+ if (derr && dbus_error_is_set(derr)) {
+ error("Access denied: %s", derr->message);
+ goto drop;
+ }
+
+ if (!bt_io_accept(ss->io, sap_connect_cb, ss, NULL, &gerr)) {
+ error("bt_io_accept: %s", gerr->message);
+ g_error_free(gerr);
+ goto drop;
+ }
+ return;
+
+drop:
+ g_io_channel_shutdown(ss->io, TRUE, NULL);
+ g_io_channel_unref(ss->io);
+ ss->io = NULL;
+}
+
+static void connect_confirm(GIOChannel *chan, gpointer data)
+{
+ GError *gerr = NULL;
+ bdaddr_t src, dst;
+ int err;
+ struct sap_server *ss = data;
+
+ assert(chan && ss);
+
+ if (ss->io)
+ goto drop;
+
+ bt_io_get(chan, BT_IO_RFCOMM, &gerr,
+ BT_IO_OPT_SOURCE_BDADDR, &src,
+ BT_IO_OPT_DEST_BDADDR, &dst,
+ BT_IO_OPT_INVALID);
+ if (gerr) {
+ error("%s", gerr->message);
+ g_error_free(gerr);
+ goto drop;
+ }
+
+ ss->io = g_io_channel_ref(chan);
+
+ err = btd_request_authorization(&src, &dst, SAP_UUID, sap_auth_cb, ss);
+
+ if (err < 0) {
+ debug("Authorization denied: %s", strerror(-err));
+ goto drop;
+ }
+
+ debug("[%s::%s] RFCOMM SAP accept socket fd: %#x", __FILE__, __FUNCTION__, g_io_channel_unix_get_fd(chan));
+
+ return;
+
+drop:
+ g_io_channel_shutdown(chan, TRUE, NULL);
+ if (ss->io && ss->io == chan) {
+ g_io_channel_unref(ss->io);
+ ss->io = NULL;
+ }
+}
+
+static void path_unregister(void *data)
+{
+ struct sap_server *ss = data;
+
+ debug("Unregistered interface %s on path %s",
+ SAP_SERVER_INTERFACE, ss->path);
+
+ server_free(ss);
+}
+
+int sap_server_init(DBusConnection *conn)
+{
+ connection = dbus_connection_ref(conn);
+
+ return 0;
+}
+
+void sap_server_exit(void)
+{
+ dbus_connection_unref(connection);
+ connection = NULL;
+}
+
+static inline DBusMessage *invalid_arguments(DBusMessage *msg,
+ const char *description)
+{
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".InvalidArguments",
+ description);
+}
+
+static DBusMessage *enable(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct sap_server *ss = data;
+ sdp_record_t *record;
+ GIOChannel *io;
+ GError *gerr = NULL;
+ gboolean master = TRUE;
+ uint8_t chan = SAP_SERVER_CHANNEL;
+
+ if (ss->enable == TRUE)
+ return g_dbus_create_error(msg, ERROR_INTERFACE
+ ".Failed",
+ "Server already enabled");
+
+ record = sap_record(SAP_SERVER_CHANNEL);
+ if (add_record_to_server(&ss->src, record) < 0) {
+ error("Failed to register service record");
+ sdp_record_free(record);
+ return g_dbus_create_error(msg, ERROR_INTERFACE
+ ".Failed",
+ "Record registration failed");
+ }
+
+ io = bt_io_listen(BT_IO_RFCOMM, NULL, connect_confirm,
+ ss, NULL, &gerr,
+ BT_IO_OPT_SOURCE_BDADDR, &ss->src,
+ BT_IO_OPT_CHANNEL, chan,
+ BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_HIGH,
+ BT_IO_OPT_MASTER, master,
+ BT_IO_OPT_INVALID);
+
+ if (!io) {
+ error("bt_io_listen: %s", gerr->message);
+ g_error_free(gerr);
+ sdp_record_free(record);
+ return g_dbus_create_error(msg, ERROR_INTERFACE
+ ".Failed",
+ "RFCOMM SAP channel listen failed");
+ }
+
+ debug("RFCOMM SAP listen socket fd %#x", g_io_channel_unix_get_fd(io));
+
+ ss->enable = TRUE;
+ ss->record_id = record->handle;
+
+ emit_property_changed(connection, ss->path, SAP_SERVER_INTERFACE,
+ "Enabled", DBUS_TYPE_BOOLEAN, &ss->enable);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *disable(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct sap_server *ss = data;
+ DBusMessage *reply;
+
+ if (ss->enable == FALSE)
+ return g_dbus_create_error(msg, ERROR_INTERFACE
+ ".Failed",
+ "Server already disabled");
+
+ if (ss->state != SAP_STATE_DISCONNECTED)
+ return g_dbus_create_error(msg, ERROR_INTERFACE
+ ".Failed",
+ "There is ongoing connection");
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ ss->enable = FALSE;
+ remove_record_from_server(ss->record_id);
+
+ if (ss->listen_io) {
+ debug("[%s::%s] Stopping RFCOMM SAP listen socket fd: %#x", __FILE__, __FUNCTION__, g_io_channel_unix_get_fd(ss->listen_io));
+ g_io_channel_shutdown(ss->listen_io, TRUE, NULL);
+ g_io_channel_unref(ss->listen_io);
+ ss->listen_io = NULL;
+ }
+
+ emit_property_changed(connection, ss->path, SAP_SERVER_INTERFACE,
+ "Enabled", DBUS_TYPE_BOOLEAN, &ss->enable);
+
+ return reply;
+}
+
+static DBusMessage *get_properties(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct sap_server *ss = data;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter dict;
+ dbus_bool_t connected;
+
+ assert(ss && conn && msg);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+ /* Enabled */
+ dict_append_entry(&dict, "Enabled", DBUS_TYPE_BOOLEAN, &ss->enable);
+
+ /* Connected */
+ connected = (ss->state == SAP_STATE_CONNECTED || ss->state == SAP_STATE_GRACEFUL_DISCONNECT);
+ dict_append_entry(&dict, "Connected", DBUS_TYPE_BOOLEAN, &connected);
+
+ dbus_message_iter_close_container(&iter, &dict);
+
+ return reply;
+}
+
+static DBusMessage *set_property(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessageIter iter;
+ DBusMessageIter sub;
+ const char *property;
+
+ if (!dbus_message_iter_init(msg, &iter))
+ return invalid_arguments(msg, "Not a dict");
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ return invalid_arguments(msg, "Key not a string");
+
+ dbus_message_iter_get_basic(&iter, &property);
+ dbus_message_iter_next(&iter);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
+ return invalid_arguments(msg, "Value not a variant");
+ dbus_message_iter_recurse(&iter, &sub);
+
+ if (g_str_equal("Enabled", property)) {
+ gboolean enabled;
+
+ if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
+ return invalid_arguments(msg, "Value not boolean");
+ dbus_message_iter_get_basic(&sub, &enabled);
+
+ return enabled ? enable(conn, msg, data) :
+ disable(conn, msg, data);
+ }
+
+ return invalid_arguments(msg, "Property does not exist");
+}
+
+
+static DBusMessage *disconnect(DBusConnection *conn, DBusMessage *msg, void *data)
+{
+ struct sap_server *ss = data;
+ dbus_bool_t disc_type;
+ const char *sender;
+ sap_disconnection_type_t sap_disc_type;
+
+ assert(ss);
+
+ if (!ss->enable)
+ return g_dbus_create_error(msg, ERROR_INTERFACE
+ ".Failed",
+ "Server already disabled");
+
+ if (dbus_message_get_args(msg, NULL, DBUS_TYPE_BOOLEAN, &disc_type, DBUS_TYPE_INVALID) == FALSE)
+ return NULL;
+
+ sap_disc_type = disc_type ? SAP_DISCONNECTION_TYPE_GRACEFUL : SAP_DISCONNECTION_TYPE_IMMEDIATE;
+ if (disconnect_req(ss, sap_disc_type) < 0)
+ return g_dbus_create_error(msg, ERROR_INTERFACE
+ ".Failed",
+ "There is no active connection");
+
+ return dbus_message_new_method_return(msg);
+}
+
+static GDBusMethodTable server_methods[] = {
+ { "SetProperty", "sv", "", set_property },
+ { "GetProperties", "", "a{sv}",get_properties },
+ { "Disconnect", "b", "", disconnect },
+ { }
+};
+
+static GDBusSignalTable server_signals[] = {
+ { "PropertyChanged", "sv" },
+ { }
+};
+
+int sap_server_register(const char *path, bdaddr_t *src)
+{
+ struct sap_server *ss;
+
+ ss = g_new0(struct sap_server, 1);
+ if (!g_dbus_register_interface(connection, path, SAP_SERVER_INTERFACE,
+ server_methods, server_signals, NULL,
+ ss, path_unregister)) {
+ error("D-Bus failed to register %s interface", SAP_SERVER_INTERFACE);
+ server_free(ss);
+ return -1;
+ }
+
+ ss->path = g_strdup(path);
+ bacpy(&ss->src, src);
+
+ return 0;
+}
+
+int sap_server_unregister(const char *path)
+{
+ g_dbus_unregister_interface(connection, path, SAP_SERVER_INTERFACE);
+
+ return 0;
+}
+
+int sap_connect_rsp(void *sap_device, sap_status_t status, uint16_t maxmsgsize)
+{
+ struct sap_server *ss = sap_device;
+ unsigned char buf[SAP_BUF_SIZE];
+ sap_message *msg = (sap_message *) buf;
+ sap_parameter *param = (sap_parameter *) msg->param;
+ gsize size = sizeof(sap_message);
+
+ assert(ss);
+
+ debug("[%s::%s] state: %#x processing_req: %#x status 0%x",
+ __FILE__, __FUNCTION__, ss->state, ss->processing_req, status);
+
+ if (ss->state != SAP_STATE_CONNECT_IN_PROGRESS)
+ goto failed;
+
+ memset(buf, 0, sizeof(buf));
+ msg->id = SAP_CONNECT_RESP;
+ msg->nparam = 0x01;
+
+ /* Adding connection status */
+ param->id = SAP_PARAM_ID_CONN_STATUS;
+ param->len = htons(SAP_PARAM_ID_CONN_STATUS_LEN);
+ *param->val = (uint8_t)status;
+ size += PARAMETER_SIZE(SAP_PARAM_ID_CONN_STATUS_LEN);
+
+ /* Adding MaxMsgSize */
+ if (maxmsgsize && (status == SAP_STATUS_MAX_MSG_SIZE_NOT_SUPPORTED ||
+ status == SAP_STATUS_MAX_MSG_SIZE_TOO_SMALL)) {
+ uint16_t *len;
+ msg->nparam++;
+ /* Skipping the first param */
+ param = (sap_parameter *) &buf[size];
+ param->id = SAP_PARAM_ID_MAXMSGSIZE;
+ param->len = htons(SAP_PARAM_ID_MAXMSGSIZE_LEN);
+ len = (uint16_t *) ¶m->val;
+ *len = htons(maxmsgsize);
+ size += PARAMETER_SIZE(SAP_PARAM_ID_MAXMSGSIZE_LEN);
+ }
+
+ if (status == SAP_STATUS_OK) {
+ gboolean connected = TRUE;
+ emit_property_changed(connection, ss->path, SAP_SERVER_INTERFACE,
+ "Connected", DBUS_TYPE_BOOLEAN, &connected);
+
+ ss->state = SAP_STATE_CONNECTED;
+ }
+ else {
+ ss->state = SAP_STATE_DISCONNECTED;
+
+ /* Start timer which will shutdown channel if client
+ * doesn't send CONNECT_REQ or doesn't shutdown channel itself. */
+ start_guard_timer(ss, SAP_TIMER_NO_ACTIVITY);
+ }
+
+ ss->processing_req = SAP_NO_REQ;
+ return send_message(sap_device, buf, size);
+
+failed:
+ error("Unexpected response");
+ return -EPERM;
+}
+
+int sap_disconnect_rsp(void *sap_device)
+{
+ struct sap_server *ss = sap_device;
+ sap_message msg = {0};
+
+ assert(ss);
+ debug("sap_disconnect_rsp: sap_device %p", sap_device);
+ debug("[%s::%s] state: %#x processing_req: %#x",
+ __FILE__, __FUNCTION__, ss->state, ss->processing_req);
+
+ switch(ss->state) {
+ case SAP_STATE_CLIENT_DISCONNECT:
+ msg.id = SAP_DISCONNECT_RESP;
+
+ ss->state = SAP_STATE_DISCONNECTED;
+ ss->processing_req = SAP_NO_REQ;
+
+ /* Start timer which will close channel if client doesn't do it. */
+ start_guard_timer(ss, SAP_TIMER_NO_ACTIVITY);
+
+ return send_message(sap_device, (unsigned char *) &msg, sizeof(msg));
+
+ case SAP_STATE_IMMEDIATE_DISCONNECT:
+ ss->state = SAP_STATE_DISCONNECTED;
+ ss->processing_req = SAP_NO_REQ;
+
+ if (ss->io)
+ g_io_channel_shutdown(ss->io, TRUE, NULL);
+ return 0;
+ default:
+ break;
+ }
+
+failed:
+ error("Unexpected response");
+ return -EPERM;
+}
+
+int sap_transfer_apdu_rsp(void *sap_device, sap_result_t result, uint8_t *apdu, uint16_t length)
+{
+ struct sap_server *ss = sap_device;
+ unsigned char buf[SAP_BUF_SIZE] = {0};
+ sap_message *msg = (sap_message *) buf;
+ sap_parameter *param = (sap_parameter *) msg->param;
+ gsize size = sizeof(sap_message);
+
+ assert(ss);
+
+ debug("[%s::%s] state: %#x processing_req: %#x",
+ __FILE__, __FUNCTION__, ss->state, ss->processing_req);
+
+ if (ss->processing_req != SAP_TRANSFER_APDU_REQ)
+ /* Ignore this response because processing (state) request has been changed.
+ * This situation can happen e.g. when client sends disconnect request
+ * while server is processing another request.*/
+ return 0;
+
+ if (result == SAP_RESULT_OK && (!apdu || (apdu && length == 0x00)))
+ return -EINVAL;
+
+ msg->id = SAP_TRANSFER_APDU_RESP;
+
+ /* Adding result code */
+ msg->nparam = 0x01;
+ size += add_result_parameter(result, param);
+
+ /* Adding APDU response. */
+ if (result == SAP_RESULT_OK) {
+ msg->nparam++;
+ /* Skipping the first param. */
+ param = (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);
+ }
+
+ ss->processing_req = SAP_NO_REQ;
+ return send_message(sap_device, buf, size);
+}
+
+int sap_transfer_atr_rsp(void *sap_device, sap_result_t result, uint8_t *atr, uint16_t length)
+{
+ struct sap_server *ss = sap_device;
+ unsigned char buf[SAP_BUF_SIZE]= {0};
+ sap_message *msg = (sap_message *) buf;
+ sap_parameter *param = (sap_parameter *) msg->param;
+ gsize size = sizeof(sap_message);
+
+ assert(ss);
+
+ debug("[%s::%s] state: %#x processing_req: %#x",
+ __FILE__, __FUNCTION__, ss->state, ss->processing_req);
+
+ if (ss->processing_req != SAP_TRANSFER_ATR_REQ)
+ /* Ignore this response because processing (state) request has been changed.
+ * This situation can happen e.g. when client sends disconnect request
+ * while server is processing another request.*/
+ return 0;
+
+ if (result == SAP_RESULT_OK && (!atr || (atr && length == 0x00)))
+ return -EINVAL;
+
+ msg->id = SAP_TRANSFER_ATR_RESP;
+
+ /* Adding result code */
+ msg->nparam = 0x01;
+ size += add_result_parameter(result, param);
+
+ /* Adding ATR response */
+ if (result == SAP_RESULT_OK) {
+ msg->nparam++;
+ /* Skipping the first param */
+ param = (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);
+ }
+
+ ss->processing_req = SAP_NO_REQ;
+ return send_message(sap_device, buf, size);
+}
+
+int sap_power_sim_off_rsp(void *sap_device, sap_result_t result)
+{
+ struct sap_server *ss = sap_device;
+ unsigned char buf[SAP_BUF_SIZE] = {0};
+ sap_message *msg = (sap_message *) buf;
+ gsize size = sizeof(sap_message);
+
+ assert(ss);
+
+ debug("[%s::%s] state: %#x processing_req: %#x",
+ __FILE__, __FUNCTION__, ss->state, ss->processing_req);
+
+ if (ss->processing_req != SAP_POWER_SIM_OFF_REQ)
+ /* Ignore this response because processing (state) request has been changed.
+ * This situation can happen e.g. when client sends disconnect request
+ * while server is processing another request. */
+ return 0;
+
+ msg->id = SAP_POWER_SIM_OFF_RESP;
+
+ /* Adding result code */
+ msg->nparam = 0x01;
+ size += add_result_parameter(result, msg->param);
+
+ ss->processing_req = SAP_NO_REQ;
+ return send_message(sap_device, buf, size);
+}
+
+int sap_power_sim_on_rsp(void *sap_device, sap_result_t result)
+{
+ struct sap_server *ss = sap_device;
+ unsigned char buf[SAP_BUF_SIZE] = {0};
+ sap_message *msg = (sap_message *) buf;
+ gsize size = sizeof(sap_message);
+
+ assert(ss);
+
+ debug("[%s::%s] state: %#x processing_req: %#x",
+ __FILE__, __FUNCTION__, ss->state, ss->processing_req);
+
+ if (ss->processing_req != SAP_POWER_SIM_ON_REQ)
+ /* Ignore this response because processing (state) request has been changed.
+ * This situation can happen e.g. when client sends disconnect request
+ * while server is processing another request. */
+ return 0;
+
+ msg->id = SAP_POWER_SIM_ON_RESP;
+
+ /* Adding result code */
+ msg->nparam = 0x01;
+ size += add_result_parameter(result, msg->param);
+
+ ss->processing_req = SAP_NO_REQ;
+ return send_message(sap_device, buf, size);
+}
+
+int sap_reset_sim_rsp(void *sap_device, sap_result_t result)
+{
+ struct sap_server *ss = sap_device;
+ unsigned char buf[SAP_BUF_SIZE] = {0};
+ sap_message *msg = (sap_message *) buf;
+ gsize size = sizeof(sap_message);
+
+ assert(ss);
+
+ debug("[%s::%s] state: %#x processing_req: %#x",
+ __FILE__, __FUNCTION__, ss->state, ss->processing_req);
+
+ if (ss->processing_req != SAP_RESET_SIM_REQ)
+ /* Ignore this response because processing (state) request has been changed.
+ * This situation can happen e.g. when client sends disconnect request
+ * while server is processing another request. */
+ return 0;
+
+ msg->id = SAP_RESET_SIM_RESP;
+
+ /* Adding result code */
+ msg->nparam = 0x01;
+ size += add_result_parameter(result, msg->param);
+
+ ss->processing_req = SAP_NO_REQ;
+ return send_message(sap_device, buf, size);
+}
+
+int sap_transfer_card_reader_status_rsp(void *sap_device, sap_result_t result, icc_reader_status_t status)
+{
+ struct sap_server *ss = sap_device;
+ unsigned char buf[SAP_BUF_SIZE] = {0};
+ sap_message *msg = (sap_message *) buf;
+ sap_parameter *param = (sap_parameter *) msg->param;
+ gsize size = sizeof(sap_message);
+
+ assert(ss);
+
+ debug("[%s::%s] state: %#x processing_req: %#x",
+ __FILE__, __FUNCTION__, ss->state, ss->processing_req);
+
+ if (ss->processing_req != SAP_TRANSFER_CARD_READER_STATUS_REQ)
+ /* Ignore this response because processing (state) request has been changed.
+ * This situation can happen e.g. when client sends disconnect request
+ * while server is processing another request. */
+ return 0;
+
+ msg->id = SAP_TRANSFER_CARD_READER_STATUS_RESP;
+
+ /* Adding result code */
+ msg->nparam = 0x01;
+ size += add_result_parameter(result, param);
+
+ /* Adding card reader status. */
+ if (result == SAP_RESULT_OK) {
+ msg->nparam++;
+ /* Skipping the first param. */
+ param = (sap_parameter *) &buf[size];
+ param->id = SAP_PARAM_ID_CARD_READER_STATUS;
+ param->len = htons(SAP_PARAM_ID_CARD_READER_STATUS_LEN);
+ *param->val = (uint8_t) status;
+ size += PARAMETER_SIZE(SAP_PARAM_ID_CARD_READER_STATUS_LEN);
+ }
+
+ ss->processing_req = SAP_NO_REQ;
+ return send_message(sap_device, buf, size);
+}
+
+int sap_error_rsp(void *sap_device)
+{
+ sap_message msg;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.id = SAP_ERROR_RESP;
+
+ return send_message(sap_device, (unsigned char *) &msg, sizeof(msg));
+}
+
+int sap_status_ind(void *sap_device, sap_status_change_t status_change)
+{
+ struct sap_server *ss = sap_device;
+ unsigned char buf[SAP_BUF_SIZE] = {0};
+ sap_message *msg = (sap_message *) buf;
+ sap_parameter *param = (sap_parameter *) msg->param;
+ gsize size = sizeof(sap_message);
+
+ assert(ss);
+
+ debug("[%s::%s] state: %#x processing_req: %#x",
+ __FILE__, __FUNCTION__, ss->state, ss->processing_req);
+
+ if (ss->state != SAP_STATE_CONNECTED && ss->state != SAP_STATE_GRACEFUL_DISCONNECT)
+ /* Ignore this indication when server is not connected. */
+ return 0;
+
+ msg->id = SAP_STATUS_IND;
+ msg->nparam = 0x01;
+
+ /* Adding status change. */
+ param->id = SAP_PARAM_ID_STATUS_CHANGE;
+ param->len = htons(SAP_PARAM_ID_STATUS_CHANGE_LEN);
+ *param->val = (uint8_t) status_change;
+ size += PARAMETER_SIZE(SAP_PARAM_ID_STATUS_CHANGE_LEN);
+
+ return send_message(sap_device, buf, size);
+}
diff --git a/sap/server.h b/sap/server.h
new file mode 100644
index 0000000..4dca525
--- /dev/null
+++ b/sap/server.h
@@ -0,0 +1,25 @@
+/*
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 ST-Ericsson SA
+ * Copyright (C) 2010 Claudio Takahasi<claudio.takahasi@openbossa.org>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+int sap_server_init(DBusConnection *conn);
+void sap_server_exit(void);
+int sap_server_register(const char *path, bdaddr_t *src);
+int sap_server_unregister(const char *path);
+
--
1.7.0.4
^ permalink raw reply related
* Re: [PATCH v2] Bluetooth: Latest firmware support for ath3k USB device
From: Marcel Holtmann @ 2010-10-06 8:48 UTC (permalink / raw)
To: Suraj Sumangala; +Cc: linux-bluetooth, Jothikumar.Mothilal
In-Reply-To: <1286353896-8811-1-git-send-email-suraj@atheros.com>
Hi Suraj,
> This patch add support for latest ath3k USB Bluetooth device firmare.
> The firmware implements shared antenna support and
> fixes few critical bugs.
>
> Signed-off-by: Suraj Sumangala <suraj@atheros.com>
> ---
> drivers/bluetooth/ath3k.c | 11 ++++++++---
> 1 files changed, 8 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
> index 128cae4..6eb4bcf 100644
> --- a/drivers/bluetooth/ath3k.c
> +++ b/drivers/bluetooth/ath3k.c
> @@ -103,6 +103,8 @@ error:
> return err;
> }
>
> +#define ATH3K_FW "ath3k-fw.fw"
> +#define ATH3K_FW_LEGACY "ath3k-1.fw"
> static int ath3k_probe(struct usb_interface *intf,
> const struct usb_device_id *id)
> {
> @@ -122,9 +124,12 @@ static int ath3k_probe(struct usb_interface *intf,
>
> data->udev = udev;
>
> - if (request_firmware(&firmware, "ath3k-1.fw", &udev->dev) < 0) {
> - kfree(data);
> - return -EIO;
> + if (request_firmware(&firmware, ATH3K_FW, &udev->dev) < 0) {
> + if (request_firmware(&firmware, ATH3K_FW_LEGACY,
> + &udev->dev) < 0) {
> + kfree(data);
> + return -EIO;
> + }
> }
>
> size = max_t(uint, firmware->size, 4096);
if this change is enough and the firmware is API compatible, then why do
you bother with this change. Just copy the new firmware over ath3k.fw
file.
I was under the assumption that the firmware is somehow API incompatible
with the current driver, but if it is not, then we don't need this at
all.
So I would propose to just send a patch against linux-firmware tree to
replace the current ath3k.fw with a newer file. Since only in API
incompatible changes should be reflected with a new name.
Regards
Marcel
^ permalink raw reply
* [PATCH v2] Bluetooth: Latest firmware support for ath3k USB device
From: Suraj Sumangala @ 2010-10-06 8:31 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jothikumar.Mothilal, Suraj Sumangala
This patch add support for latest ath3k USB Bluetooth device firmare.
The firmware implements shared antenna support and
fixes few critical bugs.
Signed-off-by: Suraj Sumangala <suraj@atheros.com>
---
drivers/bluetooth/ath3k.c | 11 ++++++++---
1 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
index 128cae4..6eb4bcf 100644
--- a/drivers/bluetooth/ath3k.c
+++ b/drivers/bluetooth/ath3k.c
@@ -103,6 +103,8 @@ error:
return err;
}
+#define ATH3K_FW "ath3k-fw.fw"
+#define ATH3K_FW_LEGACY "ath3k-1.fw"
static int ath3k_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
@@ -122,9 +124,12 @@ static int ath3k_probe(struct usb_interface *intf,
data->udev = udev;
- if (request_firmware(&firmware, "ath3k-1.fw", &udev->dev) < 0) {
- kfree(data);
- return -EIO;
+ if (request_firmware(&firmware, ATH3K_FW, &udev->dev) < 0) {
+ if (request_firmware(&firmware, ATH3K_FW_LEGACY,
+ &udev->dev) < 0) {
+ kfree(data);
+ return -EIO;
+ }
}
size = max_t(uint, firmware->size, 4096);
--
1.7.0.4
^ permalink raw reply related
* RE: Sim Access profile server implementation
From: Waldemar.Rymarkiewicz @ 2010-10-06 7:28 UTC (permalink / raw)
To: marcel; +Cc: suraj, linux-bluetooth, Jothikumar.Mothilal, joakim.xj.ceder
In-Reply-To: <1286280767.17473.89.camel@aeonflux>
Marcel,
>
>please no top posting on this mailing list.
>
Sorry, didn't know that. Thanks for pointing this out.
>> I understand you concerns about dbus reliability and I agree=20
>with you , but I guess we should find a compromise solution as=20
>ofono is not used widely in Linux mobile platforms nowadays.
>>=20
>> I my view, combination of a bluez plugin for sap and a=20
>platform dependend sim driver is a reliable and most available=20
>solution so far. The SAP plugin implements BT SAP spec and=20
>require simple API (connect, disconnect, apdu, atr, status)=20
>which is implemented in SIM driver for a certain platform.=20
>This way it's relatively easy to support SAP in different=20
>platforms. Ofono can have its own driver as well.
>>=20
>> What's you view on such design?
>> Can we also have a double solution one in ofono for ofono=20
>aware platforms and the second as a plugin for others?=20
>
>I am fine with starting this in BlueZ and see how far we get.=20
>And yes, plugin based is a must from my point of view. It is=20
>most likely similar to our different telephony drivers for=20
>Handsfree support.
It's nice to here that.
>We will move strongly in the direction of oFono being the main=20
>telephony stack. So I do care mostly that this work in=20
>conjunction with oFono.
>Everything else is just a nice benefit if it doesn't clutter=20
>the overhaul implementation and requires pointless abstraction=20
>everywhere.
>> BTW, I already have this implemented and tested with real hardware=20
>> (STEricsson). Bluez SAP works fine with Nokia 616 carkit :)
>
>Can you share that code with us. And also hardware if you. We=20
>are still having hard time to find proper hardware to test this on.
Will send a patch soon. I use http://www.stericsson.com/platforms/U8500.jsp=
hw, but need to check if I can share one with you.
Regards,
/Waldek=
^ permalink raw reply
* Re: RFC: btusb firmware load help
From: Marcel Holtmann @ 2010-10-06 7:19 UTC (permalink / raw)
To: Luis R. Rodriguez
Cc: Luis Rodriguez, linux-bluetooth, linux-kernel@vger.kernel.org,
linux-wireless@vger.kernel.org, Deepak Dhamdhere, Sree Durbha
In-Reply-To: <AANLkTimz7U52_qHaTutQDOFQde+GrWJRA0WpqY__FPgi@mail.gmail.com>
Hi Luis,
> > most likely via a separate firmware loading driver.
>
> Like the fwload patch ? Or something different?
something clean of course and not this hacking around, but in general
along that.
> > Your ath3k driver is such a driver. Same as the bcm203x driver.
>
> Right -- so ath3k depends on some atheros USB device IDs, and its a
> stupid driver that just loads firmware. The problem with this new
> device is that it requires two phases. One to load some sort of
> firmware onto it to get it to read as an ath3k device, and then ath3k
> will load the right firmware to it. So the hardware device is already
> claiming a btusb vendor:device ID, we can't change that I believe. Of
> course for future devices we can, and we've addressed this and its
> been fixed.
So your current loading procedure is this:
1) btusb with hacked firmware loading
2) ath3k
3) btusb with HCI
Who thought that this is a good idea in the first place? And more
important that I would accept this upstream? This is even worse than I
thought it is.
Please get this craziness fixed.
> > They don't do anything than claiming that USB device, loading the firmware, and then let it reset.
>
> Right but if the SFLASH configurations hardware is already shipping
> and without firmware is claiming to be a BT USB device which matches
> the USB vendor:device ID of the btusb driver. Unfortunately it does
> not accept HCI commands which as you indicates breaks some
> specification. We can and have fixed this in future chipsets but this
> one cannot be addressed. So what do we do?
>
> > And after the reset the btusb can claim the one where the firmware has
> > been loaded and which behaves like a proper USB dongle.
>
> Right, that's what the fwload patch from our BT team does, no?
Yes, but not inside the btusb driver. Stop hacking a generic driver with
crazy firmware loading only because the USB Bluetooth class descriptors
got screwed up in the first place.
> > The part that I don't understand is that you have the ath3k driver doing
> > it exactly how it should be done, why now started to make nasty hacks in
> > the btusb driver.
>
> Yeah that seems to have been a shortcoming, its something you should
> expect from us moving forward. I've been told AR3012 and future
> Atheros chipsets will not have behave this way, and this issue is only
> present for the AR3011 devices with SFLASH configuration.
Most likely including the flashing into ath3k firmware loading driver
and that being called bound twice might be a good idea. However we are
not doing the firmware loading in btusb. Then a patch to blacklist this
broken device. And then ensure that the firmware changes the USB PIDs
after success.
And if I understand you correct, then it does this anyway right now
already. Otherwise the ath3k driver would not bind to it.
Now I am failing to understand why this was done wrong in the first
place. Especially if the loading procedure happens as you say it
happens.
This is the example for the Broadcom 203x devices:
static struct usb_device_id blacklist_table[] = {
/* Broadcom BCM2033 without firmware */
{ USB_DEVICE(0x0a5c, 0x2033), .driver_info = BTUSB_IGNORE },
The btusb driver clearly blacklists them. And then bcm203x can take over
loading the firmware:
static const struct usb_device_id bcm203x_table[] = {
/* Broadcom Blutonium (BCM2033) */
{ USB_DEVICE(0x0a5c, 0x2033) },
So there is a working example of this already in the kernel tree since
forever.
Regards
Marcel
^ permalink raw reply
* Re: RFC: btusb firmware load help
From: Marcel Holtmann @ 2010-10-06 7:09 UTC (permalink / raw)
To: Matthew Garrett
Cc: Luis R. Rodriguez, Luis Rodriguez, linux-bluetooth,
linux-kernel@vger.kernel.org, linux-wireless@vger.kernel.org,
Deepak Dhamdhere, Sree Durbha
In-Reply-To: <20101005215008.GA11117@srcf.ucam.org>
Hi Matthew,
> > Right -- so ath3k depends on some atheros USB device IDs, and its a
> > stupid driver that just loads firmware. The problem with this new
> > device is that it requires two phases. One to load some sort of
> > firmware onto it to get it to read as an ath3k device, and then ath3k
> > will load the right firmware to it. So the hardware device is already
> > claiming a btusb vendor:device ID, we can't change that I believe. Of
> > course for future devices we can, and we've addressed this and its
> > been fixed.
>
> If the device IDs can be changed when the firmware is loaded, then
> simply provide a driver that binds to the original IDs and uploads the
> firmware. The original IDs can be blacklisted from btusb so it won't
> interfere. The device will then boot the firmware, detach and reattach
> with new IDs - btusb will then bind. Repeat for every cold reset.
>
> If you can't change the IDs from firmware then an alternative would be
> to blacklist it from btusb and provide a userspace application triggered
> by a udev rule. Have it load the firmware and then poke
> /sys/bus/usb/drivers/btusb/new_id .
exactly, we just blacklist the original USB IDs in the btusb driver. It
already has a blacklist table and you just use BTUSB_IGNORE in there.
Regards
Marcel
^ permalink raw reply
* Re: RFC: btusb firmware load help
From: Matthew Garrett @ 2010-10-05 21:50 UTC (permalink / raw)
To: Luis R. Rodriguez
Cc: Marcel Holtmann, Luis Rodriguez, linux-bluetooth,
linux-kernel@vger.kernel.org, linux-wireless@vger.kernel.org,
Deepak Dhamdhere, Sree Durbha
In-Reply-To: <AANLkTimz7U52_qHaTutQDOFQde+GrWJRA0WpqY__FPgi@mail.gmail.com>
On Tue, Oct 05, 2010 at 01:28:53PM -0700, Luis R. Rodriguez wrote:
> Right -- so ath3k depends on some atheros USB device IDs, and its a
> stupid driver that just loads firmware. The problem with this new
> device is that it requires two phases. One to load some sort of
> firmware onto it to get it to read as an ath3k device, and then ath3k
> will load the right firmware to it. So the hardware device is already
> claiming a btusb vendor:device ID, we can't change that I believe. Of
> course for future devices we can, and we've addressed this and its
> been fixed.
If the device IDs can be changed when the firmware is loaded, then
simply provide a driver that binds to the original IDs and uploads the
firmware. The original IDs can be blacklisted from btusb so it won't
interfere. The device will then boot the firmware, detach and reattach
with new IDs - btusb will then bind. Repeat for every cold reset.
If you can't change the IDs from firmware then an alternative would be
to blacklist it from btusb and provide a userspace application triggered
by a udev rule. Have it load the firmware and then poke
/sys/bus/usb/drivers/btusb/new_id .
--
Matthew Garrett | mjg59@srcf.ucam.org
^ permalink raw reply
* Re: RFC: btusb firmware load help
From: Luis R. Rodriguez @ 2010-10-05 20:28 UTC (permalink / raw)
To: Marcel Holtmann
Cc: Luis Rodriguez, linux-bluetooth, linux-kernel@vger.kernel.org,
linux-wireless@vger.kernel.org, Deepak Dhamdhere, Sree Durbha
In-Reply-To: <1286308731.2588.13.camel@aeonflux>
On Tue, Oct 5, 2010 at 12:58 PM, Marcel Holtmann
<holtmann@linux.intel.com> wrote:
> Hi Luis,
>
>> > > Marcel, I was just poked about this thread:
>> > >
>> > > http://www.spinics.net/lists/linux-bluetooth/msg06087.html
>> > >
>> > > The hack is required because our BT hardware does not accept HCI commands
>> > > when the device is plugged in. If I understood your position you did not
>> > > want to accept the patch because our BT USB devices are violating the
>> > > specification by not acceping HCI commands and yet claiming to be BT
>> > > devices, is that right?
>> >
>> > you don't have to accept HCI commands when your device has no firmware
>> > loaded. That is just fine. However at that point you should not claim to
>> > be a Bluetooth H:2 device with USB Bluetooth descriptors.
>> >
>> > Just having different USB PIDs for without firmware and with firmware
>> > stages would have been fine. The ancient Broadcom 203x devices even got
>> > that part right.
>>
>> Ah I see.
>>
>> > So what about sticking with the current VID:PID for the device without
>> > firmware and we blacklist it in btusb driver. And then the firmware
>> > loading ensures that after reset it uses a different PID for the device
>> > with valid HCI firmware.
>>
>> How would firmware be uploaded to the device if no module
>> is claiming it?
>
> most likely via a separate firmware loading driver.
Like the fwload patch ? Or something different?
> Your ath3k driver is such a driver. Same as the bcm203x driver.
Right -- so ath3k depends on some atheros USB device IDs, and its a
stupid driver that just loads firmware. The problem with this new
device is that it requires two phases. One to load some sort of
firmware onto it to get it to read as an ath3k device, and then ath3k
will load the right firmware to it. So the hardware device is already
claiming a btusb vendor:device ID, we can't change that I believe. Of
course for future devices we can, and we've addressed this and its
been fixed.
> They don't do anything than claiming that USB device, loading the firmware, and then let it reset.
Right but if the SFLASH configurations hardware is already shipping
and without firmware is claiming to be a BT USB device which matches
the USB vendor:device ID of the btusb driver. Unfortunately it does
not accept HCI commands which as you indicates breaks some
specification. We can and have fixed this in future chipsets but this
one cannot be addressed. So what do we do?
> And after the reset the btusb can claim the one where the firmware has
> been loaded and which behaves like a proper USB dongle.
Right, that's what the fwload patch from our BT team does, no?
> The part that I don't understand is that you have the ath3k driver doing
> it exactly how it should be done, why now started to make nasty hacks in
> the btusb driver.
Yeah that seems to have been a shortcoming, its something you should
expect from us moving forward. I've been told AR3012 and future
Atheros chipsets will not have behave this way, and this issue is only
present for the AR3011 devices with SFLASH configuration.
Luis
^ permalink raw reply
* Re: [PATCH] TODO: Automatic server indication/notification owner
From: Johan Hedberg @ 2010-10-05 20:27 UTC (permalink / raw)
To: Claudio Takahasi; +Cc: linux-bluetooth
In-Reply-To: <1286299418-21862-1-git-send-email-claudio.takahasi@openbossa.org>
Hi Claudio,
On Tue, Oct 05, 2010, Claudio Takahasi wrote:
> ---
> TODO | 1 +
> 1 files changed, 1 insertions(+), 0 deletions(-)
This one is now also upstream. Thanks.
Johan
^ permalink raw reply
* Re: [PATCH] Add PSM option for GATT/ATT over BR/EDR on gatttool
From: Johan Hedberg @ 2010-10-05 20:27 UTC (permalink / raw)
To: Claudio Takahasi; +Cc: linux-bluetooth
In-Reply-To: <1286298958-21494-1-git-send-email-claudio.takahasi@openbossa.org>
Hi Claudio,
On Tue, Oct 05, 2010, Claudio Takahasi wrote:
> ---
> TODO | 6 ------
> attrib/gatttool.c | 6 ++++--
> 2 files changed, 4 insertions(+), 8 deletions(-)
The patch has been pushed upstream. Thanks.
Johan
^ permalink raw reply
* Re: RFC: btusb firmware load help
From: Marcel Holtmann @ 2010-10-05 19:58 UTC (permalink / raw)
To: Luis R. Rodriguez
Cc: Luis Rodriguez, linux-bluetooth, linux-kernel@vger.kernel.org,
linux-wireless@vger.kernel.org, Deepak Dhamdhere, Sree Durbha
In-Reply-To: <20101005192814.GB11831@tux>
Hi Luis,
> > > Marcel, I was just poked about this thread:
> > >
> > > http://www.spinics.net/lists/linux-bluetooth/msg06087.html
> > >
> > > The hack is required because our BT hardware does not accept HCI commands
> > > when the device is plugged in. If I understood your position you did not
> > > want to accept the patch because our BT USB devices are violating the
> > > specification by not acceping HCI commands and yet claiming to be BT
> > > devices, is that right?
> >
> > you don't have to accept HCI commands when your device has no firmware
> > loaded. That is just fine. However at that point you should not claim to
> > be a Bluetooth H:2 device with USB Bluetooth descriptors.
> >
> > Just having different USB PIDs for without firmware and with firmware
> > stages would have been fine. The ancient Broadcom 203x devices even got
> > that part right.
>
> Ah I see.
>
> > So what about sticking with the current VID:PID for the device without
> > firmware and we blacklist it in btusb driver. And then the firmware
> > loading ensures that after reset it uses a different PID for the device
> > with valid HCI firmware.
>
> How would firmware be uploaded to the device if no module
> is claiming it?
most likely via a separate firmware loading driver. Your ath3k driver is
such a driver. Same as the bcm203x driver. They don't do anything than
claiming that USB device, loading the firmware, and then let it reset.
And after the reset the btusb can claim the one where the firmware has
been loaded and which behaves like a proper USB dongle.
The part that I don't understand is that you have the ath3k driver doing
it exactly how it should be done, why now started to make nasty hacks in
the btusb driver.
Regards
Marcel
^ permalink raw reply
* Re: [PATCH] Bluetooth: clean up rfcomm code
From: Gustavo F. Padovan @ 2010-10-05 19:42 UTC (permalink / raw)
To: Marcel Holtmann; +Cc: Emeltchenko Andrei, linux-bluetooth
In-Reply-To: <1286265236.17473.26.camel@aeonflux>
Hi Andrei,
* Marcel Holtmann <marcel@holtmann.org> [2010-10-05 09:53:56 +0200]:
> Hi Andrei,
>
> > Remove dead code and unused rfcomm thread events
> >
> > Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@nokia.com>
> > ---
> > include/net/bluetooth/rfcomm.h | 5 -----
> > net/bluetooth/rfcomm/core.c | 29 ++++++++++++++---------------
> > 2 files changed, 14 insertions(+), 20 deletions(-)
> >
> > diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h
> > index a140847..71047bc 100644
> > --- a/include/net/bluetooth/rfcomm.h
> > +++ b/include/net/bluetooth/rfcomm.h
> > @@ -213,11 +213,6 @@ struct rfcomm_dlc {
> > #define RFCOMM_DEFER_SETUP 8
> >
> > /* Scheduling flags and events */
> > -#define RFCOMM_SCHED_STATE 0
> > -#define RFCOMM_SCHED_RX 1
> > -#define RFCOMM_SCHED_TX 2
> > -#define RFCOMM_SCHED_TIMEO 3
> > -#define RFCOMM_SCHED_AUTH 4
> > #define RFCOMM_SCHED_WAKEUP 31
>
> we had some big ambition to use these, but never did in the end or
> realized that they are not needed. So I am fine with removing these.
>
> Acked-by: Marcel Holtmann <marcel@holtmann.org>
Patch has been applied. Thanks.
--
Gustavo F. Padovan
ProFUSION embedded systems - http://profusion.mobi
^ permalink raw reply
* Re: RFC: btusb firmware load help
From: Luis R. Rodriguez @ 2010-10-05 19:28 UTC (permalink / raw)
To: Marcel Holtmann
Cc: Luis Rodriguez, linux-bluetooth, linux-kernel@vger.kernel.org,
linux-wireless@vger.kernel.org, Deepak Dhamdhere, Sree Durbha
In-Reply-To: <1286266981.17473.33.camel@aeonflux>
On Tue, Oct 05, 2010 at 01:23:01AM -0700, Marcel Holtmann wrote:
> Hi Luis,
>
> > Marcel, I was just poked about this thread:
> >
> > http://www.spinics.net/lists/linux-bluetooth/msg06087.html
> >
> > The hack is required because our BT hardware does not accept HCI commands
> > when the device is plugged in. If I understood your position you did not
> > want to accept the patch because our BT USB devices are violating the
> > specification by not acceping HCI commands and yet claiming to be BT
> > devices, is that right?
>
> you don't have to accept HCI commands when your device has no firmware
> loaded. That is just fine. However at that point you should not claim to
> be a Bluetooth H:2 device with USB Bluetooth descriptors.
>
> Just having different USB PIDs for without firmware and with firmware
> stages would have been fine. The ancient Broadcom 203x devices even got
> that part right.
Ah I see.
> So what about sticking with the current VID:PID for the device without
> firmware and we blacklist it in btusb driver. And then the firmware
> loading ensures that after reset it uses a different PID for the device
> with valid HCI firmware.
How would firmware be uploaded to the device if no module
is claiming it?
Luis
^ permalink raw reply
* [PATCH] TODO: Automatic server indication/notification owner
From: Claudio Takahasi @ 2010-10-05 17:23 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Claudio Takahasi
---
TODO | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/TODO b/TODO
index 0a82f5c..c5c404c 100644
--- a/TODO
+++ b/TODO
@@ -23,6 +23,7 @@ ATT/GATT
Priority: Medium
Complexity: C2
+ Owner: Claudio Takahasi <claudio.takahasi@openbossa.org>
- gatttool should wait for req responses before quitting (some servers
require a small sleep even with cmd's)
--
1.7.3.1
^ permalink raw reply related
* [PATCH] Add PSM option for GATT/ATT over BR/EDR on gatttool
From: Claudio Takahasi @ 2010-10-05 17:15 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Claudio Takahasi
---
TODO | 6 ------
attrib/gatttool.c | 6 ++++--
2 files changed, 4 insertions(+), 8 deletions(-)
diff --git a/TODO b/TODO
index 41ec7a7..0a82f5c 100644
--- a/TODO
+++ b/TODO
@@ -40,12 +40,6 @@ ATT/GATT
Priority: Low
Complexity: C1
-- Add command line support for specifying psm with gatttool (e.g. --psm
- 37)
-
- Priority: Medium
- Complexity: C1
-
- Add command line support to use medium instead of (default) low
security level with gatttool (--sec-level)
diff --git a/attrib/gatttool.c b/attrib/gatttool.c
index 76fe62c..2de3f8b 100644
--- a/attrib/gatttool.c
+++ b/attrib/gatttool.c
@@ -43,7 +43,6 @@
#include "gattrib.h"
#include "gatt.h"
-#define GATT_PSM 0x1f
/* Minimum MTU for L2CAP connections over BR/EDR */
#define ATT_MIN_MTU_L2CAP 48
#define GATT_CID 4
@@ -55,6 +54,7 @@ static int opt_start = 0x0001;
static int opt_end = 0xffff;
static int opt_handle = -1;
static int opt_mtu = 0;
+static int opt_psm = 0x1f;
static gboolean opt_primary = FALSE;
static gboolean opt_characteristics = FALSE;
static gboolean opt_char_read = FALSE;
@@ -122,7 +122,7 @@ static GIOChannel *do_connect(gboolean le)
chan = bt_io_connect(BT_IO_L2CAP, connect_cb, NULL, NULL, &err,
BT_IO_OPT_SOURCE_BDADDR, &sba,
BT_IO_OPT_DEST_BDADDR, &dba,
- BT_IO_OPT_PSM, GATT_PSM,
+ BT_IO_OPT_PSM, opt_psm,
BT_IO_OPT_OMTU, opt_mtu,
BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
BT_IO_OPT_INVALID);
@@ -518,6 +518,8 @@ static GOptionEntry options[] = {
"Specify remote Bluetooth address", "MAC" },
{ "mtu", 'm', 0, G_OPTION_ARG_INT, &opt_mtu,
"Specify the MTU size", "MTU" },
+ { "psm", 'p', 0, G_OPTION_ARG_INT, &opt_psm,
+ "Specify the PSM for GATT/ATT over BR/EDR", "PSM" },
{ NULL },
};
--
1.7.3.1
^ permalink raw reply related
* pull-request: bluetooth-2.6 2010-10-05
From: Gustavo F. Padovan @ 2010-10-05 17:13 UTC (permalink / raw)
To: David Miller; +Cc: linville, marcel, linux-bluetooth, netdev
Hi Dave,
In this patch set we have two fixes for regressions in L2CAP due to ERTM code
we added in L2CAP for 2.6.36, a bugfix in the L2CAP Streaming Mode that was
making the kernel crash. And a fix for a deadlock issue between the sk_sndbuf
and the backlog queue in ERTM. The rest are also needed bug fixes.
For -next pull request things go back to normal and patches go through John.
Thanks!
The following changes since commit 899611ee7d373e5eeda08e9a8632684e1ebbbf00:
Linux 2.6.36-rc6 (2010-09-28 18:01:22 -0700)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/padovan/bluetooth-2.6.git master
Andrei Emeltchenko (1):
Bluetooth: fix MTU L2CAP configuration parameter
Gustavo F. Padovan (5):
Bluetooth: Simplify L2CAP Streaming mode sending
Bluetooth: Fix inconsistent lock state with RFCOMM
Revert "Bluetooth: Don't accept ConfigReq if we aren't in the BT_CONFIG state"
Bluetooth: Fix deadlock in the ERTM logic
Bluetooth: Disallow to change L2CAP_OPTIONS values when connected
Mat Martineau (1):
Bluetooth: Only enable L2CAP FCS for ERTM or streaming
include/net/bluetooth/bluetooth.h | 18 +++++++++++
net/bluetooth/l2cap.c | 62 +++++++++++++++++-------------------
net/bluetooth/rfcomm/sock.c | 4 ++
3 files changed, 51 insertions(+), 33 deletions(-)
--
Gustavo F. Padovan
ProFUSION embedded systems - http://profusion.mobi
^ permalink raw reply
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