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