Home | History | Annotate | Download | only in sap
      1 /*
      2  *  BlueZ - Bluetooth protocol stack for Linux
      3  *
      4  *  Copyright (C) 2010 ST-Ericsson SA
      5  *  Copyright (C) 2011 Tieto Poland
      6  *
      7  *  Author: Waldemar Rymarkiewicz <waldemar.rymarkiewicz (at) tieto.com>
      8  *          for ST-Ericsson
      9  *
     10  *  This program is free software; you can redistribute it and/or modify
     11  *  it under the terms of the GNU General Public License as published by
     12  *  the Free Software Foundation; either version 2 of the License, or
     13  *  (at your option) any later version.
     14  *
     15  *  This program is distributed in the hope that it will be useful,
     16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     18  *  GNU General Public License for more details.
     19  *
     20  *  You should have received a copy of the GNU General Public License
     21  *  along with this program; if not, write to the Free Software
     22  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     23  */
     24 
     25 #ifdef HAVE_CONFIG_H
     26 #include <config.h>
     27 #endif
     28 
     29 #include <unistd.h>
     30 #include <stdlib.h>
     31 #include <stdint.h>
     32 #include <glib.h>
     33 #include <gdbus.h>
     34 
     35 #include "log.h"
     36 #include "sap.h"
     37 
     38 #define SAP_DUMMY_IFACE "org.bluez.SimAccessTest"
     39 #define SAP_DUMMY_PATH "/org/bluez/test"
     40 
     41 enum {
     42 	SIM_DISCONNECTED= 0x00,
     43 	SIM_CONNECTED	= 0x01,
     44 	SIM_POWERED_OFF	= 0x02,
     45 	SIM_MISSING	= 0x03
     46 };
     47 
     48 static DBusConnection *connection = NULL;
     49 
     50 static int sim_card_conn_status = SIM_DISCONNECTED;
     51 static void *sap_data = NULL;  /* SAP server private data.*/
     52 static gboolean ongoing_call_status = FALSE;
     53 static int max_msg_size_supported = 512;
     54 
     55 void sap_connect_req(void *sap_device, uint16_t maxmsgsize)
     56 {
     57 	DBG("status: %d", sim_card_conn_status);
     58 
     59 	if (sim_card_conn_status != SIM_DISCONNECTED) {
     60 		sap_connect_rsp(sap_device, SAP_STATUS_CONNECTION_FAILED,
     61 								maxmsgsize);
     62 		return;
     63 	} else if (max_msg_size_supported > maxmsgsize) {
     64 		sap_connect_rsp(sap_device, SAP_STATUS_MAX_MSG_SIZE_TOO_SMALL,
     65 						max_msg_size_supported);
     66 		return;
     67 	} else if (max_msg_size_supported < maxmsgsize) {
     68 		sap_connect_rsp(sap_device,
     69 				SAP_STATUS_MAX_MSG_SIZE_NOT_SUPPORTED,
     70 				max_msg_size_supported);
     71 		return;
     72 	} else if (ongoing_call_status) {
     73 		sap_connect_rsp(sap_device, SAP_STATUS_OK_ONGOING_CALL,
     74 								maxmsgsize);
     75 		return;
     76 	} else {
     77 		sim_card_conn_status = SIM_CONNECTED;
     78 		sap_data = sap_device;
     79 
     80 		sap_connect_rsp(sap_device, SAP_STATUS_OK, maxmsgsize);
     81 		sap_status_ind(sap_device, SAP_STATUS_CHANGE_CARD_RESET);
     82 	}
     83 }
     84 
     85 void sap_disconnect_req(void *sap_device, uint8_t linkloss)
     86 {
     87 	sim_card_conn_status = SIM_DISCONNECTED;
     88 	sap_data = NULL;
     89 	ongoing_call_status = FALSE;
     90 
     91 	DBG("status: %d", sim_card_conn_status);
     92 
     93 	if (linkloss)
     94 		return;
     95 
     96 	sap_disconnect_rsp(sap_device);
     97 }
     98 
     99 void sap_transfer_apdu_req(void *sap_device, struct sap_parameter *param)
    100 {
    101 	char apdu[] = "APDU response!";
    102 
    103 	DBG("status: %d", sim_card_conn_status);
    104 
    105 	if (sim_card_conn_status == SIM_MISSING)
    106 		sap_transfer_apdu_rsp(sap_device,
    107 				SAP_RESULT_ERROR_CARD_REMOVED, NULL, 0);
    108 	else if (sim_card_conn_status == SIM_POWERED_OFF)
    109 		sap_transfer_apdu_rsp(sap_device, SAP_RESULT_ERROR_POWERED_OFF,
    110 								NULL, 0);
    111 	else if (sim_card_conn_status != SIM_CONNECTED)
    112 		sap_transfer_apdu_rsp(sap_device,
    113 			SAP_RESULT_ERROR_NOT_ACCESSIBLE, NULL, 0);
    114 	else
    115 		sap_transfer_apdu_rsp(sap_device, SAP_RESULT_OK,
    116 						(uint8_t*)&apdu, sizeof(apdu));
    117 }
    118 
    119 void sap_transfer_atr_req(void *sap_device)
    120 {
    121 	char atr[] = "ATR response!";
    122 
    123 	DBG("status: %d", sim_card_conn_status);
    124 
    125 	if (sim_card_conn_status == SIM_MISSING)
    126 		sap_transfer_atr_rsp(sap_device, SAP_RESULT_ERROR_CARD_REMOVED,
    127 								NULL, 0);
    128 	else if (sim_card_conn_status == SIM_POWERED_OFF)
    129 		sap_transfer_atr_rsp(sap_device, SAP_RESULT_ERROR_POWERED_OFF,
    130 								NULL, 0);
    131 	else if (sim_card_conn_status != SIM_CONNECTED)
    132 		sap_transfer_atr_rsp(sap_device, SAP_RESULT_ERROR_NO_REASON,
    133 								NULL, 0);
    134 	else
    135 		sap_transfer_atr_rsp(sap_device, SAP_RESULT_OK,
    136 						(uint8_t*)&atr, sizeof(atr));
    137 }
    138 
    139 void sap_power_sim_off_req(void *sap_device)
    140 {
    141 	DBG("status: %d", sim_card_conn_status);
    142 
    143 	if (sim_card_conn_status == SIM_MISSING) {
    144 		sap_power_sim_off_rsp(sap_device,
    145 					SAP_RESULT_ERROR_CARD_REMOVED);
    146 	} else if (sim_card_conn_status == SIM_POWERED_OFF) {
    147 		sap_power_sim_off_rsp(sap_device,
    148 					SAP_RESULT_ERROR_POWERED_OFF);
    149 	} else if (sim_card_conn_status != SIM_CONNECTED) {
    150 		sap_power_sim_off_rsp(sap_device,
    151 					SAP_RESULT_ERROR_NO_REASON);
    152 	} else {
    153 		sap_power_sim_off_rsp(sap_device, SAP_RESULT_OK);
    154 		sim_card_conn_status = SIM_POWERED_OFF;
    155 	}
    156 }
    157 
    158 void sap_power_sim_on_req(void *sap_device)
    159 {
    160 	DBG("status: %d", sim_card_conn_status);
    161 
    162 	if (sim_card_conn_status == SIM_MISSING) {
    163 		sap_power_sim_on_rsp(sap_device,
    164 					SAP_RESULT_ERROR_CARD_REMOVED);
    165 	} else if (sim_card_conn_status == SIM_POWERED_OFF) {
    166 		sap_power_sim_on_rsp(sap_device, SAP_RESULT_OK);
    167 		sim_card_conn_status = SIM_CONNECTED;
    168 		return;
    169 	} else if (sim_card_conn_status != SIM_CONNECTED) {
    170 		sap_power_sim_on_rsp(sap_device,
    171 					SAP_RESULT_ERROR_NOT_ACCESSIBLE);
    172 	} else {
    173 		sap_power_sim_on_rsp(sap_device,
    174 					SAP_RESULT_ERROR_NO_REASON);
    175 	}
    176 }
    177 
    178 void sap_reset_sim_req(void *sap_device)
    179 {
    180 	DBG("status: %d", sim_card_conn_status);
    181 
    182 	if (sim_card_conn_status == SIM_MISSING) {
    183 		sap_reset_sim_rsp(sap_device, SAP_RESULT_ERROR_CARD_REMOVED);
    184 	} else if (sim_card_conn_status == SIM_POWERED_OFF) {
    185 		sap_reset_sim_rsp(sap_device, SAP_RESULT_ERROR_POWERED_OFF);
    186 	} else if (sim_card_conn_status != SIM_CONNECTED) {
    187 		sap_reset_sim_rsp(sap_device, SAP_RESULT_ERROR_NO_REASON);
    188 	} else {
    189 		sap_reset_sim_rsp(sap_device, SAP_RESULT_OK);
    190 	}
    191 }
    192 
    193 void sap_transfer_card_reader_status_req(void *sap_device)
    194 {
    195 	DBG("status: %d", sim_card_conn_status);
    196 
    197 	if (sim_card_conn_status != SIM_CONNECTED) {
    198 		sap_transfer_card_reader_status_rsp(sap_device,
    199 					SAP_RESULT_ERROR_NO_REASON, 0xF1);
    200 		return;
    201 	}
    202 
    203 	sap_transfer_card_reader_status_rsp(sap_device, SAP_RESULT_OK, 0xF1);
    204 }
    205 
    206 void sap_set_transport_protocol_req(void *sap_device,
    207 					struct sap_parameter *param)
    208 {
    209 	sap_transport_protocol_rsp(sap_device, SAP_RESULT_NOT_SUPPORTED);
    210 }
    211 
    212 static inline DBusMessage *invalid_args(DBusMessage *msg)
    213 {
    214 	return g_dbus_create_error(msg, "org.bluez.Error.InvalidArguments",
    215 					"Invalid arguments in method call");
    216 }
    217 
    218 static DBusMessage *ongoing_call(DBusConnection *conn, DBusMessage *msg,
    219 						void *data)
    220 {
    221 	dbus_bool_t ongoing;
    222 
    223 	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_BOOLEAN, &ongoing,
    224 						DBUS_TYPE_INVALID))
    225 		return invalid_args(msg);
    226 
    227 	if (ongoing_call_status && !ongoing) {
    228 		/* An ongoing call has finished. Continue connection.*/
    229 		sap_connect_rsp(sap_data, SAP_STATUS_OK,
    230 						max_msg_size_supported);
    231 		sap_status_ind(sap_data, SAP_STATUS_CHANGE_CARD_RESET);
    232 		ongoing_call_status = ongoing;
    233 	} else if (!ongoing_call_status && ongoing) {
    234 		/* An ongoing call has started.*/
    235 		ongoing_call_status = ongoing;
    236 	}
    237 
    238 	DBG("OngoingCall status set to %d", ongoing_call_status);
    239 
    240 	return dbus_message_new_method_return(msg);
    241 }
    242 
    243 static DBusMessage *max_msg_size(DBusConnection *conn, DBusMessage *msg,
    244 						void *data)
    245 {
    246 	dbus_uint32_t size;
    247 
    248 	if (sim_card_conn_status == SIM_CONNECTED)
    249 		return g_dbus_create_error(msg, "org.bluez.Error.Failed",
    250 				"Can't change msg size when connected.");
    251 
    252 	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &size,
    253 							DBUS_TYPE_INVALID))
    254 		return invalid_args(msg);
    255 
    256 	max_msg_size_supported = size;
    257 
    258 	DBG("MaxMessageSize set to %d", max_msg_size_supported);
    259 
    260 	return dbus_message_new_method_return(msg);
    261 }
    262 
    263 static DBusMessage *disconnect_immediate(DBusConnection *conn, DBusMessage *msg,
    264 						void *data)
    265 {
    266 	if (sim_card_conn_status == SIM_DISCONNECTED)
    267 		return g_dbus_create_error(msg, "org.bluez.Error.Failed",
    268 				"Already disconnected.");
    269 
    270 	sim_card_conn_status = SIM_DISCONNECTED;
    271 	sap_disconnect_ind(sap_data, SAP_DISCONNECTION_TYPE_IMMEDIATE);
    272 
    273 	return dbus_message_new_method_return(msg);
    274 }
    275 
    276 static DBusMessage *card_status(DBusConnection *conn, DBusMessage *msg,
    277 								void *data)
    278 {
    279 	dbus_uint32_t status;
    280 
    281 	DBG("status %d", sim_card_conn_status);
    282 
    283 	if (sim_card_conn_status != SIM_CONNECTED)
    284 		return g_dbus_create_error(msg, "org.bluez.Error.Failed",
    285 				"Can't change msg size when not connected.");
    286 
    287 	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &status,
    288 							DBUS_TYPE_INVALID))
    289 		return invalid_args(msg);
    290 
    291 	switch (status) {
    292 	case 0: /* card removed */
    293 		sim_card_conn_status = SIM_MISSING;
    294 		sap_status_ind(sap_data, SAP_STATUS_CHANGE_CARD_REMOVED);
    295 		break;
    296 
    297 	case 1: /* card inserted */
    298 		if (sim_card_conn_status == SIM_MISSING) {
    299 			sim_card_conn_status = SIM_CONNECTED;
    300 			sap_status_ind(sap_data,
    301 					SAP_STATUS_CHANGE_CARD_INSERTED);
    302 		}
    303 		break;
    304 
    305 	case 2: /* card not longer available*/
    306 		sim_card_conn_status = SIM_POWERED_OFF;
    307 		sap_status_ind(sap_data, SAP_STATUS_CHANGE_CARD_NOT_ACCESSIBLE);
    308 		break;
    309 
    310 	default:
    311 		return g_dbus_create_error(msg, "org.bluez.Error.Failed",
    312 				"Unknown card status. Use 0, 1 or 2.");
    313 	}
    314 
    315 	DBG("Card status changed to %d", status);
    316 
    317 	return dbus_message_new_method_return(msg);
    318 }
    319 
    320 static GDBusMethodTable dummy_methods[] = {
    321 	{ "OngoingCall", "b", "", ongoing_call},
    322 	{ "MaxMessageSize", "u", "", max_msg_size},
    323 	{ "DisconnectImmediate", "", "", disconnect_immediate},
    324 	{ "CardStatus", "u", "", card_status},
    325 	{ }
    326 };
    327 
    328 int sap_init(void)
    329 {
    330 	connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
    331 
    332 	if (g_dbus_register_interface(connection, SAP_DUMMY_PATH,
    333 				SAP_DUMMY_IFACE, dummy_methods, NULL, NULL,
    334 				NULL, NULL) == FALSE) {
    335 		error("sap-dummy interface %s init failed on path %s",
    336 					SAP_DUMMY_IFACE, SAP_DUMMY_PATH);
    337 		return -1;
    338 	}
    339 
    340 	return 0;
    341 }
    342 
    343 void sap_exit(void)
    344 {
    345 	dbus_connection_unref(connection);
    346 	connection = NULL;
    347 }
    348