Hi,
Sorry, I sent on to wrong list, so agian ...
Here you are the SAP plugin modified to reflect the audio/telephony design.
Could anyone interested in do a review and put any comments.
Regards,
/Waldek
Waldemar Rymarkiewicz (1):
Add Sim Access Plugin
.gitignore | 1 +
Makefile.am | 25 +-
acinclude.m4 | 14 +
doc/sap-api.txt | 57 ++
sap/main.c | 54 ++
sap/manager.c | 94 ++++
sap/manager.h | 21 +
sap/sap-dummy.c | 306 +++++++++++
sap/sap-ste.c | 1265 ++++++++++++++++++++++++++++++++++++++++++++++
sap/sap.h | 187 +++++++
sap/server.c | 1516 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
sap/server.h | 23 +
12 files changed, 3559 insertions(+), 4 deletions(-)
create mode 100644 doc/sap-api.txt
create mode 100644 sap/main.c
create mode 100644 sap/manager.c
create mode 100644 sap/manager.h
create mode 100644 sap/sap-dummy.c
create mode 100644 sap/sap-ste.c
create mode 100644 sap/sap.h
create mode 100644 sap/server.c
create mode 100644 sap/server.h
Hi Suraj,
>> create mode 100644 sap/sap-ste.c
>I am assuming that this is the ST specific plugin. May be you=20
>can just keep the dummy plugin only so that someone can use=20
>that as a reference.
In fact, you are right. Will remove this for the time being.=20
>> create mode 100644 sap/sap.h
>> create mode 100644 sap/server.c
>> create mode 100644 sap/server.h
>
>I guess it would be better if you can split this into multiple=20
>patches so that it would be easier to review.
Ok.=20
Regards,
/Waldek
Hi Waldemar,
On 10/20/2010 1:25 PM, Waldemar Rymarkiewicz wrote:
> Sim Access plugin implements Sim Access Profile server role
> according to the Bluetooth Sim Access Profile v1.1 specification.
> ---
> .gitignore | 1 +
> Makefile.am | 25 +-
> acinclude.m4 | 14 +
> doc/sap-api.txt | 57 ++
> sap/main.c | 54 ++
> sap/manager.c | 94 ++++
> sap/manager.h | 21 +
> sap/sap-dummy.c | 306 +++++++++++
> sap/sap-ste.c | 1265 ++++++++++++++++++++++++++++++++++++++++++++++
> sap/sap.h | 187 +++++++
> sap/server.c | 1516 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
> sap/server.h | 23 +
> 12 files changed, 3559 insertions(+), 4 deletions(-)
> create mode 100644 doc/sap-api.txt
> create mode 100644 sap/main.c
> create mode 100644 sap/manager.c
> create mode 100644 sap/manager.h
> create mode 100644 sap/sap-dummy.c
> create mode 100644 sap/sap-ste.c
I am assuming that this is the ST specific plugin. May be you can just
keep the dummy plugin only so that someone can use that as a reference.
> create mode 100644 sap/sap.h
> create mode 100644 sap/server.c
> create mode 100644 sap/server.h
I guess it would be better if you can split this into multiple patches
so that it would be easier to review.
Regards
Suraj
Sim Access plugin implements Sim Access Profile server role
according to the Bluetooth Sim Access Profile v1.1 specification.
---
.gitignore | 1 +
Makefile.am | 25 +-
acinclude.m4 | 14 +
doc/sap-api.txt | 57 ++
sap/main.c | 54 ++
sap/manager.c | 94 ++++
sap/manager.h | 21 +
sap/sap-dummy.c | 306 +++++++++++
sap/sap-ste.c | 1265 ++++++++++++++++++++++++++++++++++++++++++++++
sap/sap.h | 187 +++++++
sap/server.c | 1516 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
sap/server.h | 23 +
12 files changed, 3559 insertions(+), 4 deletions(-)
create mode 100644 doc/sap-api.txt
create mode 100644 sap/main.c
create mode 100644 sap/manager.c
create mode 100644 sap/manager.h
create mode 100644 sap/sap-dummy.c
create mode 100644 sap/sap-ste.c
create mode 100644 sap/sap.h
create mode 100644 sap/server.c
create mode 100644 sap/server.h
diff --git a/.gitignore b/.gitignore
index 07e239f..3e36a59 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,6 +35,7 @@ lib/bluetooth
src/builtin.h
src/bluetoothd
audio/telephony.c
+sap/sap.c
scripts/bluetooth.rules
scripts/97-bluetooth.rules
scripts/97-bluetooth-hid2hci.rules
diff --git a/Makefile.am b/Makefile.am
index 6e8fc7d..015d84e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -142,6 +142,20 @@ audio_libtelephony_a_SOURCES = audio/telephony.h audio/telephony-dummy.c \
audio/telephony-maemo6.c
endif
+if SAPPLUGIN
+builtin_modules += sap
+builtin_sources += sap/main.c \
+ sap/manager.h sap/manager.c \
+ sap/server.h sap/server.c \
+ sap/sap.h
+builtin_nodist += sap/sap.c
+
+noinst_LIBRARIES = sap/libsap.a
+
+sap_libsap_a_SOURCES = sap/sap.h sap/sap-dummy.c \
+ sap/sap-ste.c
+endif
+
if INPUTPLUGIN
builtin_modules += input
builtin_sources += input/main.c \
@@ -263,8 +277,8 @@ EXTRA_DIST += src/genbuiltin src/bluetooth.conf \
input/input.conf serial/serial.conf \
audio/audio.conf audio/telephony-dummy.c \
audio/telephony-maemo5.c audio/telephony-ofono.c \
- audio/telephony-maemo6.c
-
+ audio/telephony-maemo6.c \
+ sap/sap-dummy.c sap/sap-ste.c
if ALSA
alsadir = $(libdir)/alsa-lib
@@ -352,7 +366,7 @@ EXTRA_DIST += doc/manager-api.txt \
doc/service-api.txt doc/agent-api.txt doc/attribute-api.txt \
doc/serial-api.txt doc/network-api.txt \
doc/input-api.txt doc/audio-api.txt doc/control-api.txt \
- doc/hfp-api.txt doc/assigned-numbers.txt
+ doc/hfp-api.txt doc/assigned-numbers.txt doc/sap-api.txt
AM_YFLAGS = -d
@@ -387,6 +401,9 @@ src/builtin.h: src/genbuiltin $(builtin_sources)
audio/telephony.c: audio/@TELEPHONY_DRIVER@
$(AM_V_GEN)$(LN_S) $(abs_top_srcdir)/$< $@
+sap/sap.c: sap/@SAP_DRIVER@
+ $(AM_V_GEN)$(LN_S) $(abs_top_srcdir)/$< $@
+
scripts/%.rules:
$(AM_V_GEN)cp $(subst 97-,,$@) $@
@@ -397,4 +414,4 @@ lib/bluetooth/%.h: lib/%.h
$(AM_V_GEN)$(LN_S) $(abs_top_srcdir)/$< $@
clean-local:
- $(RM) -r lib/bluetooth
+ $(RM) -r lib/bluetooth
\ No newline at end of file
diff --git a/acinclude.m4 b/acinclude.m4
index 287f07d..093e9a6 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -174,6 +174,7 @@ AC_DEFUN([AC_ARG_BLUEZ], [
input_enable=yes
serial_enable=yes
network_enable=yes
+ sap_enable=yes
service_enable=yes
health_enable=no
pnat_enable=no
@@ -193,6 +194,7 @@ AC_DEFUN([AC_ARG_BLUEZ], [
configfiles_enable=yes
telephony_driver=dummy
maemo6_enable=no
+ sap_driver=dummy
AC_ARG_ENABLE(optimization, AC_HELP_STRING([--disable-optimization], [disable code optimization]), [
optimization_enable=${enableval}
@@ -210,6 +212,10 @@ AC_DEFUN([AC_ARG_BLUEZ], [
network_enable=${enableval}
])
+ AC_ARG_ENABLE(sap, AC_HELP_STRING([--disable-sap], [disable sap plugin]), [
+ sap_enable=${enableval}
+ ])
+
AC_ARG_ENABLE(serial, AC_HELP_STRING([--disable-serial], [disable serial plugin]), [
serial_enable=${enableval}
])
@@ -320,6 +326,13 @@ AC_DEFUN([AC_ARG_BLUEZ], [
hal_enable=${enableval}
])
+ AC_ARG_WITH(sap, AC_HELP_STRING([--with-sap=DRIVER], [select SAP driver]), [
+ sap_driver=${withval}
+ ])
+
+
+ AC_SUBST([SAP_DRIVER], [sap-${sap_driver}.c])
+
if (test "${fortify_enable}" = "yes"); then
CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2"
fi
@@ -351,6 +364,7 @@ AC_DEFUN([AC_ARG_BLUEZ], [
AM_CONDITIONAL(INPUTPLUGIN, test "${input_enable}" = "yes")
AM_CONDITIONAL(SERIALPLUGIN, test "${serial_enable}" = "yes")
AM_CONDITIONAL(NETWORKPLUGIN, test "${network_enable}" = "yes")
+ AM_CONDITIONAL(SAPPLUGIN, test "${sap_enable}" = "yes")
AM_CONDITIONAL(SERVICEPLUGIN, test "${service_enable}" = "yes")
AM_CONDITIONAL(HEALTHPLUGIN, test "${health_enable}" = "yes")
AM_CONDITIONAL(MCAP, test "${health_enable}" = "yes")
diff --git a/doc/sap-api.txt b/doc/sap-api.txt
new file mode 100644
index 0000000..7951f56
--- /dev/null
+++ b/doc/sap-api.txt
@@ -0,0 +1,57 @@
+BlueZ D-Bus Sim Access Profile API description
+***********************************
+
+Copyright (C) 2010 ST-Ericsson SA
+
+
+Sim Access Profile hierarchy
+============================
+
+Service org.bluez
+Interface org.bluez.SimAccess
+Object path [variable prefix]/{hci0,hci1,...}
+
+Methods void Enable()
+
+ Start up SAP server and register SDP record for it.
+
+ Possible errors: org.bluez.Error.Failed
+
+ void Disable()
+
+ Shudown SAP server and remove the SDP record.
+
+ Possible errors: org.bluez.Error.Failed
+
+ void Disconnect(boolean type)
+
+ Disconnect SAP client from the server. The 'type'
+ parameter indicates disconnection type.
+
+ True - gracefull disconnection
+ False - immediate disconnection
+
+ Possible errors: org.bluez.Error.Failed
+
+ dict GetProperties()
+
+ Return all properties for the interface. See the
+ properties section for available properties.
+
+ Possible Errors: org.bluez.Error.Failed
+
+Signals PropertyChanged(string name, variant value)
+
+ This signal indicates a changed value of the given
+ property.
+
+
+Properties boolean Enabled [readonly]
+
+ Indicates the state of the server. True if the server
+ is enabled and False otherwise.
+
+ boolean Connected [readonly]
+
+ Indicates if SAP client is connected to the server.
+
diff --git a/sap/main.c b/sap/main.c
new file mode 100644
index 0000000..b3efcf8
--- /dev/null
+++ b/sap/main.c
@@ -0,0 +1,54 @@
+/*
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 Claudio Takahasi<[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <gdbus.h>
+#include "plugin.h"
+#include "manager.h"
+
+static DBusConnection *connection;
+
+static int sap_init(void)
+{
+ connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+
+ if (!connection)
+ return -EIO;
+
+ if (sap_manager_init(connection) < 0) {
+ dbus_connection_unref(connection);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void sap_exit(void)
+{
+ sap_manager_exit();
+
+ dbus_connection_unref(connection);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(sap, VERSION,
+ BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, sap_init, sap_exit)
diff --git a/sap/manager.c b/sap/manager.c
new file mode 100644
index 0000000..972a46b
--- /dev/null
+++ b/sap/manager.c
@@ -0,0 +1,94 @@
+/*
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 Claudio Takahasi<[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <gdbus.h>
+
+#include "log.h"
+#include "adapter.h"
+#include "device.h"
+
+#include "manager.h"
+
+#include "server.h"
+
+static DBusConnection *connection = NULL;
+
+
+static int sap_server_probe(struct btd_adapter *adapter)
+{
+ const 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..5a779df
--- /dev/null
+++ b/sap/manager.h
@@ -0,0 +1,21 @@
+/*
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 Claudio Takahasi<[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+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..db1078b
--- /dev/null
+++ b/sap/sap-dummy.c
@@ -0,0 +1,306 @@
+/*
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 ST-Ericsson SA
+ *
+ * Author: Waldemar Rymarkiewicz <[email protected]> for ST-Ericsson
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <glib.h>
+#include <gdbus.h>
+
+#include "log.h"
+#include "sap.h"
+
+#define SAP_DUMMY_IFACE "org.bluez.SimAccessTest"
+#define SAP_DUMMY_PATH "/org/bluez/test"
+#define SAP_ONGOING_CALL_TIMER 5
+
+typedef enum {
+ SIM_CONNECTED = 0x00,
+ SIM_DISCONNECTED= 0x01,
+ SIM_POWERED_OFF = 0x02,
+ SIM_MISSING = 0x03
+} sim_connection_status_t;
+
+static DBusConnection *connection = NULL;
+
+static sim_connection_status_t sim_card_connection_status = SIM_DISCONNECTED;
+static void * sap_data = NULL; /* SAP server private data.*/
+static gboolean ongoing_call_status = FALSE;
+static int max_msg_size_supported = 512;
+
+void sap_connect_req(void *sap_device, uint16_t maxmsgsize)
+{
+ if (sim_card_connection_status != SIM_CONNECTED) {
+ sap_connect_rsp(sap_device, SAP_STATUS_CONNECTION_FAILED,
+ maxmsgsize);
+ return;
+ } else if(max_msg_size_supported > maxmsgsize) {
+ sap_connect_rsp(sap_device, SAP_STATUS_MAX_MSG_SIZE_TOO_SMALL,
+ max_msg_size_supported);
+ return;
+ }else if (max_msg_size_supported < maxmsgsize) {
+ sap_connect_rsp(sap_device, SAP_STATUS_MAX_MSG_SIZE_NOT_SUPPORTED,
+ max_msg_size_supported);
+ return;
+ } else if(ongoing_call_status) {
+ sap_connect_rsp(sap_device, SAP_STATUS_OK_ONGOING_CALL,
+ maxmsgsize);
+ //run_timer
+ return;
+ } else {
+ sim_card_connection_status = SIM_CONNECTED;
+ sap_data = sap_device;
+
+ sap_connect_rsp(sap_device, SAP_STATUS_OK, maxmsgsize);
+ sap_status_ind(sap_device, SAP_STATUS_CHANGE_CARD_RESET);
+ }
+}
+
+void sap_disconnect_req(void *sap_device, uint8_t linkloss)
+{
+ sim_card_connection_status = SIM_DISCONNECTED;
+ sap_data = NULL;
+ ongoing_call_status = FALSE;
+
+ if(linkloss)
+ return;
+
+ sap_disconnect_rsp(sap_device);
+}
+
+void sap_transfer_apdu_req(void *sap_device, sap_parameter *param)
+{
+ if (sim_card_connection_status == SIM_MISSING)
+ sap_transfer_apdu_rsp(sap_device, SAP_RESULT_ERROR_CARD_REMOVED,
+ NULL, 0);
+ else if (sim_card_connection_status == SIM_POWERED_OFF)
+ sap_transfer_apdu_rsp(sap_device, SAP_RESULT_ERROR_POWERED_OFF,
+ NULL, 0);
+ else if (sim_card_connection_status != SIM_CONNECTED)
+ sap_transfer_apdu_rsp(sap_device, SAP_RESULT_ERROR_NOT_ACCESSIBLE,
+ NULL, 0);
+ else
+ sap_transfer_apdu_rsp(sap_device, SAP_RESULT_OK, 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};
+
+ if (sim_card_connection_status == SIM_MISSING)
+ sap_transfer_atr_rsp(sap_device, SAP_RESULT_ERROR_CARD_REMOVED,
+ NULL, 0);
+ else if (sim_card_connection_status == SIM_POWERED_OFF)
+ sap_transfer_atr_rsp(sap_device, SAP_RESULT_ERROR_POWERED_OFF,
+ NULL, 0);
+ else if (sim_card_connection_status != SIM_CONNECTED)
+ sap_transfer_atr_rsp(sap_device, SAP_RESULT_ERROR_NO_REASON,
+ NULL, 0);
+ else
+ sap_transfer_atr_rsp(sap_device, SAP_RESULT_OK, atr, 0x0E);
+}
+
+void sap_power_sim_off_req(void *sap_device)
+{
+ if(sim_card_connection_status == SIM_MISSING)
+ sap_power_sim_off_rsp(sap_device, SAP_RESULT_ERROR_CARD_REMOVED);
+ else if (sim_card_connection_status == SIM_POWERED_OFF)
+ sap_power_sim_off_rsp(sap_device, SAP_RESULT_ERROR_POWERED_OFF);
+ else if(sim_card_connection_status != SIM_CONNECTED)
+ sap_power_sim_off_rsp(sap_device, SAP_RESULT_ERROR_NO_REASON);
+ else {
+ sap_power_sim_off_rsp(sap_device, SAP_RESULT_OK);
+ sim_card_connection_status = SIM_POWERED_OFF;
+ }
+}
+
+void sap_power_sim_on_req(void *sap_device)
+{
+ if (sim_card_connection_status == SIM_MISSING)
+ sap_power_sim_on_rsp(sap_device, SAP_RESULT_ERROR_CARD_REMOVED);
+ else if (sim_card_connection_status == SIM_POWERED_OFF) {
+ sap_power_sim_on_rsp(sap_device, SAP_RESULT_OK);
+ sim_card_connection_status = SIM_CONNECTED;
+ return;
+ }else if(sim_card_connection_status != SIM_CONNECTED)
+ sap_power_sim_on_rsp(sap_device, SAP_RESULT_ERROR_NOT_ACCESSIBLE);
+ else {
+ sap_power_sim_on_rsp(sap_device, SAP_RESULT_ERROR_NO_REASON);
+ }
+}
+
+void sap_reset_sim_req(void *sap_device)
+{
+ if (sim_card_connection_status == SIM_MISSING)
+ sap_reset_sim_rsp(sap_device, SAP_RESULT_ERROR_CARD_REMOVED);
+ else if (sim_card_connection_status == SIM_POWERED_OFF)
+ sap_reset_sim_rsp(sap_device, SAP_RESULT_ERROR_POWERED_OFF);
+ else if (sim_card_connection_status != SIM_CONNECTED)
+ sap_reset_sim_rsp(sap_device, SAP_RESULT_ERROR_NO_REASON);
+ else {
+ sap_reset_sim_rsp(sap_device, SAP_RESULT_OK);
+ sap_status_ind(sap_device, SAP_STATUS_CHANGE_CARD_RESET);
+ }
+}
+
+void sap_transfer_card_reader_status_req(void * sap_device)
+{
+ if (sim_card_connection_status != SIM_CONNECTED) {
+ sap_transfer_card_reader_status_rsp(sap_device,
+ SAP_RESULT_ERROR_NO_REASON, 0xF1);
+ return;
+ }
+ sap_transfer_card_reader_status_rsp(sap_device, SAP_RESULT_OK, 0xF1);
+}
+
+void sap_set_transport_protocol_req(void * sap_device,sap_parameter * param)
+{
+ sap_transport_protocol_rsp(sap_device, SAP_RESULT_NOT_SUPPORTED);
+}
+
+static inline DBusMessage *invalid_args(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, "org.bluez.Error.InvalidArguments",
+ "Invalid arguments in method call");
+}
+
+static DBusMessage *ongoing_call(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ dbus_bool_t ongoing;
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_BOOLEAN, &ongoing,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ if (ongoing_call_status && !ongoing) {
+ /* An ongoing call has finished. Continue connection.*/
+ sap_connect_rsp(sap_data, SAP_STATUS_OK, max_msg_size_supported);
+ sap_status_ind(sap_data, SAP_STATUS_CHANGE_CARD_RESET);
+ ongoing_call_status = ongoing;
+ } else if (!ongoing_call_status && ongoing) {
+ /* An ongoing call has started.*/
+ ongoing_call_status = ongoing;
+ }
+
+ DBG("sap-dummy: OngoingCall status set to %d", ongoing_call_status);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *max_msg_size(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ dbus_uint32_t size;
+
+ if (sim_card_connection_status == SIM_CONNECTED)
+ return g_dbus_create_error(msg, "org.bluez.Error.Failed",
+ "Can't change msg size when connected.");
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &size,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ max_msg_size_supported = size;
+
+ DBG("sap-dummy: MaxMessageSize set to %d", max_msg_size_supported);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *disconnect(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ sim_card_connection_status = SIM_DISCONNECTED;
+ sap_status_ind(sap_data, SAP_STATUS_CHANGE_CARD_NOT_ACCESSIBLE);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *card_status(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ dbus_uint32_t status;
+
+ if(sim_card_connection_status != SIM_CONNECTED)
+ return g_dbus_create_error(msg, "org.bluez.Error.Failed",
+ "Can't change msg size when connected.");
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &status,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ if (status) {
+ if (sim_card_connection_status == SIM_MISSING) {
+ sim_card_connection_status = SIM_CONNECTED;
+ sap_status_ind(sap_data, SAP_STATUS_CHANGE_CARD_INSERTED);
+ }
+ } else {
+ sim_card_connection_status = SIM_MISSING;
+ sap_status_ind(sap_data, SAP_STATUS_CHANGE_CARD_REMOVED);
+ }
+
+ DBG("sap-dummy: Card status changed to %d", status);
+
+ return dbus_message_new_method_return(msg);
+}
+
+
+static GDBusMethodTable dummy_methods[] = {
+ { "OngoingCall", "b", "", ongoing_call},
+ { "MaxMessageSize", "u", "", max_msg_size},
+ { "Disconnect", "", "", disconnect},
+ { "CardStatus", "u", "", card_status},
+ { }
+};
+
+static GDBusSignalTable dummy_signals[] = {
+ { "","" },
+ { }
+};
+
+int sap_init(void)
+{
+ connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+
+ if (g_dbus_register_interface(connection, SAP_DUMMY_PATH,
+ SAP_DUMMY_IFACE,
+ dummy_methods, dummy_signals,
+ NULL, NULL, NULL) == FALSE) {
+ error("sap-dummy interface %s init failed on path %s",
+ SAP_DUMMY_IFACE, SAP_DUMMY_PATH);
+ return -1;
+ }
+
+ return 0;
+}
+
+void sap_exit(void)
+{
+ dbus_connection_unref(connection);
+ connection = NULL;
+}
diff --git a/sap/sap-ste.c b/sap/sap-ste.c
new file mode 100644
index 0000000..e9f99b5
--- /dev/null
+++ b/sap/sap-ste.c
@@ -0,0 +1,1265 @@
+/*
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 ST-Ericsson SA
+ *
+ * Author: Waldemar Rymarkiewicz <[email protected]> for
+ * ST-Ericsson.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <fcntl.h>
+#include <errno.h>
+#include <glib.h>
+#include <unistd.h>
+
+#include "log.h"
+#include "sap.h"
+
+/** SAP_STE_MAX_MSG_SIZE - Maximum size of Sim Access Profile message
+ * supported by the server.
+ */
+#define SAP_STE_MAX_MSG_SIZE 1024
+
+/** SAP_STE_MIN_MSG_SIZE - Minimal size of Sim Access Profile message
+ * supported by the server.
+ */
+#define SAP_STE_MIN_MSG_SIZE 512
+
+/** SAP_STE_UNIX_SOCKET_NAME - Unix socket name used to communicate with
+ * SIM daemon.
+ */
+#define SAP_STE_UNIX_SOCKET_NAME "/dev/socket/catd_a"
+
+/*Sizes of SIM message fields.*/
+#define SAP_STE_MSG_LEN_SIZE 0x0002
+#define SAP_STE_MSG_TYPE_SIZE 0x0002
+#define SAP_STE_MSG_CLIENT_TAG_SIZE 0x0004
+#define SAP_STE_MSG_STATUS_SIZE 0x0004
+
+/*Header size of SIM message */
+#define SAP_STE_MSG_HEADER_SIZE ((SAP_STE_MSG_LEN_SIZE) + \
+ (SAP_STE_MSG_TYPE_SIZE) + (SAP_STE_MSG_CLIENT_TAG_SIZE))
+
+#define SAP_STE_CLIENT_TAG 0x0000
+
+/** sap_ste_protocol_t - protocol used in communication with SIM.*/
+typedef enum {
+ SAP_STE_START_SAP_REQ = 0x2D01,
+ SAP_STE_START_SAP_RSP = 0x2E01,
+ SAP_STE_END_SAP_REQ = 0x2D02,
+ SAP_STE_END_SAP_RSP = 0x2E02,
+ SAP_STE_POWER_OFF_REQ = 0x2D03,
+ SAP_STE_POWER_OFF_RSP = 0x2E03,
+ SAP_STE_POWER_ON_REQ = 0x2D04,
+ SAP_STE_POWER_ON_RSP = 0x2E04,
+ SAP_STE_RESET_REQ = 0x2D05,
+ SAP_STE_RESET_RSP = 0x2E05,
+ SAP_STE_SEND_APDU_REQ = 0x2D06,
+ SAP_STE_SEND_APDU_RSP = 0x2E06,
+ SAP_STE_GET_ATR_REQ = 0x2D07,
+ SAP_STE_GET_ATR_RSP = 0x2E07,
+ SAP_STE_GET_STATUS_REQ = 0x2D08,
+ SAP_STE_GET_STATUS_RSP = 0x2E08,
+ SAP_STE_STATUS_IND = 0x2F02
+} sap_ste_protocol_t;
+
+/** sap_ste_msg_t - Type of SIM message.*/
+typedef enum {
+ SAP_STE_SEND_APDU_MSG = 0,
+ SAP_STE_GET_ATR_MSG,
+ SAP_STE_POWER_OFF_MSG,
+ SAP_STE_POWER_ON_MSG,
+ SAP_STE_RESET_MSG,
+ SAP_STE_GET_STATUS_MSG,
+ SAP_STE_MSG_MAX,
+} sap_ste_msg_t;
+
+/** sap_ste_status_t - Status of a request.*/
+typedef enum {
+ SAP_STE_STATUS_OK = 0x00000000,
+ SAP_STE_STATUS_UNDEFINED_FAILURE = 0xFFFFFFFF,
+} sap_ste_status_t;
+
+/** sap_ste_card_status_t - Sim card status.*/
+typedef enum {
+ SAP_STE_CARD_STATUS_UNKNOWN = 0x00,
+ SAP_STE_CARD_STATUS_ACTIVE = 0x01,
+ SAP_STE_CARD_STATUS_NOT_ACTIVE = 0x02,
+ SAP_STE_CARD_STATUS_MISSING = 0x03,
+ SAP_STE_CARD_STATUS_INVALID = 0x04
+} sap_ste_card_status_t;
+
+/** SAP_STE_state_t - Sim connection state.*/
+typedef enum {
+ SAP_STE_DISABLED, /* Reader not present or removed */
+ SAP_STE_POWERED_OFF, /* Card in the reader but powered off */
+ SAP_STE_NO_CARD, /* No card in the reader */
+ SAP_STE_ENABLED, /* Card in the reader and powered on */
+ SAP_STE_STATE_MAX
+} sap_ste_state_t;
+
+/** sap_ste_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)) sap_ste_message;
+
+/** sap_ste_connection - main admin structure that keeps data about connection
+ * with sim card.
+ */
+struct sap_ste_connection {
+ GIOChannel *io;
+ sap_ste_state_t state;
+ void *sap_data;
+};
+
+static struct sap_ste_connection *connection = NULL;
+
+/** sim2sap_result - Conversion table of sap result which varies with
+ * connection state and the message type.
+ */
+static const sap_result_t sim2sap_result[SAP_STE_MSG_MAX][SAP_STE_STATE_MAX] = {
+ /* SAP results for SEND APDU message */
+ {SAP_RESULT_ERROR_NOT_ACCESSIBLE,/*for SAP_STE_DISABLED state */
+ SAP_RESULT_ERROR_POWERED_OFF, /*for SAP_STE_POWERED_OFF state */
+ SAP_RESULT_ERROR_CARD_REMOVED, /*for SAP_STE_NO_CARD state */
+ SAP_RESULT_ERROR_NO_REASON}, /*for SAP_STE_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 connection_uninit(struct sap_ste_connection *conn);
+static int connection_watch(int sock, void *sap_data);
+
+/**
+ * get_sap_result - Convert STE sim status to sap result.
+ * @conn; Connection info structure.
+ * @msg; Sim message type.
+ * @status; Sim status.
+ *
+ * Returns:
+ * SAP result.
+ */
+static sap_result_t get_sap_result(struct sap_ste_connection *conn,
+ sap_ste_msg_t msg, sap_ste_status_t status)
+{
+ if (!conn)
+ return SAP_RESULT_ERROR_NO_REASON;
+
+ switch (status){
+ case SAP_STE_STATUS_OK:
+ return SAP_RESULT_OK;
+
+ case SAP_STE_STATUS_UNDEFINED_FAILURE:
+ return sim2sap_result[msg][conn->state];
+
+ default:
+ error("Cannot convert sap_ste_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(sap_ste_card_status_t status)
+{
+ switch (status){
+ case SAP_STE_CARD_STATUS_UNKNOWN:
+ return ICC_READER_UNSPECIFIED_ERROR;
+
+ case SAP_STE_CARD_STATUS_NOT_ACTIVE:
+ return ICC_READER_NOT_PRESENT;
+
+ case SAP_STE_CARD_STATUS_ACTIVE:
+ return ICC_READER_CARD_POWERED_ON;
+
+ case SAP_STE_CARD_STATUS_INVALID:
+ return ICC_READER_CARD_POWERED_OFF;
+
+ case SAP_STE_CARD_STATUS_MISSING:
+ return ICC_READER_NO_CARD;
+
+ default:
+ error("Cannot convert sap_ste_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.
+ * @conn; 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 sap_ste_connection *conn,
+ sap_ste_card_status_t status)
+{
+ if (!conn)
+ return SAP_STATUS_CHANGE_UNKNOWN_ERROR;
+
+ switch (status){
+ case SAP_STE_CARD_STATUS_UNKNOWN:
+ return SAP_STATUS_CHANGE_UNKNOWN_ERROR;
+
+ case SAP_STE_CARD_STATUS_ACTIVE:
+ conn->state = SAP_STE_ENABLED;
+ return SAP_STATUS_CHANGE_CARD_RESET;
+
+ case SAP_STE_CARD_STATUS_NOT_ACTIVE:
+ conn->state = SAP_STE_DISABLED;
+ return SAP_STATUS_CHANGE_CARD_NOT_ACCESSIBLE;
+
+ case SAP_STE_CARD_STATUS_MISSING:
+ conn->state = SAP_STE_DISABLED;
+ return SAP_STATUS_CHANGE_CARD_REMOVED;
+
+ case SAP_STE_CARD_STATUS_INVALID:
+ conn->state = SAP_STE_DISABLED;
+ return SAP_STATUS_CHANGE_CARD_NOT_ACCESSIBLE;
+
+ default:
+ error("Cannot convert sap_ste_status_change to \
+ sap_status_change.");
+ return SAP_STATUS_CHANGE_UNKNOWN_ERROR;
+ }
+}
+/**
+ * send_message - Send Sim message to Sim daemon.
+ * @conn; 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 sap_ste_connection *conn,
+ sap_ste_message *buf, gsize size)
+{
+ gsize written = 0;
+ GIOError gerr;
+
+ DBG("[STE_DRV] send_message: conn %p, buf %p size %d", conn, buf,
+ (int) size);
+
+ gerr = g_io_channel_write(conn->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;
+}
+
+/**
+ * sap_ste_start_sap_req - Create and send start SAP request message.
+ * @conn; Connection info structure.
+ *
+ * Returns:
+ * O if success or negaive integer in case of error.
+ */
+static int sap_ste_start_sap_req(struct sap_ste_connection *conn)
+{
+ int err = 0;
+ sap_ste_message *msg = NULL;
+ gsize msg_size = SAP_STE_MSG_HEADER_SIZE;
+
+ DBG("[STE_DRV] sap_ste_start_sap_req: conn %p", conn);
+
+ msg = (sap_ste_message *)g_malloc0(msg_size);
+ if (!msg)
+ return -ENOMEM;
+
+ msg->len = msg_size - SAP_STE_MSG_LEN_SIZE;
+ msg->id = SAP_STE_START_SAP_REQ;
+ msg->client_tag = SAP_STE_CLIENT_TAG;
+
+ err = send_message(conn, msg, msg_size);
+
+ g_free(msg);
+ return err;
+}
+
+/**
+ * sap_ste_end_sap_req - Create and send end SAP request message.
+ * @conn; Connection info structure.
+ *
+ * Returns:
+ * O if success or negaive integer in case of error.
+ */
+static int sap_ste_end_sap_req(struct sap_ste_connection *conn)
+{
+ int err = 0;
+ sap_ste_message *msg = NULL;
+ gsize msg_size = SAP_STE_MSG_HEADER_SIZE;
+
+ DBG("[STE_DRV] sap_ste_end_sap_req: conn %p", conn);
+
+ msg = (sap_ste_message *)g_malloc0(msg_size);
+ if (!msg)
+ return -ENOMEM;
+
+ msg->len = msg_size - SAP_STE_MSG_LEN_SIZE;
+ msg->id = SAP_STE_END_SAP_REQ;
+ msg->client_tag = SAP_STE_CLIENT_TAG;
+
+ err = send_message(conn, msg, msg_size);
+
+ g_free(msg);
+ return err;
+}
+
+/**
+ * sap_ste_end_sap_req - Create and send transfer apdu request message.
+ * @conn; Connection info structure.
+ *
+ * Returns:
+ * O if success or negaive integer in case of error.
+ */
+static int sap_ste_send_apdu_req(struct sap_ste_connection *conn,
+ sap_parameter *param)
+{
+ int err = 0;
+ sap_ste_message *msg = NULL;
+ gsize msg_size = SAP_STE_MSG_HEADER_SIZE + param->len;
+
+ DBG("[STE_DRV] sap_ste_send_apdu_req: conn %p param %p len %d",
+ conn, param, param->len);
+
+ msg = (sap_ste_message *)g_malloc0(msg_size);
+ if (!msg)
+ return -ENOMEM;
+
+ msg->len = msg_size - SAP_STE_MSG_LEN_SIZE;
+ msg->id = SAP_STE_SEND_APDU_REQ;
+ msg->client_tag = SAP_STE_CLIENT_TAG;
+ memcpy(msg->payload, param->val, param->len);
+
+ err = send_message(conn, msg, msg_size);
+
+ g_free(msg);
+ return err;
+}
+
+/**
+ * sap_ste_get_atr_req - Create and send get ATR request message.
+ * @conn; Connection info structure.
+ *
+ * Returns:
+ * O if success or negaive integer in case of error.
+ */
+static int sap_ste_get_atr_req(struct sap_ste_connection *conn)
+{
+ int err = 0;
+ sap_ste_message *msg = NULL;
+ gsize msg_size = SAP_STE_MSG_HEADER_SIZE;
+
+ DBG("[STE_DRV] sap_ste_get_atr_req: conn %p", conn);
+
+ msg = (sap_ste_message *)g_malloc0(msg_size);
+ if (!msg)
+ return -ENOMEM;
+
+ msg->len = msg_size - SAP_STE_MSG_LEN_SIZE;
+ msg->id = SAP_STE_GET_ATR_REQ;
+ msg->client_tag = SAP_STE_CLIENT_TAG;
+
+ err = send_message(conn, msg, msg_size);
+
+ g_free(msg);
+ return err;
+}
+
+/**
+ * sap_ste_power_off_req - Create and send power off request message.
+ * @conn; Connection info structure.
+ *
+ * Returns:
+ * O if success or negaive integer in case of error.
+ */
+static int sap_ste_power_off_req(struct sap_ste_connection *conn)
+{
+ int err = 0;
+ sap_ste_message *msg = NULL;
+ gsize msg_size = SAP_STE_MSG_HEADER_SIZE;
+
+ DBG("[STE_DRV] sap_ste_power_off_req: conn %p", conn);
+
+ msg = (sap_ste_message *)g_malloc0(msg_size);
+ if (!msg)
+ return -ENOMEM;
+
+ msg->len = msg_size - SAP_STE_MSG_LEN_SIZE;
+ msg->id = SAP_STE_POWER_OFF_REQ;
+ msg->client_tag = SAP_STE_CLIENT_TAG;
+
+ err = send_message(conn, msg, msg_size);
+
+ g_free(msg);
+ return err;
+}
+
+/**
+ * sap_ste_power_on_req - Create and send power on request message.
+ * @conn; Connection info structure.
+ *
+ * Returns:
+ * O if success or negaive integer in case of error.
+ */
+static int sap_ste_power_on_req(struct sap_ste_connection *conn)
+{
+ int err = 0;
+ sap_ste_message *msg = NULL;
+ gsize msg_size = SAP_STE_MSG_HEADER_SIZE;
+
+ DBG("[STE_DRV] sap_ste_power_on_req: conn %p", conn);
+
+ msg = (sap_ste_message *)g_malloc0(msg_size);
+ if (!msg)
+ return -ENOMEM;
+
+ msg->len = msg_size - SAP_STE_MSG_LEN_SIZE;
+ msg->id = SAP_STE_POWER_ON_REQ;
+ msg->client_tag = SAP_STE_CLIENT_TAG;
+
+ err = send_message(conn, msg, msg_size);
+
+ g_free(msg);
+ return err;
+}
+
+/**
+ * sap_ste_reset_req - Create and send card reset request message.
+ * @conn; Connection info structure.
+ *
+ * Returns:
+ * O if success or negaive integer in case of error.
+ */
+static int sap_ste_reset_req(struct sap_ste_connection *conn)
+{
+ int err = 0;
+ sap_ste_message *msg = NULL;
+ gsize msg_size = SAP_STE_MSG_HEADER_SIZE;
+
+ DBG("[STE_DRV] sap_ste_reset_req: conn %p", conn);
+
+ msg = (sap_ste_message *)g_malloc0(msg_size);
+ if (!msg)
+ return -ENOMEM;
+
+ msg->len = msg_size - SAP_STE_MSG_LEN_SIZE;
+ msg->id = SAP_STE_RESET_REQ;
+ msg->client_tag = SAP_STE_CLIENT_TAG;
+
+ err = send_message(conn, msg, msg_size);
+
+ g_free(msg);
+ return err;
+}
+
+/**
+ * sap_ste_get_status_req - Create and send card status request message.
+ * @conn; Connection info structure.
+ *
+ * Returns:
+ * O if success or negaive integer in case of error.
+ */
+static int sap_ste_get_status_req(struct sap_ste_connection *conn)
+{
+ int err = 0;
+ sap_ste_message *msg = NULL;
+ gsize msg_size = SAP_STE_MSG_HEADER_SIZE;
+
+ DBG("[STE_DRV] sap_ste_get_status_req: conn %p", conn);
+
+ msg = (sap_ste_message *)g_malloc0(msg_size);
+ if (!msg)
+ return -ENOMEM;
+
+ msg->len = msg_size - SAP_STE_MSG_LEN_SIZE;
+ msg->id = SAP_STE_GET_STATUS_REQ;
+ msg->client_tag = SAP_STE_CLIENT_TAG;
+
+ err = send_message(conn, msg, msg_size);
+
+ g_free(msg);
+ return err;
+}
+
+/**
+ * sap_ste_start_sap_rsp - Handle start SAP response message.
+ * @conn; Connection info structure.
+ * @msg; Response message.
+ */
+static void sap_ste_start_sap_rsp(struct sap_ste_connection *conn,
+ sap_ste_message * msg)
+{
+ uint32_t *status;
+
+ DBG("[STE_DRV] sap_ste_start_sap_rsp: conn %p (conn %p) msg %p",
+ conn, connection, msg );
+ if (msg && conn) {
+ status = (uint32_t*) msg->payload;
+ if (*status == SAP_STE_STATUS_OK)
+ sap_connect_rsp(conn->sap_data, SAP_STATUS_OK, 0);
+ else {
+ sap_connect_rsp(conn->sap_data, SAP_STATUS_CONNECTION_FAILED, 0);
+ connection_uninit(conn);
+ }
+ }
+}
+
+/**
+ * sap_ste_end_sap_rsp - Handle end SAP response message.
+ * @conn; Connection info structure.
+ * @msg; Response message.
+ */
+static void sap_ste_end_sap_rsp(struct sap_ste_connection *conn,
+ sap_ste_message * msg)
+{
+ DBG("[STE_DRV] sap_ste_end_sap_rsp: conn %p (conn %p) msg %p",
+ conn, connection, msg );
+ if (msg && conn) {
+ sap_disconnect_rsp(conn->sap_data);
+ connection_uninit(conn);
+ }
+}
+
+/**
+ * sap_ste_send_apdu_rsp - Handle transfer apdu response message.
+ * @conn; Connection info structure.
+ * @msg; Response message.
+ */
+static void sap_ste_send_apdu_rsp(struct sap_ste_connection *conn,
+ sap_ste_message * msg)
+{
+ uint32_t *status;
+ sap_result_t sr;
+ uint8_t *apdu = NULL;
+ uint16_t len = 0;
+
+ DBG("[STE_DRV] sap_ste_send_apdu_rsp: conn %p (conn %p) msg %p",
+ conn, connection, msg );
+
+ if (msg && conn) {
+ status = (uint32_t*) msg->payload;
+ if (*status == SAP_STE_STATUS_OK) {
+ apdu = (uint8_t *)(msg->payload + SAP_STE_MSG_STATUS_SIZE);
+ len = msg->len - (SAP_STE_MSG_HEADER_SIZE) +
+ SAP_STE_MSG_LEN_SIZE - SAP_STE_MSG_STATUS_SIZE;
+ }
+
+ sr = get_sap_result(conn, SAP_STE_SEND_APDU_MSG, *status);
+ sap_transfer_apdu_rsp(conn->sap_data, sr, apdu, len);
+ }
+}
+
+/**
+ * sap_ste_get_atr_rsp - Handle get ATR response message.
+ * @conn; Connection info structure.
+ * @msg; Response message.
+ */
+static void sap_ste_get_atr_rsp(struct sap_ste_connection *conn,
+ sap_ste_message * msg)
+{
+ uint32_t *status;
+ sap_result_t sr;
+ uint8_t *atr = NULL;
+ uint16_t len = 0;
+
+ DBG("[STE_DRV] sap_ste_get_atr_rsp: conn %p (conn %p) msg %p",
+ conn, connection, msg );
+
+ if (msg && conn) {
+ status = (uint32_t*) msg->payload;
+ if (*status == SAP_STE_STATUS_OK) {
+ atr = (uint8_t *)(msg->payload + SAP_STE_MSG_STATUS_SIZE);
+ len = msg->len - (SAP_STE_MSG_HEADER_SIZE) +
+ SAP_STE_MSG_LEN_SIZE;
+ }
+
+ sr = get_sap_result(conn, SAP_STE_GET_ATR_MSG, *status);
+ sap_transfer_atr_rsp(conn->sap_data, sr, atr, len);
+ }
+}
+
+/**
+ * sap_ste_power_off_rsp - Handle power off response message.
+ * @conn; Connection info structure.
+ * @msg; Response message.
+ */
+static void sap_ste_power_off_rsp(struct sap_ste_connection *conn,
+ sap_ste_message * msg)
+{
+ uint32_t *status;
+ sap_result_t sr;
+
+ DBG("[STE_DRV] sap_ste_power_off_rsp: conn %p (conn %p) msg %p",
+ conn, connection, msg );
+
+ if (msg && conn) {
+ status = (uint32_t *) msg->payload;
+ if (*status == SAP_STE_STATUS_OK)
+ conn->state = SAP_STE_POWERED_OFF;
+
+ sr = get_sap_result(conn, SAP_STE_POWER_OFF_MSG, *status);
+ sap_power_sim_off_rsp(conn->sap_data, sr);
+ }
+}
+
+/**
+ * sap_ste_power_on_rsp - Handle power on response message.
+ * @conn; Connection info structure.
+ * @msg; Response message.
+ */
+static void sap_ste_power_on_rsp(struct sap_ste_connection *conn,
+ sap_ste_message * msg)
+{
+ uint32_t *status;
+ sap_result_t sr;
+
+ DBG("[STE_DRV] sap_ste_power_on_rsp: conn %p (conn %p) msg %p",
+ conn, connection, msg );
+
+ if (msg && conn) {
+ status = (uint32_t *) msg->payload;
+ if (*status == SAP_STE_STATUS_OK)
+ conn->state = SAP_STE_ENABLED;
+
+ sr = get_sap_result(conn, SAP_STE_POWER_ON_MSG, *status);
+ sap_power_sim_on_rsp(conn->sap_data, sr);
+ }
+}
+
+/**
+ * sap_ste_reset_rsp - Handle reset response message.
+ * @conn; Connection info structure.
+ * @msg; Response message.
+ */
+static void sap_ste_reset_rsp(struct sap_ste_connection *conn,
+ sap_ste_message * msg)
+{
+ uint32_t *status;
+ sap_result_t sr;
+
+ DBG("[STE_DRV] sap_ste_reset_rsp: conn %p (conn %p) msg %p",
+ conn, connection, msg );
+
+ if (msg && conn) {
+ status = (uint32_t *) msg->payload;
+ if (*status == SAP_STE_STATUS_OK)
+ conn->state = SAP_STE_ENABLED;
+
+ sr = get_sap_result(conn, SAP_STE_RESET_MSG, *status);
+ sap_reset_sim_rsp(conn->sap_data, sr);
+ }
+}
+
+/**
+ * sap_ste_get_status_rsp - Handle card status response message.
+ * @conn; Connection info structure.
+ * @msg; Response message.
+ */
+static void sap_ste_get_status_rsp(struct sap_ste_connection *conn,
+ sap_ste_message * msg)
+{
+ uint8_t *p = NULL;
+ uint32_t *status;
+ sap_result_t sr;
+ sap_ste_card_status_t cs;
+ icc_reader_status_t iccrs;
+
+ DBG("[STE_DRV] sap_ste_get_status_rsp: conn %p (conn %p) msg %p",
+ conn, connection, msg );
+
+ if (msg && conn) {
+ p = msg->payload;
+ status = (uint32_t *)p; p += sizeof(uint32_t);
+ cs = *((uint16_t *)p);
+
+ iccrs = get_sap_reader_status(cs);
+ sr = get_sap_result(conn, SAP_STE_GET_STATUS_MSG, *status);
+ sap_transfer_card_reader_status_rsp(conn->sap_data, sr, iccrs);
+ }
+}
+
+/**
+ * sap_ste_status_ind - Handle status indication message.
+ * @conn; Connection info structure.
+ * @msg; Response message.
+ */
+static void sap_ste_status_ind(struct sap_ste_connection *conn,
+ sap_ste_message * msg)
+{
+ sap_status_change_t sc;
+ sap_ste_card_status_t cs;
+ uint32_t *status;
+
+ DBG("[STE_DRV] sap_ste_status_ind: conn %p (conn %p) msg %p",
+ conn, connection, msg );
+
+ if (msg && conn) {
+ status = (uint32_t *) msg->payload;
+ cs = *status;
+ sc = sap_status_change(conn, cs);
+
+ sap_status_ind(conn->sap_data, sc);
+ }
+}
+
+/**
+ * handle_msg - Handle messages from Sim daemon.
+ * @conn; 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 sap_ste_connection *conn, unsigned char *buf,
+ gsize size)
+{
+ unsigned char *iter = buf;
+ sap_ste_message * msg = (sap_ste_message *) buf;
+ gssize msize = (gssize) size;
+
+ DBG("[STE_DRV] handle_msg: msg %p conn %p", msg, conn);
+
+ if (msg == NULL || conn == NULL)
+ return -EFAULT;
+
+ do {
+ DBG("[STE_DRV] handle_msg: msize %d msg->len %d.",
+ (int)msize, msg->len);
+
+ /* Message must be at least size of header len */
+ if (msize < SAP_STE_MSG_HEADER_SIZE) {
+ error("[STE_DRV] Invalid message size.");
+ return -EBADMSG;
+ }
+
+ /* Message must be completed. */
+ if (msize < (SAP_STE_MSG_LEN_SIZE + msg->len)) {
+ error("[STE_DRV] Not complete message.");
+ return -EBADMSG;
+ }
+
+ switch (msg->id){
+ case SAP_STE_START_SAP_RSP:
+ sap_ste_start_sap_rsp(conn, msg);
+ break;
+
+ case SAP_STE_END_SAP_RSP:
+ sap_ste_end_sap_rsp(conn, msg);
+ break;
+
+ case SAP_STE_SEND_APDU_RSP:
+ sap_ste_send_apdu_rsp(conn, msg);
+ break;
+
+ case SAP_STE_GET_ATR_RSP:
+ sap_ste_get_atr_rsp(conn, msg);
+ break;
+
+ case SAP_STE_POWER_OFF_RSP:
+ sap_ste_power_off_rsp(conn, msg);
+ break;
+
+ case SAP_STE_POWER_ON_RSP:
+ sap_ste_power_on_rsp(conn, msg);
+ break;
+
+ case SAP_STE_RESET_RSP:
+ sap_ste_reset_rsp(conn, msg);
+ break;
+
+ case SAP_STE_GET_STATUS_RSP:
+ sap_ste_get_status_rsp(conn, msg);
+ break;
+
+ case SAP_STE_STATUS_IND:
+ sap_ste_status_ind(conn, 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 -= (SAP_STE_MSG_HEADER_SIZE +
+ (msg->len - (SAP_STE_MSG_HEADER_SIZE) +
+ SAP_STE_MSG_LEN_SIZE));
+
+ /* Move msg ponter to then next message if any */
+ iter += (msg->len + SAP_STE_MSG_LEN_SIZE);
+ msg = (sap_ste_message *)iter;
+ } while (msize > 0);
+
+ return 0;
+}
+
+/**
+ * connection_io_data_cb - Handle data on socket to Sim daemon.
+ * @io; Connection info structure.
+ * @conn; Conndition that triggered this callback.
+ * @data; Data buffor.
+ *
+ * Returns:
+ * True if @data was handled, False otherwise.
+ */
+static gboolean connection_io_data_cb(GIOChannel *io, GIOCondition cond,
+ gpointer data)
+{
+ GIOError err = G_IO_ERROR_NONE;
+ unsigned char buf[SAP_STE_MAX_MSG_SIZE];
+ gsize read_bytes = 0;
+
+ if (cond & G_IO_NVAL) {
+ DBG("[STE_DRV] NVAL on sim socket");
+ return FALSE;
+ }
+
+ if (cond & G_IO_HUP) {
+ DBG("[STE_DRV] HUP on sim socket");
+ return FALSE;
+ }
+
+ if (cond & G_IO_ERR) {
+ DBG("[STE_DRV] ERR on sim socket");
+ return FALSE;
+ }
+
+ 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;
+}
+
+/**
+ * connection_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 connection_io_destroy_cb(void *data)
+{
+ struct sap_ste_connection *conn = (struct sap_ste_connection *)data;
+
+ if (conn && connection) {
+ DBG("[STE_DRV] connection_io_destroy_cb: conn %p conn %p io %p",
+ conn, connection, conn->io);
+
+ g_io_channel_unref(conn->io);
+ g_io_channel_shutdown(conn->io, TRUE, NULL);
+ g_free(conn);
+ connection = NULL;
+ }
+}
+
+/**
+ * connection_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 connection_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, SAP_STE_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;
+ }
+
+ DBG("[STE_DRV] connection_init: sock %d ",sock);
+
+ /* Start watching incoming data */
+ if (connection_watch(sock, sap_data) < 0)
+ goto drop;
+
+ return 0;
+
+drop:
+ DBG("[STE_DRV] connection_init: drop!");
+ close(sock);
+ return -errno;
+}
+
+/**
+ * connection_uninit - Disconnect from Sim daemon.
+ * @conn; Connection info structure.
+ */
+static void connection_uninit(struct sap_ste_connection *conn)
+{
+ DBG("[STE_DRV] connection_uninit: conn %p connection %p", conn,
+ connection);
+
+ if (!conn)
+ return;
+
+ g_io_channel_shutdown(conn->io, TRUE, NULL);
+ g_io_channel_unref(conn->io);
+ g_free(conn);
+
+ connection = NULL;
+}
+
+
+/**
+ * connection_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 connection_watch(int sock, void *sap_data)
+{
+ GIOChannel *io = NULL;
+
+ DBG("[STE_DRV] connection_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);
+
+
+ connection = g_new0(struct sap_ste_connection, 1);
+ if (!connection) {
+ error("[STE_DRV] connection_watch: connection %p io %p",
+ connection, io);
+ g_io_channel_shutdown(io, TRUE, NULL);
+ g_io_channel_unref(io);
+ return -1;
+ }
+
+ connection->io = io;
+ connection->sap_data = sap_data;
+ connection->state = SAP_STE_DISABLED;
+
+ g_io_add_watch_full(io, G_PRIORITY_DEFAULT,
+ G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ connection_io_data_cb, connection, connection_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)
+{
+
+ DBG("[STE_DRV] sap_connect_req: conn %p sap_device %p maxmsgsize %d",
+ connection, sap_device, maxmsgsize);
+
+ if (maxmsgsize < SAP_STE_MIN_MSG_SIZE) {
+ sap_connect_rsp(sap_device, SAP_STATUS_MAX_MSG_SIZE_TOO_SMALL,
+ SAP_STE_MAX_MSG_SIZE);
+ return;
+ }
+
+ if (maxmsgsize > SAP_STE_MAX_MSG_SIZE) {
+ sap_connect_rsp(sap_device, SAP_STATUS_MAX_MSG_SIZE_NOT_SUPPORTED,
+ SAP_STE_MAX_MSG_SIZE);
+ return;
+ }
+
+ if (connection_init(sap_device) < 0) {
+ DBG("[STE_DRV] connection_init: failed!");
+ sap_connect_rsp(sap_device, SAP_STATUS_CONNECTION_FAILED, 0);
+ return;
+ }
+
+ if (connection && connection->state == SAP_STE_DISABLED) {
+ if (sap_ste_start_sap_req(connection) < 0) {
+ sap_connect_rsp(sap_device, SAP_STATUS_CONNECTION_FAILED,
+ SAP_STE_MAX_MSG_SIZE);
+ connection_uninit(connection);
+ }
+ } else {
+ DBG("[STE_DRV] Connection failed! (connection %p) ", connection);
+ 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)
+{
+ DBG("[STE_DRV] sap_disconnect_req: conn %p sap_device %p linkloss %d",
+ connection, sap_device, linkloss);
+ if (connection && linkloss) {
+ connection_uninit(connection);
+ return;
+ }
+
+ if (connection && connection->state != SAP_STE_DISABLED) {
+ if (sap_ste_end_sap_req(connection) < 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;
+
+ DBG("[STE_DRV] sap_transfer_apdu_req: conn %p sap_device %p param %p\
+ param len %d", connection, sap_device, param, param->len);
+
+ if (connection && connection->state == SAP_STE_ENABLED) {
+ if (sap_ste_send_apdu_req(connection, param) < 0)
+ sap_transfer_apdu_rsp(sap_device,
+ SAP_RESULT_ERROR_NO_REASON, NULL, 0);
+ } else {
+ sr = get_sap_result(connection, SAP_STE_SEND_APDU_MSG,
+ SAP_STE_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;
+
+ DBG("[STE_DRV] sap_transfer_atr_req: conn %p, sap_device %p",
+ connection, sap_device);
+
+ if (connection && connection->state == SAP_STE_ENABLED) {
+ if (sap_ste_get_atr_req(connection) < 0)
+ sap_transfer_atr_rsp(sap_device,
+ SAP_RESULT_ERROR_NO_DATA, NULL, 0);
+ } else {
+ sr = get_sap_result(connection, SAP_STE_GET_ATR_MSG,
+ SAP_STE_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;
+
+ DBG("[STE_DRV] sap_power_sim_off_req: conn %p, sap_device %p",
+ connection, sap_device);
+
+ if (connection && connection->state == SAP_STE_ENABLED) {
+ if (sap_ste_power_off_req(connection) < 0)
+ sap_power_sim_off_rsp(sap_device,
+ SAP_RESULT_ERROR_NO_REASON);
+ } else {
+ sr = get_sap_result(connection, SAP_STE_POWER_OFF_MSG,
+ SAP_STE_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;
+
+ DBG("[STE_DRV] sap_power_sim_on_req: conn %p, sap_device %p",
+ connection, sap_device);
+
+ if (connection && connection->state == SAP_STE_POWERED_OFF) {
+ if (sap_ste_power_on_req(connection) < 0)
+ sap_power_sim_on_rsp(sap_device,
+ SAP_RESULT_ERROR_NO_REASON);
+ } else {
+ sr = get_sap_result(connection, SAP_STE_POWER_ON_MSG,
+ SAP_STE_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;
+
+ DBG("[STE_DRV] sap_reset_sim_req: conn %p, sap_device %p",
+ connection, sap_device);
+
+ if (connection && connection->state == SAP_STE_ENABLED) {
+ if (sap_ste_reset_req(connection) < 0)
+ sap_reset_sim_rsp(sap_device,
+ SAP_RESULT_ERROR_NO_REASON);
+ } else {
+ sr = get_sap_result(connection, SAP_STE_RESET_MSG,
+ SAP_STE_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;
+
+ DBG("[STE_DRV] sap_transfer_card_reader_status_req: conn %p, \
+ sap_device %p", connection, sap_device);
+
+ if (connection && connection->state != SAP_STE_DISABLED) {
+ if (sap_ste_get_status_req(connection) < 0)
+ sap_transfer_card_reader_status_rsp(sap_device,
+ SAP_RESULT_ERROR_NO_DATA,
+ ICC_READER_UNSPECIFIED_ERROR);
+ } else {
+ sr = get_sap_result(connection, SAP_STE_GET_STATUS_MSG,
+ SAP_STE_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)
+{
+ sap_transport_protocol_rsp(sap_device, SAP_RESULT_NOT_SUPPORTED);
+}
+
+int sap_init(void)
+{
+ return 0;
+}
+
+void sap_exit(void)
+{
+}
diff --git a/sap/sap.h b/sap/sap.h
new file mode 100644
index 0000000..a9189fc
--- /dev/null
+++ b/sap/sap.h
@@ -0,0 +1,187 @@
+/*
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 ST-Ericsson SA
+ * Copyright (C) 2010 Claudio Takahasi<[email protected]>
+ *
+ * Author: Marek Skowron <[email protected]> for ST-Ericsson.
+ * Author: Waldemar Rymarkiewicz <[email protected]> for ST-Ericsson.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdint.h>
+#include <glib.h>
+
+ #define SAP_VERSION 0x0101
+
+/* Connection Status - SAP v1.1 section 5.2.2 */
+typedef enum {
+ SAP_STATUS_OK = 0x00,
+ SAP_STATUS_CONNECTION_FAILED = 0x01,
+ SAP_STATUS_MAX_MSG_SIZE_NOT_SUPPORTED = 0x02,
+ SAP_STATUS_MAX_MSG_SIZE_TOO_SMALL = 0x03,
+ SAP_STATUS_OK_ONGOING_CALL = 0x04
+} sap_status_t;
+
+/* Disconnection Type - SAP v1.1 section 5.2.3 */
+typedef enum {
+ SAP_DISCONNECTION_TYPE_GRACEFUL = 0x00,
+ SAP_DISCONNECTION_TYPE_IMMEDIATE = 0x01,
+ SAP_DISCONNECTION_TYPE_CLIENT = 0xFF
+} sap_disconnection_type_t;
+
+/* Result codes - SAP v1.1 section 5.2.4 */
+typedef enum {
+ SAP_RESULT_OK = 0x00,
+ SAP_RESULT_ERROR_NO_REASON = 0x01,
+ SAP_RESULT_ERROR_NOT_ACCESSIBLE = 0x02,
+ SAP_RESULT_ERROR_POWERED_OFF = 0x03,
+ SAP_RESULT_ERROR_CARD_REMOVED = 0x04,
+ SAP_RESULT_ERROR_POWERED_ON = 0x05,
+ SAP_RESULT_ERROR_NO_DATA = 0x06,
+ SAP_RESULT_NOT_SUPPORTED = 0x07
+} sap_result_t;
+
+/* Status Change - SAP v1.1 section 5.2.8 */
+typedef enum {
+ SAP_STATUS_CHANGE_UNKNOWN_ERROR = 0x00,
+ SAP_STATUS_CHANGE_CARD_RESET = 0x01,
+ SAP_STATUS_CHANGE_CARD_NOT_ACCESSIBLE = 0x02,
+ SAP_STATUS_CHANGE_CARD_REMOVED = 0x03,
+ SAP_STATUS_CHANGE_CARD_INSERTED = 0x04,
+ SAP_STATUS_CHANGE_CARD_RECOVERED = 0x05
+} sap_status_change_t;
+
+/* Message format - SAP v1.1 section 5.1 */
+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,
+ SAP_CONNECT_RESP = 0x01,
+ SAP_DISCONNECT_REQ = 0x02,
+ SAP_DISCONNECT_RESP = 0x03,
+ SAP_DISCONNECT_IND = 0x04,
+ SAP_TRANSFER_APDU_REQ = 0x05,
+ SAP_TRANSFER_APDU_RESP = 0x06,
+ SAP_TRANSFER_ATR_REQ = 0x07,
+ SAP_TRANSFER_ATR_RESP = 0x08,
+ SAP_POWER_SIM_OFF_REQ = 0x09,
+ SAP_POWER_SIM_OFF_RESP = 0x0A,
+ SAP_POWER_SIM_ON_REQ = 0x0B,
+ SAP_POWER_SIM_ON_RESP = 0x0C,
+ SAP_RESET_SIM_REQ = 0x0D,
+ SAP_RESET_SIM_RESP = 0x0E,
+ SAP_TRANSFER_CARD_READER_STATUS_REQ = 0x0F,
+ SAP_TRANSFER_CARD_READER_STATUS_RESP = 0x10,
+ SAP_STATUS_IND = 0x11,
+ SAP_ERROR_RESP = 0x12,
+ SAP_SET_TRANSPORT_PROTOCOL_REQ = 0x13,
+ SAP_SET_TRANSPORT_PROTOCOL_RESP = 0x14,
+} sap_protocol;
+
+/* Parameters Ids - SAP 1.1 section 5.2 */
+#define SAP_PARAM_ID_MAX_MSG_SIZE 0x00
+#define SAP_PARAM_ID_MAX_MSG_SIZE_LEN 0x02
+
+#define SAP_PARAM_ID_CONN_STATUS 0x01
+#define SAP_PARAM_ID_CONN_STATUS_LEN 0x01
+
+#define SAP_PARAM_ID_RESULT_CODE 0x02
+#define SAP_PARAM_ID_RESULT_CODE_LEN 0x01
+
+#define SAP_PARAM_ID_DISCONNECT_IND 0x03
+#define SAP_PARAM_ID_DISCONNECT_IND_LEN 0x01
+
+#define SAP_PARAM_ID_COMMAND_APDU 0x04
+#define SAP_PARAM_ID_RESPONSE_APDU 0x05
+#define SAP_PARAM_ID_ATR 0x06
+
+#define SAP_PARAM_ID_CARD_READER_STATUS 0x07
+#define SAP_PARAM_ID_CARD_READER_STATUS_LEN 0x01
+
+#define SAP_PARAM_ID_STATUS_CHANGE 0x08
+#define SAP_PARAM_ID_STATUS_CHANGE_LEN 0x01
+
+#define SAP_PARAM_ID_TRANSPORT_PROTOCOL 0x09
+#define SAP_PARAM_ID_TRANSPORT_PROTOCOL_LEN 0x01
+
+#define SAP_PARAM_ID_COMMAND_APDU7816 0x10
+
+/* Transport Protocol - SAP v1.1 section 5.2.9 */
+#define SAP_TRANSPORT_PROTOCOL_T0 0x00
+#define SAP_TRANSPORT_PROTOCOL_T1 0x01
+
+/*SAP driver init and exit routines. Implemented by sap-*.c */
+int sap_init(void);
+void sap_exit(void);
+
+/* SAP requests implemented by sap-*.c */
+void sap_connect_req(void *sap_device, uint16_t maxmsgsize);
+void sap_disconnect_req(void *sap_device, uint8_t linkloss);
+void sap_transfer_apdu_req(void *sap_device, 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);
+
+/*SAP responses to SAP requests. Implemented by server.c */
+int sap_connect_rsp(void *sap_device, sap_status_t status, uint16_t maxmsgsize);
+int sap_disconnect_rsp(void *sap_device);
+int sap_transfer_apdu_rsp(void *sap_device, sap_result_t result, uint8_t *sap_apdu_resp, uint16_t length);
+int sap_transfer_atr_rsp(void *sap_device, sap_result_t result, uint8_t *sap_atr, uint16_t length);
+int sap_power_sim_off_rsp(void *sap_device, sap_result_t result);
+int sap_power_sim_on_rsp(void *sap_device, sap_result_t result);
+int sap_reset_sim_rsp(void *sap_device, sap_result_t result);
+int sap_transfer_card_reader_status_rsp(void *sap_device, sap_result_t result, icc_reader_status_t status);
+int sap_error_rsp(void *sap_device);
+int sap_transport_protocol_rsp(void *sap_device, sap_result_t result);
+
+/* Event indication. Implemented by server.c*/
+int sap_status_ind(void *sap_device, sap_status_change_t status_change);
+
diff --git a/sap/server.c b/sap/server.c
new file mode 100644
index 0000000..683df5e
--- /dev/null
+++ b/sap/server.c
@@ -0,0 +1,1516 @@
+/*
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 ST-Ericsson SA
+ * Copyright (C) 2010 Claudio Takahasi<[email protected]>
+ *
+ * Author: Marek Skowron <[email protected]> for ST-Ericsson.
+ * Author: Waldemar Rymarkiewicz <[email protected]> for ST-Ericsson.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <glib.h>
+#include <gdbus.h>
+#include <netinet/in.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include "adapter.h"
+#include "btio.h"
+#include "sdpd.h"
+#include "log.h"
+#include "error.h"
+#include "dbus-common.h"
+
+#include "sap.h"
+#include "server.h"
+
+#define SAP_SERVER_INTERFACE "org.bluez.SimAccess"
+#define SAP_UUID "0000112D-0000-1000-8000-00805F9B34FB"
+#define SAP_SERVER_CHANNEL 8
+#define SAP_BUF_SIZE 512
+
+#define PADDING4(x) (4 - (x & 0x03))
+#define PARAMETER_SIZE(x) (sizeof(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;
+ uint32_t record_id;
+ GIOChannel *listen_io;
+ GIOChannel *io; /* Connected client channel.*/
+ sap_state_t state;
+ uint8_t processing_req;
+ guint timer_id;
+};
+
+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 *server, guint interval);
+static void stop_guard_timer(struct sap_server *server);
+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)
+{
+ if(!msg)
+ return -EFAULT;
+
+ switch(msg->id) {
+ case SAP_CONNECT_REQ:
+ if (msg->nparam == 0x01 &&
+ msg->param->id == SAP_PARAM_ID_MAX_MSG_SIZE &&
+ ntohs(msg->param->len) == SAP_PARAM_ID_MAX_MSG_SIZE_LEN)
+ return 0;
+ break;
+ case SAP_TRANSFER_APDU_REQ:
+ if (msg->nparam == 0x01 &&
+ (msg->param->id == SAP_PARAM_ID_COMMAND_APDU ||
+ msg->param->id == SAP_PARAM_ID_COMMAND_APDU7816) &&
+ msg->param->len != 0x00)
+ return 0;
+ break;
+ case SAP_SET_TRANSPORT_PROTOCOL_REQ:
+ if (msg->nparam == 0x01 &&
+ msg->param->id == SAP_PARAM_ID_TRANSPORT_PROTOCOL &&
+ ntohs(msg->param->len) == SAP_PARAM_ID_TRANSPORT_PROTOCOL_LEN &&
+ (*msg->param->val == SAP_TRANSPORT_PROTOCOL_T0 ||
+ *msg->param->val == SAP_TRANSPORT_PROTOCOL_T1))
+ return 0;
+ break;
+ case SAP_DISCONNECT_REQ:
+ case SAP_TRANSFER_ATR_REQ:
+ case SAP_POWER_SIM_OFF_REQ:
+ case SAP_POWER_SIM_ON_REQ:
+ case SAP_RESET_SIM_REQ:
+ case SAP_TRANSFER_CARD_READER_STATUS_REQ:
+ if (msg->nparam == 0x00)
+ return 0;
+ break;
+ }
+
+ error("Invalid message");
+ return -EBADMSG;
+}
+
+
+static void start_guard_timer(struct sap_server *server, guint interval)
+{
+ if(!server)
+ return;
+
+ if (!server->timer_id)
+ server->timer_id = g_timeout_add_seconds(interval,
+ guard_timeout, server);
+ else
+ error("Timer is already active.");
+}
+
+static void stop_guard_timer(struct sap_server *server)
+{
+ if (server && server->timer_id) {
+ g_source_remove(server->timer_id);
+ server->timer_id = 0;
+ }
+}
+
+static gboolean guard_timeout(gpointer data)
+{
+ struct sap_server *server = data;
+
+ if (!server)
+ return FALSE;
+
+ DBG("guard_timeout: state: %x pr %x", server->state,
+ server->processing_req);
+
+ server->timer_id = 0;
+
+ switch(server->state) {
+ case SAP_STATE_DISCONNECTED:
+ /* Client opened RFCOMM channel but didn't send CONNECT_REQ,
+ * in fixed time or client disconnected SAP connection but
+ * didn't closed RFCOMM channel in fixed time.*/
+ if (server->io)
+ g_io_channel_shutdown(server->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(server, SAP_DISCONNECTION_TYPE_IMMEDIATE);
+ break;
+ default:
+ error("guard_timeout: Unexpected state.");
+ break;
+ }
+
+ return FALSE;
+}
+
+static sdp_record_t *create_sap_record(uint8_t channel)
+{
+ sdp_list_t *apseq, *aproto, *profiles, *proto[2], *root, *svclass_id;
+ uuid_t sap_uuid, gt_uuid, root_uuid, l2cap, rfcomm;
+ sdp_profile_desc_t profile;
+ sdp_record_t *record;
+ sdp_data_t *ch;
+
+ record = sdp_record_alloc();
+ if (!record)
+ return NULL;
+
+ root = sdp_list_append(NULL, &root_uuid);
+ sdp_set_browse_groups(record, root);
+ sdp_list_free(root, NULL);
+
+ sdp_uuid16_create(&sap_uuid, SAP_SVCLASS_ID);
+ svclass_id = sdp_list_append(NULL, &sap_uuid);
+ sdp_uuid16_create(>_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_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 *server, gchar *buf, gssize size)
+{
+ gsize written = 0;
+ GError *gerr = NULL;
+ GIOStatus gstatus;
+
+ if(!server || !buf)
+ return -1;
+
+ DBG("send_message: size=%x",(unsigned int)size);
+
+ gstatus = g_io_channel_write_chars(server->io, buf, size, &written, &gerr);
+
+ if (gstatus != G_IO_STATUS_NORMAL) {
+ if (gerr)
+ g_error_free(gerr);
+
+ error("send_message:write error (%d)", gstatus);
+ return -1;
+ }
+ if(written != (gsize)size) {
+ error("send_message:write error. written %d size %d", written, size);
+ }
+ DBG("send_message: written=%x",(unsigned int)written);
+ return 0;
+}
+
+static void connect_req(void *data, sap_parameter *param)
+{
+ struct sap_server *server = data;
+ uint16_t maxmsgsize, *val;
+
+ if(!server || !param)
+ goto error_rsp;
+
+ if (server->state != SAP_STATE_DISCONNECTED)
+ goto error_rsp;
+
+ stop_guard_timer(server);
+
+ val = (uint16_t *) ¶m->val;
+ maxmsgsize = ntohs(*val);
+
+ DBG("Connect MaxMsgSize: 0x%04X(%d)", maxmsgsize, maxmsgsize);
+
+ server->state = SAP_STATE_CONNECT_IN_PROGRESS;
+
+ if (maxmsgsize <= SAP_BUF_SIZE){
+ server->processing_req = SAP_CONNECT_REQ;
+ sap_connect_req(server, maxmsgsize);
+ }else{
+ sap_connect_rsp(server, SAP_STATUS_MAX_MSG_SIZE_NOT_SUPPORTED,
+ SAP_BUF_SIZE);
+ }
+
+ return;
+
+error_rsp:
+ error("Wrong state (state %x pr %x)", server->state,
+ server->processing_req);
+ sap_error_rsp(data);
+}
+
+static int disconnect_req(void *data, sap_disconnection_type_t disc_type)
+{
+ struct sap_server *server = data;
+
+ if(!server)
+ goto error_rsp;
+
+ DBG("disconnect_req: type 0x%x state %d", disc_type, server->state);
+
+ switch(disc_type) {
+ case SAP_DISCONNECTION_TYPE_GRACEFUL:
+
+ if (server->state == SAP_STATE_DISCONNECTED ||
+ server->state == SAP_STATE_CONNECT_IN_PROGRESS)
+ goto error_req;
+
+ if (server->state == SAP_STATE_CONNECTED) {
+ server->state = SAP_STATE_GRACEFUL_DISCONNECT;
+ server->processing_req = SAP_NO_REQ;
+ disconnect_ind(server, disc_type);
+
+ /* Start guard timer - timer will disconnect connection
+ * if client doesn't do it. */
+ start_guard_timer(server, SAP_TIMER_GRACEFUL_DISCONNECT);
+
+ return 0;
+ }
+ /* Disconnection is ongoing - do nothing. */
+ return 0;
+
+ case SAP_DISCONNECTION_TYPE_IMMEDIATE:
+
+ if (server->state == SAP_STATE_DISCONNECTED ||
+ server->state == SAP_STATE_CONNECT_IN_PROGRESS)
+ goto error_req;
+
+ if (server->state == SAP_STATE_CONNECTED ||
+ server->state == SAP_STATE_GRACEFUL_DISCONNECT) {
+ server->state = SAP_STATE_IMMEDIATE_DISCONNECT;
+ server->processing_req = SAP_NO_REQ;
+
+ stop_guard_timer(server);
+
+ disconnect_ind(server, disc_type);
+ sap_disconnect_req(server, 0);
+
+ return 0;
+ }
+ /* Disconnection is ongoing - do nothing. */
+ return 0;
+
+ case SAP_DISCONNECTION_TYPE_CLIENT:
+
+ if (server->state != SAP_STATE_CONNECTED &&
+ server->state != SAP_STATE_GRACEFUL_DISCONNECT)
+ goto error_rsp;
+
+ server->state = SAP_STATE_CLIENT_DISCONNECT;
+ server->processing_req = SAP_NO_REQ;
+
+ stop_guard_timer(server);
+
+ sap_disconnect_req(server, 0);
+
+ return 0;
+
+ default:
+ error("Unknown disconnection type (type %x).", disc_type);
+ return -EINVAL;
+ }
+
+error_rsp:
+ sap_error_rsp(server);
+error_req:
+ error("Wrong state (state %x pr %x)", server->state,
+ server->processing_req);
+ return -EPERM;
+}
+
+static void transfer_apdu_req(void * data, sap_parameter * param)
+{
+ struct sap_server *server = data;
+
+ if(!server || !param)
+ goto error_rsp;
+
+ param->len = ntohs(param->len);
+
+ DBG("transfer_apdu_req: data %p state %d", data, server->state);
+ DBG("transfer_apdu_req: apdu param id %d val %s len %d ",
+ param->id, param->val, param->len);
+
+ if (server->state != SAP_STATE_CONNECTED &&
+ server->state != SAP_STATE_GRACEFUL_DISCONNECT)
+ goto error_rsp;
+
+ if (server->processing_req != SAP_NO_REQ)
+ goto error_rsp;
+
+ server->processing_req = SAP_TRANSFER_APDU_REQ;
+ sap_transfer_apdu_req(server, param);
+
+ return;
+
+error_rsp:
+ error("Wrong state (state %x pr %x)", server->state,
+ server->processing_req);
+ sap_error_rsp(server);
+}
+
+
+static void transfer_atr_req(void * data)
+{
+ struct sap_server *server = data;
+
+ if(!server)
+ goto error_rsp;
+
+ DBG("transfer_atr_req: data %p state %d", data, server->state);
+
+ if (server->state != SAP_STATE_CONNECTED)
+ goto error_rsp;
+
+ if (server->processing_req != SAP_NO_REQ)
+ goto error_rsp;
+
+ server->processing_req = SAP_TRANSFER_ATR_REQ;
+ sap_transfer_atr_req(server);
+
+ return;
+
+error_rsp:
+ error("Wrong state (state %x pr %x)", server->state,
+ server->processing_req);
+ sap_error_rsp(server);
+}
+
+
+static void power_sim_off_req(void *data)
+{
+ struct sap_server *server = data;
+
+ if(!server)
+ goto error_rsp;
+
+ DBG("power_sim_off_req: data %p state %d", data, server->state);
+
+ if (server->state != SAP_STATE_CONNECTED)
+ goto error_rsp;
+
+ if (!is_power_sim_off_req_allowed(server->processing_req))
+ goto error_rsp;
+
+ server->processing_req = SAP_POWER_SIM_OFF_REQ;
+ sap_power_sim_off_req(server);
+
+ return;
+
+error_rsp:
+ error("Wrong state (state %x pr %x)", server->state,
+ server->processing_req);
+ sap_error_rsp(server);
+}
+
+static void power_sim_on_req(void *data)
+{
+ struct sap_server *server = data;
+
+ if(!server)
+ goto error_rsp;
+
+ DBG("power_sim_on_req: data %p state %d", data, server->state);
+
+ if (server->state != SAP_STATE_CONNECTED)
+ goto error_rsp;
+
+ if (server->processing_req != SAP_NO_REQ)
+ goto error_rsp;
+
+ server->processing_req = SAP_POWER_SIM_ON_REQ;
+ sap_power_sim_on_req(server);
+
+ return;
+
+error_rsp:
+ error("Wrong state (state %x pr %x)", server->state,
+ server->processing_req);
+ sap_error_rsp(server);
+}
+
+static void reset_sim_req(void *data)
+{
+ struct sap_server *server = data;
+
+ if(!server)
+ goto error_rsp;
+
+ DBG("reset_sim_req: data %p state %d", data, server->state);
+
+ if (server->state != SAP_STATE_CONNECTED)
+ goto error_rsp;
+
+ if (!is_reset_sim_req_allowed(server->processing_req))
+ goto error_rsp;
+
+ server->processing_req = SAP_RESET_SIM_REQ;
+ sap_reset_sim_req(server);
+
+ return;
+
+error_rsp:
+ error("Wrong state (state %x pr %x)", server->state,
+ server->processing_req);
+ sap_error_rsp(server);
+}
+
+static void transfer_card_reader_status_req(void * data)
+{
+ struct sap_server *server = data;
+
+ if(!server)
+ goto error_rsp;
+
+ DBG("transfer_card_reader_status_req: data %p state %d",
+ data, server->state);
+
+ if (server->state != SAP_STATE_CONNECTED)
+ goto error_rsp;
+
+ if (server->processing_req != SAP_NO_REQ)
+ goto error_rsp;
+
+ server->processing_req = SAP_TRANSFER_CARD_READER_STATUS_REQ;
+ sap_transfer_card_reader_status_req(server);
+
+ return;
+
+error_rsp:
+ error("Wrong state (state %x pr %x)", server->state,
+ server->processing_req);
+ sap_error_rsp(server);
+}
+
+static void set_transport_protocol_req(void *data, sap_parameter *param)
+{
+ struct sap_server *server = data;
+
+ if(!server || !param)
+ goto error_rsp;
+
+ DBG("set_transport_protocol_req: data %p state %d param %p",
+ data, server->state, param);
+
+ if (server->state != SAP_STATE_CONNECTED)
+ goto error_rsp;
+
+ if (server->processing_req != SAP_NO_REQ)
+ goto error_rsp;
+
+ server->processing_req = SAP_SET_TRANSPORT_PROTOCOL_REQ;
+ sap_set_transport_protocol_req(server, param);
+
+ return;
+
+error_rsp:
+ error("Wrong state (state %x pr %x)", server->state,
+ server->processing_req);
+ sap_error_rsp(server);
+}
+
+static int disconnect_ind(void *sap_device, sap_disconnection_type_t type)
+{
+ struct sap_server *server = sap_device;
+ gchar buf[SAP_BUF_SIZE];
+ sap_message *msg = (sap_message *) buf;
+ sap_parameter *param = (sap_parameter *) msg->param;
+ gsize size = sizeof(sap_message);
+
+ if(!server)
+ return -1;
+
+ DBG("disconnect_ind: data %p state %d disc_type %d",
+ server, server->state, type);
+
+ if (server->state != SAP_STATE_GRACEFUL_DISCONNECT &&
+ server->state != SAP_STATE_IMMEDIATE_DISCONNECT)
+ goto error_ind;
+
+ memset(buf, 0, sizeof(buf));
+ msg->id = SAP_DISCONNECT_IND;
+ msg->nparam = 0x01;
+
+ /* Add 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);
+
+ return send_message(sap_device, buf, size);
+
+error_ind:
+ error("Wrong state (state %x pr %x)", server->state,
+ server->processing_req);
+ return -EPERM;
+}
+
+int sap_connect_rsp(void *sap_device, sap_status_t status, uint16_t maxmsgsize)
+{
+ struct sap_server *server = sap_device;
+ gchar buf[SAP_BUF_SIZE];
+ sap_message *msg = (sap_message *) buf;
+ sap_parameter *param = (sap_parameter *) msg->param;
+ gsize size = sizeof(sap_message);
+
+ if(!server)
+ return -1;
+
+ DBG("sap_connect_rsp: state %x pr %x status %x", server->state,
+ server->processing_req, status);
+
+ if (server->state != SAP_STATE_CONNECT_IN_PROGRESS) {
+ return -EPERM;
+ }
+
+ memset(buf, 0, sizeof(buf));
+ msg->id = SAP_CONNECT_RESP;
+ msg->nparam = 0x01;
+
+ /* Add connection status */
+ param->id = SAP_PARAM_ID_CONN_STATUS;
+ param->len = htons(SAP_PARAM_ID_CONN_STATUS_LEN);
+ *param->val = (uint8_t)status;
+ size += PARAMETER_SIZE(SAP_PARAM_ID_CONN_STATUS_LEN);
+
+ /* Add MaxMsgSize */
+ if (maxmsgsize && (status == SAP_STATUS_MAX_MSG_SIZE_NOT_SUPPORTED ||
+ status == SAP_STATUS_MAX_MSG_SIZE_TOO_SMALL)) {
+ uint16_t *len;
+ msg->nparam++;
+ /* Skip the first param */
+ param = (sap_parameter *) &buf[size];
+ param->id = SAP_PARAM_ID_MAX_MSG_SIZE;
+ param->len = htons(SAP_PARAM_ID_MAX_MSG_SIZE_LEN);
+ len = (uint16_t *) ¶m->val;
+ *len = htons(maxmsgsize);
+ size += PARAMETER_SIZE(SAP_PARAM_ID_MAX_MSG_SIZE_LEN);
+ }
+
+ if (status == SAP_STATUS_OK) {
+ gboolean connected = TRUE;
+ emit_property_changed(connection, server->path, SAP_SERVER_INTERFACE,
+ "Connected", DBUS_TYPE_BOOLEAN, &connected);
+
+ server->state = SAP_STATE_CONNECTED;
+ } else {
+ server->state = SAP_STATE_DISCONNECTED;
+
+ /* Timer will shutdown channel if client doesn't send
+ * CONNECT_REQ or doesn't shutdown channel itself.*/
+ start_guard_timer(server, SAP_TIMER_NO_ACTIVITY);
+ }
+
+ server->processing_req = SAP_NO_REQ;
+ return send_message(sap_device, buf, size);
+}
+
+int sap_disconnect_rsp(void *sap_device)
+{
+ struct sap_server *server = sap_device;
+ sap_message msg = {0};
+
+ if(!server)
+ return -1;
+
+ DBG("sap_disconnect_rsp: state %x pr %x", server->state,
+ server->processing_req);
+
+ switch(server->state) {
+ case SAP_STATE_CLIENT_DISCONNECT:
+ msg.id = SAP_DISCONNECT_RESP;
+
+ server->state = SAP_STATE_DISCONNECTED;
+ server->processing_req = SAP_NO_REQ;
+
+ /* Timer will close channel if client doesn't do it.*/
+ start_guard_timer(server, SAP_TIMER_NO_ACTIVITY);
+
+ return send_message(sap_device, (gchar *) &msg, sizeof(msg));
+
+ case SAP_STATE_IMMEDIATE_DISCONNECT:
+ server->state = SAP_STATE_DISCONNECTED;
+ server->processing_req = SAP_NO_REQ;
+
+ if (server->io)
+ g_io_channel_shutdown(server->io, TRUE, NULL);
+ return 0;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+int sap_transfer_apdu_rsp(void *sap_device, sap_result_t result, uint8_t *apdu,
+ uint16_t length)
+{
+ struct sap_server *server = sap_device;
+ gchar buf[SAP_BUF_SIZE] = {0};
+ sap_message *msg = (sap_message *) buf;
+ sap_parameter *param = (sap_parameter *) msg->param;
+ gsize size = sizeof(sap_message);
+
+ if(!server)
+ return -1;
+
+ DBG("sap_transfer_apdu_rsp: state %x pr %x", server->state,
+ server->processing_req);
+
+ if (server->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;
+
+ /* Add result code */
+ msg->nparam = 0x01;
+ size += add_result_parameter(result, param);
+
+ /* Add 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);
+ }
+
+ server->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 *server = sap_device;
+ gchar buf[SAP_BUF_SIZE]= {0};
+ sap_message *msg = (sap_message *) buf;
+ sap_parameter *param = (sap_parameter *) msg->param;
+ gsize size = sizeof(sap_message);
+
+ if(!server)
+ return -1;
+
+ DBG("sap_transfer_atr_rsp: state %x pr %x", server->state,
+ server->processing_req);
+
+ if (server->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;
+
+ /* Add result code */
+ msg->nparam = 0x01;
+ size += add_result_parameter(result, param);
+
+ /* Add ATR response */
+ if (result == SAP_RESULT_OK) {
+ msg->nparam++;
+ /* Skip 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);
+ }
+
+ server->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 *server = sap_device;
+ gchar buf[SAP_BUF_SIZE] = {0};
+ sap_message *msg = (sap_message *) buf;
+ gsize size = sizeof(sap_message);
+
+ if(!server)
+ return -1;
+
+ DBG("sap_power_sim_off_rsp: state %x pr %x", server->state,
+ server->processing_req);
+
+ if (server->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;
+
+ /* Add result code.*/
+ msg->nparam = 0x01;
+ size += add_result_parameter(result, msg->param);
+
+ server->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 *server = sap_device;
+ gchar buf[SAP_BUF_SIZE] = {0};
+ sap_message *msg = (sap_message *) buf;
+ gsize size = sizeof(sap_message);
+
+ if(!server)
+ return -1;
+
+ DBG("sap_power_sim_on_rsp: state %x pr %x", server->state,
+ server->processing_req);
+
+ if (server->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;
+
+ /* Add result code */
+ msg->nparam = 0x01;
+ size += add_result_parameter(result, msg->param);
+
+ server->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 *server = sap_device;
+ gchar buf[SAP_BUF_SIZE] = {0};
+ sap_message *msg = (sap_message *) buf;
+ gsize size = sizeof(sap_message);
+
+ if(!server)
+ return -1;
+
+ DBG("sap_reset_sim_rsp: state %x pr %x", server->state,
+ server->processing_req);
+
+ if (server->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;
+
+ /* Add result code */
+ msg->nparam = 0x01;
+ size += add_result_parameter(result, msg->param);
+
+ server->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 *server = sap_device;
+ gchar buf[SAP_BUF_SIZE] = {0};
+ sap_message *msg = (sap_message *) buf;
+ sap_parameter *param = (sap_parameter *) msg->param;
+ gsize size = sizeof(sap_message);
+
+ if(!server)
+ return -1;
+
+ DBG("sap_transfer_card_reader_status_rsp: state %x pr %x", server->state,
+ server->processing_req);
+
+ if (server->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;
+
+ /* Add result code */
+ msg->nparam = 0x01;
+ size += add_result_parameter(result, param);
+
+ /* Add card reader status. */
+ if (result == SAP_RESULT_OK) {
+ msg->nparam++;
+ /* Skipp 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);
+ }
+
+ server->processing_req = SAP_NO_REQ;
+ return send_message(sap_device, buf, size);
+}
+
+int sap_transport_protocol_rsp(void *sap_device, sap_result_t result)
+{
+ struct sap_server *server = sap_device;
+ gchar buf[SAP_BUF_SIZE] = {0};
+ sap_message *msg = (sap_message *) buf;
+ gsize size = sizeof(sap_message);
+
+ if(!server)
+ return -1;
+
+ DBG("sap_transport_protocol_rsp: state %x pr %x", server->state,
+ server->processing_req);
+
+ if (server->processing_req != SAP_SET_TRANSPORT_PROTOCOL_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_SET_TRANSPORT_PROTOCOL_RESP;
+
+ /* Add result code */
+ msg->nparam = 0x01;
+ size += add_result_parameter(result, msg->param);
+
+ server->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, (gchar *) &msg, sizeof(msg));
+}
+
+int sap_status_ind(void *sap_device, sap_status_change_t status_change)
+{
+ struct sap_server *server = sap_device;
+ gchar buf[SAP_BUF_SIZE] = {0};
+ sap_message *msg = (sap_message *) buf;
+ sap_parameter *param = (sap_parameter *) msg->param;
+ gsize size = sizeof(sap_message);
+
+ if(!server)
+ return -1;
+
+ DBG("sap_status_ind: state %x pr %x", server->state,
+ server->processing_req);
+
+ if (server->state != SAP_STATE_CONNECTED &&
+ server->state != SAP_STATE_GRACEFUL_DISCONNECT)
+ /*Don't propagate status indication if client is not connected */
+ return 0;
+
+ msg->id = SAP_STATUS_IND;
+ msg->nparam = 0x01;
+
+ /* Add status change. */
+ param->id = SAP_PARAM_ID_STATUS_CHANGE;
+ param->len = htons(SAP_PARAM_ID_STATUS_CHANGE_LEN);
+ *param->val = (uint8_t) status_change;
+ size += PARAMETER_SIZE(SAP_PARAM_ID_STATUS_CHANGE_LEN);
+
+ return send_message(sap_device, buf, size);
+}
+
+static int handle_cmd(void *data, gchar *buf, gsize size)
+{
+ sap_message *msg = (sap_message *) buf;
+
+ if (size < sizeof(sap_message))
+ goto error_rsp;
+
+ 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:
+ DBG("SAP Connect.");
+ connect_req(data, msg->param);
+ return 0;
+ case SAP_DISCONNECT_REQ:
+ DBG("SAP Disconnect.");
+ disconnect_req(data, SAP_DISCONNECTION_TYPE_CLIENT);
+ return 0;
+ case SAP_TRANSFER_APDU_REQ:
+ DBG("SAP Transfer APDU.");
+ transfer_apdu_req(data, msg->param);
+ return 0;
+ case SAP_TRANSFER_ATR_REQ:
+ DBG("SAP Transfer ATR.");
+ transfer_atr_req(data);
+ return 0;
+ case SAP_POWER_SIM_OFF_REQ:
+ DBG("SAP SIM off.");
+ power_sim_off_req(data);
+ return 0;
+ case SAP_POWER_SIM_ON_REQ:
+ DBG("SAP SIM on.");
+ power_sim_on_req(data);
+ return 0;
+ case SAP_RESET_SIM_REQ:
+ DBG("SAP SIM reset.");
+ reset_sim_req(data);
+ return 0;
+ case SAP_TRANSFER_CARD_READER_STATUS_REQ:
+ DBG("SAP reader status.");
+ transfer_card_reader_status_req(data);
+ return 0;
+ case SAP_SET_TRANSPORT_PROTOCOL_REQ:
+ DBG("SAP set proto request.");
+ set_transport_protocol_req(data, msg->param);
+ return 0;
+ default:
+ DBG("SAP unknown message.");
+ break;
+ }
+
+error_rsp:
+ DBG("SAP ERROR RSP");
+ sap_error_rsp(data);
+ return -EBADMSG;
+}
+
+static gboolean sap_io_cb(GIOChannel *chan, GIOCondition cond, void *data)
+{
+ gchar buf[SAP_BUF_SIZE];
+ gsize bytes_read = 0;
+ GError *gerr = NULL;
+ GIOStatus gstatus;
+
+ if (cond & G_IO_NVAL){
+ DBG("ERR (G_IO_NVAL) on rfcomm socket.");
+ return FALSE;
+ }
+
+ if (cond & G_IO_ERR) {
+ DBG("ERR (G_IO_ERR) on rfcomm socket.");
+ return FALSE;
+ }
+
+ if (cond & G_IO_HUP ) {
+ DBG("HUP on rfcomm socket.");
+ return FALSE;
+ }
+
+ gstatus = g_io_channel_read_chars(chan, buf, sizeof(buf) - 1,
+ &bytes_read, &gerr);
+
+ if (gstatus != G_IO_STATUS_NORMAL) {
+ if(gerr)
+ g_error_free(gerr);
+ return TRUE;
+ }
+
+ if (handle_cmd(data, buf, bytes_read) < 0) {
+ error("Invalid SAP message.");
+ }
+
+ return TRUE;
+}
+
+static void sap_io_destroy(void *data)
+{
+ struct sap_server *server = data;
+
+ if (server && server->io) {
+ gboolean connected = FALSE;
+
+ stop_guard_timer(server);
+
+ g_io_channel_shutdown(server->io, TRUE, NULL);
+ g_io_channel_unref(server->io);
+
+ server->io = NULL;
+
+ if (server->state != SAP_STATE_CONNECT_IN_PROGRESS)
+ emit_property_changed(connection, server->path,
+ SAP_SERVER_INTERFACE,"Connected",
+ DBUS_TYPE_BOOLEAN, &connected);
+
+ if (server->state == SAP_STATE_CONNECT_IN_PROGRESS ||
+ server->state == SAP_STATE_CONNECTED ||
+ server->state == SAP_STATE_GRACEFUL_DISCONNECT){
+ sap_disconnect_req(NULL, 1);
+ }
+
+ server->state = SAP_STATE_DISCONNECTED;
+ }
+}
+
+static void sap_connect_cb(GIOChannel *chan, GError *gerr, gpointer data)
+{
+ struct sap_server *server = data;
+
+ if(!server)
+ return;
+
+ /* Timer will shutdown the channel in case of lack of client activity */
+ start_guard_timer(server, 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, server, sap_io_destroy);
+}
+
+static void connect_auth_cb(DBusError *derr, void *data)
+{
+ struct sap_server *server = data;
+ GError *gerr = NULL;
+
+ if(!server || !server->io)
+ return;
+
+ if (derr && dbus_error_is_set(derr)) {
+ error("Access denied: %s", derr->message);
+ goto drop;
+ }
+
+ if (!bt_io_accept(server->io, sap_connect_cb, server, NULL, &gerr)) {
+ error("bt_io_accept: %s", gerr->message);
+ g_error_free(gerr);
+ goto drop;
+ }
+ return;
+
+drop:
+ g_io_channel_shutdown(server->io, TRUE, NULL);
+ g_io_channel_unref(server->io);
+ server->io = NULL;
+}
+
+static void connect_confirm_cb(GIOChannel *chan, gpointer data)
+{
+ struct sap_server *server = data;
+ GError *gerr = NULL;
+ bdaddr_t src, dst;
+ int err;
+
+ if(!chan || !server)
+ return;
+
+ if (server->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;
+ }
+
+ server->io = g_io_channel_ref(chan);
+
+ err = btd_request_authorization(&src, &dst, SAP_UUID, connect_auth_cb, server);
+
+ if (err < 0) {
+ DBG("Authorization denied: %s", strerror(err));
+ goto drop;
+ }
+
+ DBG("SAP incoming connection (sock %d) authorization.", g_io_channel_unix_get_fd(chan));
+
+ return;
+
+drop:
+ g_io_channel_shutdown(chan, TRUE, NULL);
+ if (server->io && server->io == chan) {
+ g_io_channel_unref(server->io);
+ server->io = NULL;
+ }
+}
+
+
+
+static inline DBusMessage *message_failed(DBusMessage *msg,
+ const char *description)
+{
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
+ "%s", description);
+}
+
+static DBusMessage *enable(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct sap_server *server = data;
+ sdp_record_t *record = NULL;
+ GIOChannel *io = NULL;
+ GError *gerr = NULL;
+
+ if (!server)
+ return message_failed(msg, "Server internal error.");
+
+ if (server->enable)
+ return message_failed(msg, "Server already enabled.");
+
+ record = create_sap_record(SAP_SERVER_CHANNEL);
+ if (!record)
+ return message_failed(msg, "Can't create SDP record for SAP.");
+
+ if (add_record_to_server(&server->src, record) < 0) {
+ sdp_record_free(record);
+ return message_failed(msg, "SDP record registration failed.");
+ }
+
+ io = bt_io_listen(BT_IO_RFCOMM, NULL, connect_confirm_cb, server, NULL, &gerr,
+ BT_IO_OPT_SOURCE_BDADDR, &server->src,
+ BT_IO_OPT_CHANNEL, SAP_SERVER_CHANNEL,
+ BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_HIGH,
+ BT_IO_OPT_MASTER, TRUE,
+ BT_IO_OPT_INVALID);
+ if (!io) {
+ g_error_free(gerr);
+ sdp_record_free(record);
+ return message_failed(msg, "Listen rfcomm channel failed.");
+ }
+
+ DBG("Listen socket %x", g_io_channel_unix_get_fd(io));
+
+ server->enable = TRUE;
+ server->record_id = record->handle;
+ server->listen_io = io;
+
+ emit_property_changed(connection, server->path, SAP_SERVER_INTERFACE,
+ "Enabled", DBUS_TYPE_BOOLEAN, &server->enable);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *disable(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct sap_server *server = data;
+ DBusMessage *reply = NULL;
+
+ if(!server)
+ return message_failed(msg, "Server internal error.");
+
+ if (!server->enable)
+ return message_failed(msg, "Server already disabled.");
+
+ if (server->state != SAP_STATE_DISCONNECTED)
+ return message_failed(msg, "Ongoing connection exists.");
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ remove_record_from_server(server->record_id);
+
+ if (server->listen_io) {
+ g_io_channel_shutdown(server->listen_io, TRUE, NULL);
+ g_io_channel_unref(server->listen_io);
+ server->listen_io = NULL;
+ }
+
+ server->enable = FALSE;
+
+ emit_property_changed(connection, server->path, SAP_SERVER_INTERFACE,
+ "Enabled", DBUS_TYPE_BOOLEAN, &server->enable);
+
+ return reply;
+}
+
+static DBusMessage *get_properties(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct sap_server *server = data;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter dict;
+ dbus_bool_t connected;
+
+ if(!server)
+ return message_failed(msg, "Server internal error.");
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+ dict_append_entry(&dict, "Enabled", DBUS_TYPE_BOOLEAN, &server->enable);
+
+ connected = (server->state == SAP_STATE_CONNECTED ||
+ server->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 *disconnect(DBusConnection *conn, DBusMessage *msg, void *data)
+{
+ struct sap_server *server = data;
+ dbus_bool_t disc_type;
+ sap_disconnection_type_t sap_disc_type;
+
+ if (!server)
+ return message_failed(msg, "Server internal error.");
+
+ if (!server->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(server, 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[] = {
+ { "Enable","","", enable },
+ { "Disable","","", disable },
+ { "GetProperties","","a{sv}",get_properties },
+ { "Disconnect","b","", disconnect },
+ { }
+};
+
+static GDBusSignalTable server_signals[] = {
+ { "PropertyChanged", "sv"},
+ { }
+};
+
+static void server_free(struct sap_server *server)
+{
+ DBG("[%s::%s]", __FILE__, __FUNCTION__);
+
+ if (!server)
+ return;
+
+ g_free(server->path);
+ g_free(server);
+}
+
+static void destroy_sap_interface(void *data)
+{
+ struct sap_server *server = data;
+
+ DBG("Unregistered interface %s on path %s",
+ SAP_SERVER_INTERFACE, server->path);
+
+ server_free(server);
+}
+
+int sap_server_register(const char *path, bdaddr_t *src)
+{
+ struct sap_server *server;
+
+ if(sap_init() < 0) {
+ error("Sap driver initialization failed.");
+ return -1;
+ }
+
+ server = g_new0(struct sap_server, 1);
+
+ if (!server) {
+ sap_exit();
+ return -ENOMEM;
+ }
+
+ server->enable = FALSE;
+
+ if (!g_dbus_register_interface(connection, path, SAP_SERVER_INTERFACE,
+ server_methods, server_signals, NULL,
+ server, destroy_sap_interface)) {
+ error("D-Bus failed to register %s interface",
+ SAP_SERVER_INTERFACE);
+ server_free(server);
+ sap_exit();
+ return -1;
+ }
+
+ server->path = g_strdup(path);
+ bacpy(&server->src, src);
+
+ return 0;
+}
+
+int sap_server_unregister(const char *path)
+{
+ g_dbus_unregister_interface(connection, path, SAP_SERVER_INTERFACE);
+ sap_exit();
+ return 0;
+}
+
+int sap_server_init(DBusConnection *conn)
+{
+ connection = dbus_connection_ref(conn);
+ return 0;
+}
+
+void sap_server_exit(void)
+{
+ dbus_connection_unref(connection);
+ connection = NULL;
+}
diff --git a/sap/server.h b/sap/server.h
new file mode 100644
index 0000000..6e7f6fc
--- /dev/null
+++ b/sap/server.h
@@ -0,0 +1,23 @@
+/*
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 Claudio Takahasi<[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+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