| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411 |
- // SPDX-License-Identifier: GPL-2.0-or-later
- /*
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2010 Instituto Nokia de Tecnologia - INdT
- * Copyright (C) 2010 ST-Ericsson SA
- * Copyright (C) 2011 Tieto Poland
- *
- * Author: Marek Skowron <marek.skowron@tieto.com> for ST-Ericsson.
- * Author: Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com>
- * for ST-Ericsson.
- *
- */
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
- #include <errno.h>
- #include <glib.h>
- #include "lib/sdp.h"
- #include "lib/sdp_lib.h"
- #include "lib/uuid.h"
- #include "gdbus/gdbus.h"
- #include "btio/btio.h"
- #include "src/adapter.h"
- #include "src/sdpd.h"
- #include "src/log.h"
- #include "src/error.h"
- #include "src/dbus-common.h"
- #include "src/shared/timeout.h"
- #include "src/shared/util.h"
- #include "sap.h"
- #include "server.h"
- #define SAP_SERVER_INTERFACE "org.bluez.SimAccess1"
- #define SAP_SERVER_CHANNEL 8
- #define PADDING4(x) ((4 - ((x) & 0x03)) & 0x03)
- #define PARAMETER_SIZE(x) (sizeof(struct sap_parameter) + x + PADDING4(x))
- #define SAP_NO_REQ 0xFF
- #define SAP_DISCONNECTION_TYPE_CLIENT 0xFF
- #define SAP_TIMER_GRACEFUL_DISCONNECT 30
- #define SAP_TIMER_NO_ACTIVITY 30
- enum {
- SAP_STATE_DISCONNECTED,
- SAP_STATE_CONNECT_IN_PROGRESS,
- SAP_STATE_CONNECT_MODEM_BUSY,
- SAP_STATE_CONNECTED,
- SAP_STATE_GRACEFUL_DISCONNECT,
- SAP_STATE_IMMEDIATE_DISCONNECT,
- SAP_STATE_CLIENT_DISCONNECT
- };
- struct sap_connection {
- GIOChannel *io;
- uint32_t state;
- uint8_t processing_req;
- unsigned int timer_id;
- };
- struct sap_server {
- struct btd_adapter *adapter;
- uint32_t record_id;
- GIOChannel *listen_io;
- struct sap_connection *conn;
- };
- static void start_guard_timer(struct sap_server *server, guint interval);
- static void stop_guard_timer(struct sap_server *server);
- static bool guard_timeout(gpointer data);
- static size_t add_result_parameter(uint8_t result,
- struct sap_parameter *param)
- {
- param->id = SAP_PARAM_ID_RESULT_CODE;
- param->len = htons(SAP_PARAM_ID_RESULT_CODE_LEN);
- *param->val = result;
- return PARAMETER_SIZE(SAP_PARAM_ID_RESULT_CODE_LEN);
- }
- static 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 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(struct sap_message *msg)
- {
- switch (msg->id) {
- case SAP_CONNECT_REQ:
- if (msg->nparam != 0x01)
- return -EBADMSG;
- if (msg->param->id != SAP_PARAM_ID_MAX_MSG_SIZE)
- return -EBADMSG;
- if (ntohs(msg->param->len) != SAP_PARAM_ID_MAX_MSG_SIZE_LEN)
- return -EBADMSG;
- break;
- case SAP_TRANSFER_APDU_REQ:
- if (msg->nparam != 0x01)
- return -EBADMSG;
- if (msg->param->id != SAP_PARAM_ID_COMMAND_APDU)
- if (msg->param->id != SAP_PARAM_ID_COMMAND_APDU7816)
- return -EBADMSG;
- if (msg->param->len == 0x00)
- return -EBADMSG;
- break;
- case SAP_SET_TRANSPORT_PROTOCOL_REQ:
- if (msg->nparam != 0x01)
- return -EBADMSG;
- if (msg->param->id != SAP_PARAM_ID_TRANSPORT_PROTOCOL)
- return -EBADMSG;
- if (ntohs(msg->param->len) != SAP_PARAM_ID_TRANSPORT_PROTO_LEN)
- return -EBADMSG;
- if (*msg->param->val != SAP_TRANSPORT_PROTOCOL_T0)
- if (*msg->param->val != SAP_TRANSPORT_PROTOCOL_T1)
- return -EBADMSG;
- 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 -EBADMSG;
- break;
- }
- return 0;
- }
- 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;
- sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
- 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_connection *conn, void *buf, size_t size)
- {
- size_t written = 0;
- GError *gerr = NULL;
- GIOStatus gstatus;
- SAP_VDBG("conn %p, size %zu", conn, size);
- gstatus = g_io_channel_write_chars(conn->io, buf, size, &written,
- &gerr);
- if (gstatus != G_IO_STATUS_NORMAL) {
- if (gerr)
- g_error_free(gerr);
- error("write error (0x%02x).", gstatus);
- return -EIO;
- }
- if (written != size) {
- error("written %zu bytes out of %zu", written, size);
- return -EIO;
- }
- return written;
- }
- static int disconnect_ind(struct sap_connection *conn, uint8_t disc_type)
- {
- char buf[SAP_BUF_SIZE];
- struct sap_message *msg = (struct sap_message *) buf;
- struct sap_parameter *param = (struct sap_parameter *) msg->param;
- size_t size = sizeof(struct sap_message);
- DBG("data %p state %d disc_type 0x%02x", conn, conn->state, disc_type);
- memset(buf, 0, sizeof(buf));
- msg->id = SAP_DISCONNECT_IND;
- msg->nparam = 0x01;
- /* Add disconnection type param. */
- param->id = SAP_PARAM_ID_DISCONNECT_IND;
- param->len = htons(SAP_PARAM_ID_DISCONNECT_IND_LEN);
- *param->val = disc_type;
- size += PARAMETER_SIZE(SAP_PARAM_ID_DISCONNECT_IND_LEN);
- return send_message(conn, buf, size);
- }
- static int sap_error_rsp(struct sap_connection *conn)
- {
- struct sap_message msg;
- memset(&msg, 0, sizeof(msg));
- msg.id = SAP_ERROR_RESP;
- error("SAP error (state %d pr 0x%02x).", conn->state,
- conn->processing_req);
- return send_message(conn, &msg, sizeof(msg));
- }
- static void connect_req(struct sap_server *server,
- struct sap_parameter *param)
- {
- struct sap_connection *conn = server->conn;
- uint16_t maxmsgsize;
- DBG("conn %p state %d", conn, conn->state);
- if (!param)
- goto error_rsp;
- if (conn->state != SAP_STATE_DISCONNECTED)
- goto error_rsp;
- stop_guard_timer(server);
- maxmsgsize = get_be16(¶m->val);
- DBG("Connect MaxMsgSize: 0x%04x", maxmsgsize);
- conn->state = SAP_STATE_CONNECT_IN_PROGRESS;
- if (maxmsgsize <= SAP_BUF_SIZE) {
- conn->processing_req = SAP_CONNECT_REQ;
- sap_connect_req(server, maxmsgsize);
- } else {
- sap_connect_rsp(server, SAP_STATUS_MAX_MSG_SIZE_NOT_SUPPORTED);
- }
- return;
- error_rsp:
- sap_error_rsp(conn);
- }
- static int disconnect_req(struct sap_server *server, uint8_t disc_type)
- {
- struct sap_connection *conn = server->conn;
- DBG("conn %p state %d disc_type 0x%02x", conn, conn->state, disc_type);
- switch (disc_type) {
- case SAP_DISCONNECTION_TYPE_GRACEFUL:
- if (conn->state == SAP_STATE_DISCONNECTED ||
- conn->state == SAP_STATE_CONNECT_IN_PROGRESS ||
- conn->state == SAP_STATE_CONNECT_MODEM_BUSY)
- return -EPERM;
- if (conn->state == SAP_STATE_CONNECTED) {
- conn->state = SAP_STATE_GRACEFUL_DISCONNECT;
- conn->processing_req = SAP_NO_REQ;
- disconnect_ind(conn, disc_type);
- /* Timer will disconnect if client won't do.*/
- start_guard_timer(server,
- SAP_TIMER_GRACEFUL_DISCONNECT);
- }
- return 0;
- case SAP_DISCONNECTION_TYPE_IMMEDIATE:
- if (conn->state == SAP_STATE_DISCONNECTED ||
- conn->state == SAP_STATE_CONNECT_IN_PROGRESS ||
- conn->state == SAP_STATE_CONNECT_MODEM_BUSY)
- return -EPERM;
- if (conn->state == SAP_STATE_CONNECTED ||
- conn->state == SAP_STATE_GRACEFUL_DISCONNECT) {
- conn->state = SAP_STATE_IMMEDIATE_DISCONNECT;
- conn->processing_req = SAP_NO_REQ;
- stop_guard_timer(server);
- disconnect_ind(conn, disc_type);
- sap_disconnect_req(server, 0);
- }
- return 0;
- case SAP_DISCONNECTION_TYPE_CLIENT:
- if (conn->state != SAP_STATE_CONNECTED &&
- conn->state != SAP_STATE_GRACEFUL_DISCONNECT) {
- sap_error_rsp(conn);
- return -EPERM;
- }
- conn->state = SAP_STATE_CLIENT_DISCONNECT;
- conn->processing_req = SAP_NO_REQ;
- stop_guard_timer(server);
- sap_disconnect_req(server, 0);
- return 0;
- default:
- error("Unknown disconnection type (0x%02x).", disc_type);
- return -EINVAL;
- }
- }
- static void transfer_apdu_req(struct sap_server *server,
- struct sap_parameter *param)
- {
- struct sap_connection *conn = server->conn;
- SAP_VDBG("conn %p state %d", conn, conn->state);
- if (!param)
- goto error_rsp;
- param->len = ntohs(param->len);
- if (conn->state != SAP_STATE_CONNECTED &&
- conn->state != SAP_STATE_GRACEFUL_DISCONNECT)
- goto error_rsp;
- if (conn->processing_req != SAP_NO_REQ)
- goto error_rsp;
- conn->processing_req = SAP_TRANSFER_APDU_REQ;
- sap_transfer_apdu_req(server, param);
- return;
- error_rsp:
- sap_error_rsp(conn);
- }
- static void transfer_atr_req(struct sap_server *server)
- {
- struct sap_connection *conn = server->conn;
- DBG("conn %p state %d", conn, conn->state);
- if (conn->state != SAP_STATE_CONNECTED)
- goto error_rsp;
- if (conn->processing_req != SAP_NO_REQ)
- goto error_rsp;
- conn->processing_req = SAP_TRANSFER_ATR_REQ;
- sap_transfer_atr_req(server);
- return;
- error_rsp:
- sap_error_rsp(conn);
- }
- static void power_sim_off_req(struct sap_server *server)
- {
- struct sap_connection *conn = server->conn;
- DBG("conn %p state %d", conn, conn->state);
- if (conn->state != SAP_STATE_CONNECTED)
- goto error_rsp;
- if (!is_power_sim_off_req_allowed(conn->processing_req))
- goto error_rsp;
- conn->processing_req = SAP_POWER_SIM_OFF_REQ;
- sap_power_sim_off_req(server);
- return;
- error_rsp:
- sap_error_rsp(conn);
- }
- static void power_sim_on_req(struct sap_server *server)
- {
- struct sap_connection *conn = server->conn;
- DBG("conn %p state %d", conn, conn->state);
- if (conn->state != SAP_STATE_CONNECTED)
- goto error_rsp;
- if (conn->processing_req != SAP_NO_REQ)
- goto error_rsp;
- conn->processing_req = SAP_POWER_SIM_ON_REQ;
- sap_power_sim_on_req(server);
- return;
- error_rsp:
- sap_error_rsp(conn);
- }
- static void reset_sim_req(struct sap_server *server)
- {
- struct sap_connection *conn = server->conn;
- DBG("conn %p state %d", conn, conn->state);
- if (conn->state != SAP_STATE_CONNECTED)
- goto error_rsp;
- if (!is_reset_sim_req_allowed(conn->processing_req))
- goto error_rsp;
- conn->processing_req = SAP_RESET_SIM_REQ;
- sap_reset_sim_req(server);
- return;
- error_rsp:
- sap_error_rsp(conn);
- }
- static void transfer_card_reader_status_req(struct sap_server *server)
- {
- struct sap_connection *conn = server->conn;
- DBG("conn %p state %d", conn, conn->state);
- if (conn->state != SAP_STATE_CONNECTED)
- goto error_rsp;
- if (conn->processing_req != SAP_NO_REQ)
- goto error_rsp;
- conn->processing_req = SAP_TRANSFER_CARD_READER_STATUS_REQ;
- sap_transfer_card_reader_status_req(server);
- return;
- error_rsp:
- sap_error_rsp(conn);
- }
- static void set_transport_protocol_req(struct sap_server *server,
- struct sap_parameter *param)
- {
- struct sap_connection *conn = server->conn;
- if (!param)
- goto error_rsp;
- DBG("conn %p state %d param %p", conn, conn->state, param);
- if (conn->state != SAP_STATE_CONNECTED)
- goto error_rsp;
- if (conn->processing_req != SAP_NO_REQ)
- goto error_rsp;
- conn->processing_req = SAP_SET_TRANSPORT_PROTOCOL_REQ;
- sap_set_transport_protocol_req(server, param);
- return;
- error_rsp:
- sap_error_rsp(conn);
- }
- static void start_guard_timer(struct sap_server *server, guint interval)
- {
- struct sap_connection *conn = server->conn;
- if (!conn)
- return;
- if (!conn->timer_id)
- conn->timer_id = timeout_add_seconds(interval, guard_timeout,
- server, NULL);
- else
- error("Timer is already active.");
- }
- static void stop_guard_timer(struct sap_server *server)
- {
- struct sap_connection *conn = server->conn;
- if (conn && conn->timer_id) {
- timeout_remove(conn->timer_id);
- conn->timer_id = 0;
- }
- }
- static bool guard_timeout(gpointer data)
- {
- struct sap_server *server = data;
- struct sap_connection *conn = server->conn;
- if (!conn)
- return FALSE;
- DBG("conn %p state %d pr 0x%02x", conn, conn->state,
- conn->processing_req);
- conn->timer_id = 0;
- switch (conn->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 (conn->io) {
- g_io_channel_shutdown(conn->io, TRUE, NULL);
- g_io_channel_unref(conn->io);
- conn->io = 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("Unexpected state (%d).", conn->state);
- break;
- }
- return FALSE;
- }
- static void sap_set_connected(struct sap_server *server)
- {
- server->conn->state = SAP_STATE_CONNECTED;
- g_dbus_emit_property_changed(btd_get_dbus_connection(),
- adapter_get_path(server->adapter),
- SAP_SERVER_INTERFACE, "Connected");
- }
- int sap_connect_rsp(void *sap_device, uint8_t status)
- {
- struct sap_server *server = sap_device;
- struct sap_connection *conn = server->conn;
- char buf[SAP_BUF_SIZE];
- struct sap_message *msg = (struct sap_message *) buf;
- struct sap_parameter *param = (struct sap_parameter *) msg->param;
- size_t size = sizeof(struct sap_message);
- if (!conn)
- return -EINVAL;
- DBG("state %d pr 0x%02x status 0x%02x", conn->state,
- conn->processing_req, status);
- if (conn->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 = status;
- size += PARAMETER_SIZE(SAP_PARAM_ID_CONN_STATUS_LEN);
- switch (status) {
- case SAP_STATUS_OK:
- sap_set_connected(server);
- break;
- case SAP_STATUS_OK_ONGOING_CALL:
- DBG("ongoing call. Wait for reset indication!");
- conn->state = SAP_STATE_CONNECT_MODEM_BUSY;
- break;
- case SAP_STATUS_MAX_MSG_SIZE_NOT_SUPPORTED: /* Add MaxMsgSize */
- msg->nparam++;
- param = (struct sap_parameter *) &buf[size];
- param->id = SAP_PARAM_ID_MAX_MSG_SIZE;
- param->len = htons(SAP_PARAM_ID_MAX_MSG_SIZE_LEN);
- put_be16(SAP_BUF_SIZE, ¶m->val);
- size += PARAMETER_SIZE(SAP_PARAM_ID_MAX_MSG_SIZE_LEN);
- /* fall through */
- default:
- conn->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);
- break;
- }
- conn->processing_req = SAP_NO_REQ;
- return send_message(conn, buf, size);
- }
- int sap_disconnect_rsp(void *sap_device)
- {
- struct sap_server *server = sap_device;
- struct sap_connection *conn = server->conn;
- struct sap_message msg;
- if (!conn)
- return -EINVAL;
- DBG("state %d pr 0x%02x", conn->state, conn->processing_req);
- switch (conn->state) {
- case SAP_STATE_CLIENT_DISCONNECT:
- memset(&msg, 0, sizeof(msg));
- msg.id = SAP_DISCONNECT_RESP;
- conn->state = SAP_STATE_DISCONNECTED;
- conn->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(conn, &msg, sizeof(msg));
- case SAP_STATE_IMMEDIATE_DISCONNECT:
- conn->state = SAP_STATE_DISCONNECTED;
- conn->processing_req = SAP_NO_REQ;
- if (conn->io) {
- g_io_channel_shutdown(conn->io, TRUE, NULL);
- g_io_channel_unref(conn->io);
- conn->io = NULL;
- }
- return 0;
- default:
- break;
- }
- return 0;
- }
- int sap_transfer_apdu_rsp(void *sap_device, uint8_t result, uint8_t *apdu,
- uint16_t length)
- {
- struct sap_server *server = sap_device;
- struct sap_connection *conn = server->conn;
- char buf[SAP_BUF_SIZE];
- struct sap_message *msg = (struct sap_message *) buf;
- struct sap_parameter *param = (struct sap_parameter *) msg->param;
- size_t size = sizeof(struct sap_message);
- if (!conn)
- return -EINVAL;
- SAP_VDBG("state %d pr 0x%02x", conn->state, conn->processing_req);
- if (conn->processing_req != SAP_TRANSFER_APDU_REQ)
- return 0;
- if (result == SAP_RESULT_OK && (!apdu || (apdu && length == 0x00)))
- return -EINVAL;
- memset(buf, 0, sizeof(buf));
- msg->id = SAP_TRANSFER_APDU_RESP;
- msg->nparam = 0x01;
- size += add_result_parameter(result, param);
- /* Add APDU response. */
- if (result == SAP_RESULT_OK) {
- msg->nparam++;
- param = (struct 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);
- }
- conn->processing_req = SAP_NO_REQ;
- return send_message(conn, buf, size);
- }
- int sap_transfer_atr_rsp(void *sap_device, uint8_t result, uint8_t *atr,
- uint16_t length)
- {
- struct sap_server *server = sap_device;
- struct sap_connection *conn = server->conn;
- char buf[SAP_BUF_SIZE];
- struct sap_message *msg = (struct sap_message *) buf;
- struct sap_parameter *param = (struct sap_parameter *) msg->param;
- size_t size = sizeof(struct sap_message);
- if (!conn)
- return -EINVAL;
- DBG("result 0x%02x state %d pr 0x%02x len %d", result, conn->state,
- conn->processing_req, length);
- if (conn->processing_req != SAP_TRANSFER_ATR_REQ)
- return 0;
- if (result == SAP_RESULT_OK && (!atr || (atr && length == 0x00)))
- return -EINVAL;
- memset(buf, 0, sizeof(buf));
- msg->id = SAP_TRANSFER_ATR_RESP;
- msg->nparam = 0x01;
- size += add_result_parameter(result, param);
- /* Add ATR response */
- if (result == SAP_RESULT_OK) {
- msg->nparam++;
- param = (struct 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);
- }
- conn->processing_req = SAP_NO_REQ;
- return send_message(conn, buf, size);
- }
- int sap_power_sim_off_rsp(void *sap_device, uint8_t result)
- {
- struct sap_server *server = sap_device;
- struct sap_connection *conn = server->conn;
- char buf[SAP_BUF_SIZE];
- struct sap_message *msg = (struct sap_message *) buf;
- size_t size = sizeof(struct sap_message);
- if (!conn)
- return -EINVAL;
- DBG("state %d pr 0x%02x", conn->state, conn->processing_req);
- if (conn->processing_req != SAP_POWER_SIM_OFF_REQ)
- return 0;
- memset(buf, 0, sizeof(buf));
- msg->id = SAP_POWER_SIM_OFF_RESP;
- msg->nparam = 0x01;
- size += add_result_parameter(result, msg->param);
- conn->processing_req = SAP_NO_REQ;
- return send_message(conn, buf, size);
- }
- int sap_power_sim_on_rsp(void *sap_device, uint8_t result)
- {
- struct sap_server *server = sap_device;
- struct sap_connection *conn = server->conn;
- char buf[SAP_BUF_SIZE];
- struct sap_message *msg = (struct sap_message *) buf;
- size_t size = sizeof(struct sap_message);
- if (!conn)
- return -EINVAL;
- DBG("state %d pr 0x%02x", conn->state, conn->processing_req);
- if (conn->processing_req != SAP_POWER_SIM_ON_REQ)
- return 0;
- memset(buf, 0, sizeof(buf));
- msg->id = SAP_POWER_SIM_ON_RESP;
- msg->nparam = 0x01;
- size += add_result_parameter(result, msg->param);
- conn->processing_req = SAP_NO_REQ;
- return send_message(conn, buf, size);
- }
- int sap_reset_sim_rsp(void *sap_device, uint8_t result)
- {
- struct sap_server *server = sap_device;
- struct sap_connection *conn = server->conn;
- char buf[SAP_BUF_SIZE];
- struct sap_message *msg = (struct sap_message *) buf;
- size_t size = sizeof(struct sap_message);
- if (!conn)
- return -EINVAL;
- DBG("state %d pr 0x%02x result 0x%02x", conn->state,
- conn->processing_req, result);
- if (conn->processing_req != SAP_RESET_SIM_REQ)
- return 0;
- memset(buf, 0, sizeof(buf));
- msg->id = SAP_RESET_SIM_RESP;
- msg->nparam = 0x01;
- size += add_result_parameter(result, msg->param);
- conn->processing_req = SAP_NO_REQ;
- return send_message(conn, buf, size);
- }
- int sap_transfer_card_reader_status_rsp(void *sap_device, uint8_t result,
- uint8_t status)
- {
- struct sap_server *server = sap_device;
- struct sap_connection *conn = server->conn;
- char buf[SAP_BUF_SIZE];
- struct sap_message *msg = (struct sap_message *) buf;
- struct sap_parameter *param = (struct sap_parameter *) msg->param;
- size_t size = sizeof(struct sap_message);
- if (!conn)
- return -EINVAL;
- DBG("state %d pr 0x%02x result 0x%02x", conn->state,
- conn->processing_req, result);
- if (conn->processing_req != SAP_TRANSFER_CARD_READER_STATUS_REQ)
- return 0;
- memset(buf, 0, sizeof(buf));
- msg->id = SAP_TRANSFER_CARD_READER_STATUS_RESP;
- msg->nparam = 0x01;
- size += add_result_parameter(result, param);
- /* Add card reader status. */
- if (result == SAP_RESULT_OK) {
- msg->nparam++;
- param = (struct sap_parameter *) &buf[size];
- param->id = SAP_PARAM_ID_CARD_READER_STATUS;
- param->len = htons(SAP_PARAM_ID_CARD_READER_STATUS_LEN);
- *param->val = status;
- size += PARAMETER_SIZE(SAP_PARAM_ID_CARD_READER_STATUS_LEN);
- }
- conn->processing_req = SAP_NO_REQ;
- return send_message(conn, buf, size);
- }
- int sap_transport_protocol_rsp(void *sap_device, uint8_t result)
- {
- struct sap_server *server = sap_device;
- struct sap_connection *conn = server->conn;
- char buf[SAP_BUF_SIZE];
- struct sap_message *msg = (struct sap_message *) buf;
- size_t size = sizeof(struct sap_message);
- if (!conn)
- return -EINVAL;
- DBG("state %d pr 0x%02x result 0x%02x", conn->state,
- conn->processing_req, result);
- if (conn->processing_req != SAP_SET_TRANSPORT_PROTOCOL_REQ)
- return 0;
- memset(buf, 0, sizeof(buf));
- msg->id = SAP_SET_TRANSPORT_PROTOCOL_RESP;
- msg->nparam = 0x01;
- size += add_result_parameter(result, msg->param);
- conn->processing_req = SAP_NO_REQ;
- return send_message(conn, buf, size);
- }
- int sap_status_ind(void *sap_device, uint8_t status_change)
- {
- struct sap_server *server = sap_device;
- struct sap_connection *conn = server->conn;
- char buf[SAP_BUF_SIZE];
- struct sap_message *msg = (struct sap_message *) buf;
- struct sap_parameter *param = (struct sap_parameter *) msg->param;
- size_t size = sizeof(struct sap_message);
- if (!conn)
- return -EINVAL;
- DBG("state %d pr 0x%02x sc 0x%02x", conn->state, conn->processing_req,
- status_change);
- switch (conn->state) {
- case SAP_STATE_CONNECT_MODEM_BUSY:
- if (status_change != SAP_STATUS_CHANGE_CARD_RESET)
- break;
- /* Change state to connected after ongoing call ended */
- sap_set_connected(server);
- /* fall through */
- case SAP_STATE_CONNECTED:
- case SAP_STATE_GRACEFUL_DISCONNECT:
- memset(buf, 0, sizeof(buf));
- 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 = status_change;
- size += PARAMETER_SIZE(SAP_PARAM_ID_STATUS_CHANGE_LEN);
- return send_message(conn, buf, size);
- case SAP_STATE_DISCONNECTED:
- case SAP_STATE_CONNECT_IN_PROGRESS:
- case SAP_STATE_IMMEDIATE_DISCONNECT:
- case SAP_STATE_CLIENT_DISCONNECT:
- break;
- }
- return 0;
- }
- int sap_disconnect_ind(void *sap_device, uint8_t disc_type)
- {
- return disconnect_req(sap_device, SAP_DISCONNECTION_TYPE_IMMEDIATE);
- }
- static int handle_cmd(struct sap_server *server, void *buf, size_t size)
- {
- struct sap_connection *conn = server->conn;
- struct sap_message *msg = buf;
- if (!conn)
- return -EINVAL;
- if (size < sizeof(struct sap_message))
- goto error_rsp;
- if (msg->nparam != 0 && size < (sizeof(struct sap_message) +
- sizeof(struct sap_parameter) + 4))
- goto error_rsp;
- if (check_msg(msg) < 0)
- goto error_rsp;
- switch (msg->id) {
- case SAP_CONNECT_REQ:
- connect_req(server, msg->param);
- return 0;
- case SAP_DISCONNECT_REQ:
- disconnect_req(server, SAP_DISCONNECTION_TYPE_CLIENT);
- return 0;
- case SAP_TRANSFER_APDU_REQ:
- transfer_apdu_req(server, msg->param);
- return 0;
- case SAP_TRANSFER_ATR_REQ:
- transfer_atr_req(server);
- return 0;
- case SAP_POWER_SIM_OFF_REQ:
- power_sim_off_req(server);
- return 0;
- case SAP_POWER_SIM_ON_REQ:
- power_sim_on_req(server);
- return 0;
- case SAP_RESET_SIM_REQ:
- reset_sim_req(server);
- return 0;
- case SAP_TRANSFER_CARD_READER_STATUS_REQ:
- transfer_card_reader_status_req(server);
- return 0;
- case SAP_SET_TRANSPORT_PROTOCOL_REQ:
- set_transport_protocol_req(server, msg->param);
- return 0;
- default:
- DBG("Unknown SAP message id 0x%02x.", msg->id);
- break;
- }
- error_rsp:
- DBG("Invalid SAP message format.");
- sap_error_rsp(conn);
- return -EBADMSG;
- }
- static void sap_server_remove_conn(struct sap_server *server)
- {
- struct sap_connection *conn = server->conn;
- DBG("conn %p", conn);
- if (!conn)
- return;
- if (conn->io) {
- g_io_channel_shutdown(conn->io, TRUE, NULL);
- g_io_channel_unref(conn->io);
- }
- g_free(conn);
- server->conn = NULL;
- }
- static gboolean sap_io_cb(GIOChannel *io, GIOCondition cond, gpointer data)
- {
- char buf[SAP_BUF_SIZE];
- size_t bytes_read = 0;
- GError *gerr = NULL;
- GIOStatus gstatus;
- SAP_VDBG("conn %p io %p", conn, io);
- 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(io, 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("SAP protocol processing failure.");
- return TRUE;
- }
- static void sap_io_destroy(void *data)
- {
- struct sap_server *server = data;
- struct sap_connection *conn = server->conn;
- DBG("conn %p", conn);
- if (!conn || !conn->io)
- return;
- stop_guard_timer(server);
- if (conn->state != SAP_STATE_CONNECT_IN_PROGRESS &&
- conn->state != SAP_STATE_CONNECT_MODEM_BUSY)
- g_dbus_emit_property_changed(btd_get_dbus_connection(),
- adapter_get_path(server->adapter),
- SAP_SERVER_INTERFACE,
- "Connected");
- if (conn->state == SAP_STATE_CONNECT_IN_PROGRESS ||
- conn->state == SAP_STATE_CONNECT_MODEM_BUSY ||
- conn->state == SAP_STATE_CONNECTED ||
- conn->state == SAP_STATE_GRACEFUL_DISCONNECT)
- sap_disconnect_req(server, 1);
- sap_server_remove_conn(server);
- }
- static void sap_connect_cb(GIOChannel *io, GError *gerr, gpointer data)
- {
- struct sap_server *server = data;
- struct sap_connection *conn = server->conn;
- DBG("conn %p, io %p", conn, io);
- if (!conn)
- 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(io, G_PRIORITY_DEFAULT,
- G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
- sap_io_cb, server, sap_io_destroy);
- }
- static void connect_auth_cb(DBusError *derr, void *data)
- {
- struct sap_server *server = data;
- struct sap_connection *conn = server->conn;
- GError *gerr = NULL;
- DBG("conn %p", conn);
- if (!conn)
- return;
- if (derr && dbus_error_is_set(derr)) {
- error("Access has been denied (%s)", derr->message);
- sap_server_remove_conn(server);
- return;
- }
- if (!bt_io_accept(conn->io, sap_connect_cb, server, NULL, &gerr)) {
- error("bt_io_accept: %s", gerr->message);
- g_error_free(gerr);
- sap_server_remove_conn(server);
- return;
- }
- DBG("Access has been granted.");
- }
- static void connect_confirm_cb(GIOChannel *io, gpointer data)
- {
- struct sap_server *server = data;
- struct sap_connection *conn = server->conn;
- GError *gerr = NULL;
- bdaddr_t src, dst;
- char dstaddr[18];
- guint ret;
- DBG("conn %p io %p", conn, io);
- if (!io)
- return;
- if (conn) {
- DBG("Another SAP connection already exists.");
- g_io_channel_shutdown(io, TRUE, NULL);
- return;
- }
- conn = g_try_new0(struct sap_connection, 1);
- if (!conn) {
- error("Can't allocate memory for incoming SAP connection.");
- g_io_channel_shutdown(io, TRUE, NULL);
- return;
- }
- g_io_channel_set_encoding(io, NULL, NULL);
- g_io_channel_set_buffered(io, FALSE);
- server->conn = conn;
- conn->io = g_io_channel_ref(io);
- conn->state = SAP_STATE_DISCONNECTED;
- bt_io_get(io, &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);
- sap_server_remove_conn(server);
- return;
- }
- ba2str(&dst, dstaddr);
- ret = btd_request_authorization(&src, &dst, SAP_UUID, connect_auth_cb,
- server);
- if (ret == 0) {
- error("Authorization failure");
- sap_server_remove_conn(server);
- return;
- }
- DBG("Authorizing incoming SAP connection from %s", dstaddr);
- }
- static DBusMessage *disconnect(DBusConnection *conn, DBusMessage *msg,
- void *data)
- {
- struct sap_server *server = data;
- if (!server)
- return btd_error_failed(msg, "Server internal error.");
- DBG("conn %p", server->conn);
- if (!server->conn)
- return btd_error_failed(msg, "Client already disconnected");
- if (disconnect_req(server, SAP_DISCONNECTION_TYPE_GRACEFUL) < 0)
- return btd_error_failed(msg, "There is no active connection");
- return dbus_message_new_method_return(msg);
- }
- static gboolean server_property_get_connected(
- const GDBusPropertyTable *property,
- DBusMessageIter *iter, void *data)
- {
- struct sap_server *server = data;
- struct sap_connection *conn = server->conn;
- dbus_bool_t connected;
- if (!conn) {
- connected = FALSE;
- goto append;
- }
- connected = (conn->state == SAP_STATE_CONNECTED ||
- conn->state == SAP_STATE_GRACEFUL_DISCONNECT);
- append:
- dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &connected);
- return TRUE;
- }
- static const GDBusMethodTable server_methods[] = {
- { GDBUS_METHOD("Disconnect", NULL, NULL, disconnect) },
- { }
- };
- static const GDBusPropertyTable server_properties[] = {
- { "Connected", "b", server_property_get_connected },
- { }
- };
- static void server_remove(struct sap_server *server)
- {
- if (!server)
- return;
- sap_server_remove_conn(server);
- adapter_service_remove(server->adapter, 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;
- }
- btd_adapter_unref(server->adapter);
- 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,
- adapter_get_path(server->adapter));
- server_remove(server);
- }
- int sap_server_register(struct btd_adapter *adapter)
- {
- sdp_record_t *record = NULL;
- GError *gerr = NULL;
- GIOChannel *io;
- struct sap_server *server;
- if (sap_init() < 0) {
- error("Sap driver initialization failed.");
- return -1;
- }
- record = create_sap_record(SAP_SERVER_CHANNEL);
- if (!record) {
- error("Creating SAP SDP record failed.");
- goto sdp_err;
- }
- if (adapter_service_add(adapter, record) < 0) {
- error("Adding SAP SDP record to the SDP server failed.");
- sdp_record_free(record);
- goto sdp_err;
- }
- server = g_new0(struct sap_server, 1);
- server->adapter = btd_adapter_ref(adapter);
- server->record_id = record->handle;
- io = bt_io_listen(NULL, connect_confirm_cb, server,
- NULL, &gerr,
- BT_IO_OPT_SOURCE_BDADDR,
- btd_adapter_get_address(adapter),
- BT_IO_OPT_CHANNEL, SAP_SERVER_CHANNEL,
- BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_HIGH,
- BT_IO_OPT_CENTRAL, TRUE,
- BT_IO_OPT_INVALID);
- if (!io) {
- error("Can't listen at channel %d.", SAP_SERVER_CHANNEL);
- g_error_free(gerr);
- goto server_err;
- }
- server->listen_io = io;
- if (!g_dbus_register_interface(btd_get_dbus_connection(),
- adapter_get_path(server->adapter),
- SAP_SERVER_INTERFACE,
- server_methods, NULL,
- server_properties, server,
- destroy_sap_interface)) {
- error("D-Bus failed to register %s interface",
- SAP_SERVER_INTERFACE);
- goto server_err;
- }
- DBG("server %p, listen socket 0x%02x", server,
- g_io_channel_unix_get_fd(io));
- return 0;
- server_err:
- server_remove(server);
- sdp_err:
- sap_exit();
- return -1;
- }
- void sap_server_unregister(const char *path)
- {
- g_dbus_unregister_interface(btd_get_dbus_connection(),
- path, SAP_SERVER_INTERFACE);
- sap_exit();
- }
|