177 lines
4.9 KiB
C
177 lines
4.9 KiB
C
/* Simulated CCID card slot. This is used in absence of a real hardware back-end
|
|
* in order to test the CCID firmware codebase in a virtual environment */
|
|
|
|
/* (C) 2019-2020 by Harald Welte <laforge@gnumonks.org>
|
|
*
|
|
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
|
|
*/
|
|
|
|
#include <osmocom/core/msgb.h>
|
|
#include <osmocom/core/timer.h>
|
|
#include <osmocom/core/logging.h>
|
|
|
|
#include "ccid_device.h"
|
|
|
|
struct slotsim_slot {
|
|
struct osmo_timer_list pwron_timer;
|
|
struct osmo_timer_list xfr_timer;
|
|
/* bSeq of the operation currently in progress */
|
|
uint8_t seq;
|
|
};
|
|
|
|
struct slotsim_instance {
|
|
struct slotsim_slot slot[NR_SLOTS];
|
|
};
|
|
|
|
static struct slotsim_instance g_si;
|
|
|
|
struct slotsim_slot *ccid_slot2slotsim_slot(struct ccid_slot *cs)
|
|
{
|
|
OSMO_ASSERT(cs->slot_nr < ARRAY_SIZE(g_si.slot));
|
|
return &g_si.slot[cs->slot_nr];
|
|
}
|
|
|
|
static const uint8_t sysmousim_sjs1_atr[] = {
|
|
0x3B, 0x9F, 0x96, 0x80, 0x1F, 0xC7, 0x80, 0x31,
|
|
0xA0, 0x73, 0xBE, 0x21, 0x13, 0x67, 0x43, 0x20,
|
|
0x07, 0x18, 0x00, 0x00, 0x01, 0xA5 };
|
|
|
|
static const struct ccid_pars_decoded slotsim_def_pars = {
|
|
.fi = 372,
|
|
.di = 1,
|
|
.clock_stop = CCID_CLOCK_STOP_NOTALLOWED,
|
|
.inverse_convention = false,
|
|
.t0 = {
|
|
.guard_time_etu = 0,
|
|
.waiting_integer = 0,
|
|
},
|
|
/* FIXME: T=1 */
|
|
};
|
|
|
|
static void slotsim_pre_proc_cb(struct ccid_slot *cs, struct msgb *msg)
|
|
{
|
|
/* do nothing; real hardware would update the slot related state here */
|
|
}
|
|
|
|
static void slotsim_icc_power_on_async(struct ccid_slot *cs, struct msgb *msg,
|
|
const struct ccid_pc_to_rdr_icc_power_on *ipo)
|
|
{
|
|
struct slotsim_slot *ss = ccid_slot2slotsim_slot(cs);
|
|
|
|
ss->seq = ipo->hdr.bSeq;
|
|
LOGPCS(cs, LOGL_DEBUG, "scheduling pwron_timer\n");
|
|
osmo_timer_schedule(&ss->pwron_timer, 1, 0);
|
|
msgb_free(msg);
|
|
/* continues in timer call-back below */
|
|
}
|
|
static void slotsim_pwron_timer_cb(void *data)
|
|
{
|
|
struct ccid_slot *cs = data;
|
|
struct slotsim_slot *ss = ccid_slot2slotsim_slot(cs);
|
|
struct msgb *resp;
|
|
|
|
LOGPCS(cs, LOGL_DEBUG, "%s\n", __func__);
|
|
|
|
resp = ccid_gen_data_block(cs, ss->seq, CCID_CMD_STATUS_OK, 0,
|
|
sysmousim_sjs1_atr, sizeof(sysmousim_sjs1_atr));
|
|
ccid_slot_send_unbusy(cs, resp);
|
|
}
|
|
|
|
static void slotsim_xfr_block_async(struct ccid_slot *cs, struct msgb *msg,
|
|
const struct ccid_pc_to_rdr_xfr_block *xfb)
|
|
{
|
|
struct slotsim_slot *ss = ccid_slot2slotsim_slot(cs);
|
|
|
|
ss->seq = xfb->hdr.bSeq;
|
|
LOGPCS(cs, LOGL_DEBUG, "scheduling xfr_timer\n");
|
|
osmo_timer_schedule(&ss->xfr_timer, 0, 50000);
|
|
msgb_free(msg);
|
|
/* continues in timer call-back below */
|
|
}
|
|
static void slotsim_xfr_timer_cb(void *data)
|
|
{
|
|
struct ccid_slot *cs = data;
|
|
struct slotsim_slot *ss = ccid_slot2slotsim_slot(cs);
|
|
struct msgb *resp;
|
|
|
|
LOGPCS(cs, LOGL_DEBUG, "%s\n", __func__);
|
|
|
|
resp = ccid_gen_data_block(cs, ss->seq, CCID_CMD_STATUS_OK, 0, NULL, 0);
|
|
ccid_slot_send_unbusy(cs, resp);
|
|
}
|
|
|
|
|
|
static void slotsim_set_power(struct ccid_slot *cs, bool enable)
|
|
{
|
|
if (enable) {
|
|
cs->icc_powered = true;
|
|
cs->icc_in_reset = false;
|
|
} else {
|
|
cs->icc_powered = false;
|
|
cs->icc_in_reset = true;
|
|
}
|
|
}
|
|
|
|
static void slotsim_set_clock(struct ccid_slot *cs, enum ccid_clock_command cmd)
|
|
{
|
|
/* FIXME */
|
|
switch (cmd) {
|
|
case CCID_CLOCK_CMD_STOP:
|
|
break;
|
|
case CCID_CLOCK_CMD_RESTART:
|
|
break;
|
|
default:
|
|
OSMO_ASSERT(0);
|
|
}
|
|
}
|
|
|
|
static int slotsim_set_params(struct ccid_slot *cs, enum ccid_protocol_num proto,
|
|
const struct ccid_pars_decoded *pars_dec)
|
|
{
|
|
/* we always acknowledge all parameters */
|
|
return 0;
|
|
}
|
|
|
|
static int slotsim_set_rate_and_clock(struct ccid_slot *cs, uint32_t freq_hz, uint32_t rate_bps)
|
|
{
|
|
/* we always acknowledge all rates/clocks */
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int slotsim_init(struct ccid_slot *cs)
|
|
{
|
|
struct slotsim_slot *ss = ccid_slot2slotsim_slot(cs);
|
|
|
|
LOGPCS(cs, LOGL_DEBUG, "%s\n", __func__);
|
|
cs->icc_present = true;
|
|
cs->icc_powered = true;
|
|
osmo_timer_setup(&ss->pwron_timer, slotsim_pwron_timer_cb, cs);
|
|
osmo_timer_setup(&ss->xfr_timer, slotsim_xfr_timer_cb, cs);
|
|
cs->default_pars = &slotsim_def_pars;
|
|
return 0;
|
|
}
|
|
|
|
const struct ccid_slot_ops slotsim_slot_ops = {
|
|
.init = slotsim_init,
|
|
.pre_proc_cb = slotsim_pre_proc_cb,
|
|
.icc_power_on_async = slotsim_icc_power_on_async,
|
|
.xfr_block_async = slotsim_xfr_block_async,
|
|
.set_power = slotsim_set_power,
|
|
.set_clock = slotsim_set_clock,
|
|
.set_params = slotsim_set_params,
|
|
.set_rate_and_clock = slotsim_set_rate_and_clock,
|
|
};
|