mirror of
https://git.kernel.org/pub/scm/bluetooth/bluez.git
synced 2024-12-02 00:24:25 +08:00
4e02012afe
The sap_disconnect_ind() let's the sim driver to indicate immediate disconnection. Add support of immediate disconnection in sap-dummy driver as well as a card status change in order to pass all PTS tests.
348 lines
9.5 KiB
C
348 lines
9.5 KiB
C
/*
|
|
* BlueZ - Bluetooth protocol stack for Linux
|
|
*
|
|
* Copyright (C) 2010 ST-Ericsson SA
|
|
* Copyright (C) 2011 Tieto Poland
|
|
*
|
|
* Author: Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com>
|
|
* for ST-Ericsson
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <glib.h>
|
|
#include <gdbus.h>
|
|
|
|
#include "log.h"
|
|
#include "sap.h"
|
|
|
|
#define SAP_DUMMY_IFACE "org.bluez.SimAccessTest"
|
|
#define SAP_DUMMY_PATH "/org/bluez/test"
|
|
|
|
enum {
|
|
SIM_DISCONNECTED= 0x00,
|
|
SIM_CONNECTED = 0x01,
|
|
SIM_POWERED_OFF = 0x02,
|
|
SIM_MISSING = 0x03
|
|
};
|
|
|
|
static DBusConnection *connection = NULL;
|
|
|
|
static int sim_card_conn_status = SIM_DISCONNECTED;
|
|
static void *sap_data = NULL; /* SAP server private data.*/
|
|
static gboolean ongoing_call_status = FALSE;
|
|
static int max_msg_size_supported = 512;
|
|
|
|
void sap_connect_req(void *sap_device, uint16_t maxmsgsize)
|
|
{
|
|
DBG("status: %d", sim_card_conn_status);
|
|
|
|
if (sim_card_conn_status != SIM_DISCONNECTED) {
|
|
sap_connect_rsp(sap_device, SAP_STATUS_CONNECTION_FAILED,
|
|
maxmsgsize);
|
|
return;
|
|
} else if (max_msg_size_supported > maxmsgsize) {
|
|
sap_connect_rsp(sap_device, SAP_STATUS_MAX_MSG_SIZE_TOO_SMALL,
|
|
max_msg_size_supported);
|
|
return;
|
|
} else if (max_msg_size_supported < maxmsgsize) {
|
|
sap_connect_rsp(sap_device,
|
|
SAP_STATUS_MAX_MSG_SIZE_NOT_SUPPORTED,
|
|
max_msg_size_supported);
|
|
return;
|
|
} else if (ongoing_call_status) {
|
|
sap_connect_rsp(sap_device, SAP_STATUS_OK_ONGOING_CALL,
|
|
maxmsgsize);
|
|
return;
|
|
} else {
|
|
sim_card_conn_status = SIM_CONNECTED;
|
|
sap_data = sap_device;
|
|
|
|
sap_connect_rsp(sap_device, SAP_STATUS_OK, maxmsgsize);
|
|
sap_status_ind(sap_device, SAP_STATUS_CHANGE_CARD_RESET);
|
|
}
|
|
}
|
|
|
|
void sap_disconnect_req(void *sap_device, uint8_t linkloss)
|
|
{
|
|
sim_card_conn_status = SIM_DISCONNECTED;
|
|
sap_data = NULL;
|
|
ongoing_call_status = FALSE;
|
|
|
|
DBG("status: %d", sim_card_conn_status);
|
|
|
|
if (linkloss)
|
|
return;
|
|
|
|
sap_disconnect_rsp(sap_device);
|
|
}
|
|
|
|
void sap_transfer_apdu_req(void *sap_device, struct sap_parameter *param)
|
|
{
|
|
char apdu[] = "APDU response!";
|
|
|
|
DBG("status: %d", sim_card_conn_status);
|
|
|
|
if (sim_card_conn_status == SIM_MISSING)
|
|
sap_transfer_apdu_rsp(sap_device,
|
|
SAP_RESULT_ERROR_CARD_REMOVED, NULL, 0);
|
|
else if (sim_card_conn_status == SIM_POWERED_OFF)
|
|
sap_transfer_apdu_rsp(sap_device, SAP_RESULT_ERROR_POWERED_OFF,
|
|
NULL, 0);
|
|
else if (sim_card_conn_status != SIM_CONNECTED)
|
|
sap_transfer_apdu_rsp(sap_device,
|
|
SAP_RESULT_ERROR_NOT_ACCESSIBLE, NULL, 0);
|
|
else
|
|
sap_transfer_apdu_rsp(sap_device, SAP_RESULT_OK,
|
|
(uint8_t*)&apdu, sizeof(apdu));
|
|
}
|
|
|
|
void sap_transfer_atr_req(void *sap_device)
|
|
{
|
|
char atr[] = "ATR response!";
|
|
|
|
DBG("status: %d", sim_card_conn_status);
|
|
|
|
if (sim_card_conn_status == SIM_MISSING)
|
|
sap_transfer_atr_rsp(sap_device, SAP_RESULT_ERROR_CARD_REMOVED,
|
|
NULL, 0);
|
|
else if (sim_card_conn_status == SIM_POWERED_OFF)
|
|
sap_transfer_atr_rsp(sap_device, SAP_RESULT_ERROR_POWERED_OFF,
|
|
NULL, 0);
|
|
else if (sim_card_conn_status != SIM_CONNECTED)
|
|
sap_transfer_atr_rsp(sap_device, SAP_RESULT_ERROR_NO_REASON,
|
|
NULL, 0);
|
|
else
|
|
sap_transfer_atr_rsp(sap_device, SAP_RESULT_OK,
|
|
(uint8_t*)&atr, sizeof(atr));
|
|
}
|
|
|
|
void sap_power_sim_off_req(void *sap_device)
|
|
{
|
|
DBG("status: %d", sim_card_conn_status);
|
|
|
|
if (sim_card_conn_status == SIM_MISSING) {
|
|
sap_power_sim_off_rsp(sap_device,
|
|
SAP_RESULT_ERROR_CARD_REMOVED);
|
|
} else if (sim_card_conn_status == SIM_POWERED_OFF) {
|
|
sap_power_sim_off_rsp(sap_device,
|
|
SAP_RESULT_ERROR_POWERED_OFF);
|
|
} else if (sim_card_conn_status != SIM_CONNECTED) {
|
|
sap_power_sim_off_rsp(sap_device,
|
|
SAP_RESULT_ERROR_NO_REASON);
|
|
} else {
|
|
sap_power_sim_off_rsp(sap_device, SAP_RESULT_OK);
|
|
sim_card_conn_status = SIM_POWERED_OFF;
|
|
}
|
|
}
|
|
|
|
void sap_power_sim_on_req(void *sap_device)
|
|
{
|
|
DBG("status: %d", sim_card_conn_status);
|
|
|
|
if (sim_card_conn_status == SIM_MISSING) {
|
|
sap_power_sim_on_rsp(sap_device,
|
|
SAP_RESULT_ERROR_CARD_REMOVED);
|
|
} else if (sim_card_conn_status == SIM_POWERED_OFF) {
|
|
sap_power_sim_on_rsp(sap_device, SAP_RESULT_OK);
|
|
sim_card_conn_status = SIM_CONNECTED;
|
|
return;
|
|
} else if (sim_card_conn_status != SIM_CONNECTED) {
|
|
sap_power_sim_on_rsp(sap_device,
|
|
SAP_RESULT_ERROR_NOT_ACCESSIBLE);
|
|
} else {
|
|
sap_power_sim_on_rsp(sap_device,
|
|
SAP_RESULT_ERROR_NO_REASON);
|
|
}
|
|
}
|
|
|
|
void sap_reset_sim_req(void *sap_device)
|
|
{
|
|
DBG("status: %d", sim_card_conn_status);
|
|
|
|
if (sim_card_conn_status == SIM_MISSING) {
|
|
sap_reset_sim_rsp(sap_device, SAP_RESULT_ERROR_CARD_REMOVED);
|
|
} else if (sim_card_conn_status == SIM_POWERED_OFF) {
|
|
sap_reset_sim_rsp(sap_device, SAP_RESULT_ERROR_POWERED_OFF);
|
|
} else if (sim_card_conn_status != SIM_CONNECTED) {
|
|
sap_reset_sim_rsp(sap_device, SAP_RESULT_ERROR_NO_REASON);
|
|
} else {
|
|
sap_reset_sim_rsp(sap_device, SAP_RESULT_OK);
|
|
}
|
|
}
|
|
|
|
void sap_transfer_card_reader_status_req(void *sap_device)
|
|
{
|
|
DBG("status: %d", sim_card_conn_status);
|
|
|
|
if (sim_card_conn_status != SIM_CONNECTED) {
|
|
sap_transfer_card_reader_status_rsp(sap_device,
|
|
SAP_RESULT_ERROR_NO_REASON, 0xF1);
|
|
return;
|
|
}
|
|
|
|
sap_transfer_card_reader_status_rsp(sap_device, SAP_RESULT_OK, 0xF1);
|
|
}
|
|
|
|
void sap_set_transport_protocol_req(void *sap_device,
|
|
struct sap_parameter *param)
|
|
{
|
|
sap_transport_protocol_rsp(sap_device, SAP_RESULT_NOT_SUPPORTED);
|
|
}
|
|
|
|
static inline DBusMessage *invalid_args(DBusMessage *msg)
|
|
{
|
|
return g_dbus_create_error(msg, "org.bluez.Error.InvalidArguments",
|
|
"Invalid arguments in method call");
|
|
}
|
|
|
|
static DBusMessage *ongoing_call(DBusConnection *conn, DBusMessage *msg,
|
|
void *data)
|
|
{
|
|
dbus_bool_t ongoing;
|
|
|
|
if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_BOOLEAN, &ongoing,
|
|
DBUS_TYPE_INVALID))
|
|
return invalid_args(msg);
|
|
|
|
if (ongoing_call_status && !ongoing) {
|
|
/* An ongoing call has finished. Continue connection.*/
|
|
sap_connect_rsp(sap_data, SAP_STATUS_OK,
|
|
max_msg_size_supported);
|
|
sap_status_ind(sap_data, SAP_STATUS_CHANGE_CARD_RESET);
|
|
ongoing_call_status = ongoing;
|
|
} else if (!ongoing_call_status && ongoing) {
|
|
/* An ongoing call has started.*/
|
|
ongoing_call_status = ongoing;
|
|
}
|
|
|
|
DBG("OngoingCall status set to %d", ongoing_call_status);
|
|
|
|
return dbus_message_new_method_return(msg);
|
|
}
|
|
|
|
static DBusMessage *max_msg_size(DBusConnection *conn, DBusMessage *msg,
|
|
void *data)
|
|
{
|
|
dbus_uint32_t size;
|
|
|
|
if (sim_card_conn_status == SIM_CONNECTED)
|
|
return g_dbus_create_error(msg, "org.bluez.Error.Failed",
|
|
"Can't change msg size when connected.");
|
|
|
|
if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &size,
|
|
DBUS_TYPE_INVALID))
|
|
return invalid_args(msg);
|
|
|
|
max_msg_size_supported = size;
|
|
|
|
DBG("MaxMessageSize set to %d", max_msg_size_supported);
|
|
|
|
return dbus_message_new_method_return(msg);
|
|
}
|
|
|
|
static DBusMessage *disconnect_immediate(DBusConnection *conn, DBusMessage *msg,
|
|
void *data)
|
|
{
|
|
if (sim_card_conn_status == SIM_DISCONNECTED)
|
|
return g_dbus_create_error(msg, "org.bluez.Error.Failed",
|
|
"Already disconnected.");
|
|
|
|
sim_card_conn_status = SIM_DISCONNECTED;
|
|
sap_disconnect_ind(sap_data, SAP_DISCONNECTION_TYPE_IMMEDIATE);
|
|
|
|
return dbus_message_new_method_return(msg);
|
|
}
|
|
|
|
static DBusMessage *card_status(DBusConnection *conn, DBusMessage *msg,
|
|
void *data)
|
|
{
|
|
dbus_uint32_t status;
|
|
|
|
DBG("status %d", sim_card_conn_status);
|
|
|
|
if (sim_card_conn_status != SIM_CONNECTED)
|
|
return g_dbus_create_error(msg, "org.bluez.Error.Failed",
|
|
"Can't change msg size when not connected.");
|
|
|
|
if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &status,
|
|
DBUS_TYPE_INVALID))
|
|
return invalid_args(msg);
|
|
|
|
switch (status) {
|
|
case 0: /* card removed */
|
|
sim_card_conn_status = SIM_MISSING;
|
|
sap_status_ind(sap_data, SAP_STATUS_CHANGE_CARD_REMOVED);
|
|
break;
|
|
|
|
case 1: /* card inserted */
|
|
if (sim_card_conn_status == SIM_MISSING) {
|
|
sim_card_conn_status = SIM_CONNECTED;
|
|
sap_status_ind(sap_data,
|
|
SAP_STATUS_CHANGE_CARD_INSERTED);
|
|
}
|
|
break;
|
|
|
|
case 2: /* card not longer available*/
|
|
sim_card_conn_status = SIM_POWERED_OFF;
|
|
sap_status_ind(sap_data, SAP_STATUS_CHANGE_CARD_NOT_ACCESSIBLE);
|
|
break;
|
|
|
|
default:
|
|
return g_dbus_create_error(msg, "org.bluez.Error.Failed",
|
|
"Unknown card status. Use 0, 1 or 2.");
|
|
}
|
|
|
|
DBG("Card status changed to %d", status);
|
|
|
|
return dbus_message_new_method_return(msg);
|
|
}
|
|
|
|
static GDBusMethodTable dummy_methods[] = {
|
|
{ "OngoingCall", "b", "", ongoing_call},
|
|
{ "MaxMessageSize", "u", "", max_msg_size},
|
|
{ "DisconnectImmediate", "", "", disconnect_immediate},
|
|
{ "CardStatus", "u", "", card_status},
|
|
{ }
|
|
};
|
|
|
|
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, NULL, NULL,
|
|
NULL, NULL) == FALSE) {
|
|
error("sap-dummy interface %s init failed on path %s",
|
|
SAP_DUMMY_IFACE, SAP_DUMMY_PATH);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void sap_exit(void)
|
|
{
|
|
dbus_connection_unref(connection);
|
|
connection = NULL;
|
|
}
|