blob: fe7cf9978240479b12cd4763d9a2206518384fff [file] [log] [blame]
Harald Welte727d6752019-09-30 21:46:44 +02001/* Code providing a ccid_slot_ops implementation based on iso7716_fsm,
2 * (which in turn sits on top of card_uart) */
3
4#include <unistd.h>
5#include <errno.h>
6
7#include <osmocom/core/msgb.h>
8#include <osmocom/core/timer.h>
9#include <osmocom/core/logging.h>
10#include <osmocom/core/fsm.h>
11
12#include "ccid_device.h"
13#include "cuart.h"
14#include "iso7816_fsm.h"
15
16struct iso_fsm_slot {
17 /* CCID slot above us */
18 struct ccid_slot *cs;
19 /* main ISO7816-3 FSM instance beneath us */
20 struct osmo_fsm_inst *fi;
21 /* UART beneath the ISO7816-3 FSM */
22 struct card_uart *cuart;
23 /* bSeq of the operation currently in progress */
24 uint8_t seq;
25};
26
27struct iso_fsm_slot_instance {
28 struct iso_fsm_slot slot[NR_SLOTS];
29};
30
31static struct iso_fsm_slot_instance g_si;
32
Harald Welte4aab33f2019-09-28 23:19:31 +020033static struct iso_fsm_slot *ccid_slot2iso_fsm_slot(struct ccid_slot *cs)
Harald Welte727d6752019-09-30 21:46:44 +020034{
35 OSMO_ASSERT(cs->slot_nr < ARRAY_SIZE(g_si.slot));
36 return &g_si.slot[cs->slot_nr];
37}
38
Harald Welte4aab33f2019-09-28 23:19:31 +020039struct card_uart *cuart4slot_nr(uint8_t slot_nr)
40{
41 OSMO_ASSERT(slot_nr < ARRAY_SIZE(g_si.slot));
42 return g_si.slot[slot_nr].cuart;
43}
44
Harald Welte727d6752019-09-30 21:46:44 +020045static const uint8_t sysmousim_sjs1_atr[] = {
46 0x3B, 0x9F, 0x96, 0x80, 0x1F, 0xC7, 0x80, 0x31,
47 0xA0, 0x73, 0xBE, 0x21, 0x13, 0x67, 0x43, 0x20,
48 0x07, 0x18, 0x00, 0x00, 0x01, 0xA5 };
49
50static const struct ccid_pars_decoded iso_fsm_def_pars = {
51 .fi = 372,
52 .di = 1,
53 .clock_stop = CCID_CLOCK_STOP_NOTALLOWED,
54 .inverse_convention = false,
55 .t0 = {
56 .guard_time_etu = 0,
57 .waiting_integer = 0,
58 },
59 /* FIXME: T=1 */
60};
61
62static void iso_fsm_slot_pre_proc_cb(struct ccid_slot *cs, struct msgb *msg)
63{
64 /* do nothing; real hardware would update the slot related state here */
65}
66
67static void iso_fsm_slot_icc_power_on_async(struct ccid_slot *cs, struct msgb *msg,
68 const struct ccid_pc_to_rdr_icc_power_on *ipo)
69{
70 struct iso_fsm_slot *ss = ccid_slot2iso_fsm_slot(cs);
71
72 ss->seq = ipo->hdr.bSeq;
73 LOGPCS(cs, LOGL_DEBUG, "scheduling power-up\n");
74
75 /* FIXME: do this via a FSM? */
76 card_uart_ctrl(ss->cuart, CUART_CTL_RST, true);
Harald Welte742163a2019-10-10 13:30:24 +020077 osmo_fsm_inst_dispatch(ss->fi, ISO7816_E_RESET_ACT_IND, NULL);
Harald Welte727d6752019-09-30 21:46:44 +020078 card_uart_ctrl(ss->cuart, CUART_CTL_POWER, true);
79 osmo_fsm_inst_dispatch(ss->fi, ISO7816_E_POWER_UP_IND, NULL);
80 cs->icc_powered = true;
81 card_uart_ctrl(ss->cuart, CUART_CTL_CLOCK, true);
82 usleep(10000);
83 card_uart_ctrl(ss->cuart, CUART_CTL_RST, false);
84 osmo_fsm_inst_dispatch(ss->fi, ISO7816_E_RESET_REL_IND, NULL);
85
86 msgb_free(msg);
87 /* continues in iso_fsm_clot_user_cb once ATR is received */
88}
89static void iso_fsm_clot_user_cb(struct osmo_fsm_inst *fi, int event, int cause, void *data)
90{
91 struct iso_fsm_slot *ss = iso7816_fsm_get_user_priv(fi);
92 struct ccid_slot *cs = ss->cs;
93 struct msgb *tpdu, *resp;
94
95 LOGPCS(cs, LOGL_DEBUG, "%s(event=%d, cause=%d, data=%p)\n", __func__, event, cause, data);
96
97 switch (event) {
98 case ISO7816_E_ATR_DONE_IND:
99 tpdu = data;
100 /* FIXME: copy response data over */
101 resp = ccid_gen_data_block(cs, ss->seq, CCID_CMD_STATUS_OK, 0,
102 msgb_data(tpdu), msgb_length(tpdu));
103 ccid_slot_send_unbusy(cs, resp);
104 msgb_free(tpdu);
105 break;
106 case ISO7816_E_TPDU_DONE_IND:
107 tpdu = data;
108 /* FIXME: copy response data over */
109 resp = ccid_gen_data_block(cs, ss->seq, CCID_CMD_STATUS_OK, 0, msgb_l2(tpdu), msgb_l2len(tpdu));
110 ccid_slot_send_unbusy(cs, resp);
111 msgb_free(tpdu);
112 break;
113 }
114}
115
116static void iso_fsm_slot_xfr_block_async(struct ccid_slot *cs, struct msgb *msg,
117 const struct ccid_pc_to_rdr_xfr_block *xfb)
118{
119 struct iso_fsm_slot *ss = ccid_slot2iso_fsm_slot(cs);
120
121 LOGPCS(cs, LOGL_DEBUG, "scheduling TPDU transfer\n");
122 ss->seq = xfb->hdr.bSeq;
123 osmo_fsm_inst_dispatch(ss->fi, ISO7816_E_XCEIVE_TPDU_CMD, msg);
124 /* continues in iso_fsm_clot_user_cb once response/error/timeout is received */
125}
126
127
128static void iso_fsm_slot_set_power(struct ccid_slot *cs, bool enable)
129{
130 struct iso_fsm_slot *ss = ccid_slot2iso_fsm_slot(cs);
131
132 if (enable) {
133 card_uart_ctrl(ss->cuart, CUART_CTL_POWER, true);
134 } else {
135 card_uart_ctrl(ss->cuart, CUART_CTL_POWER, false);
136 }
137}
138
139static void iso_fsm_slot_set_clock(struct ccid_slot *cs, enum ccid_clock_command cmd)
140{
141 struct iso_fsm_slot *ss = ccid_slot2iso_fsm_slot(cs);
142
143 switch (cmd) {
144 case CCID_CLOCK_CMD_STOP:
145 card_uart_ctrl(ss->cuart, CUART_CTL_CLOCK, false);
146 break;
147 case CCID_CLOCK_CMD_RESTART:
148 card_uart_ctrl(ss->cuart, CUART_CTL_CLOCK, true);
149 break;
150 default:
151 OSMO_ASSERT(0);
152 }
153}
154
155static int iso_fsm_slot_set_params(struct ccid_slot *cs, enum ccid_protocol_num proto,
156 const struct ccid_pars_decoded *pars_dec)
157{
158 /* we always acknowledge all parameters */
159 return 0;
160}
161
162static int iso_fsm_slot_set_rate_and_clock(struct ccid_slot *cs, uint32_t freq_hz, uint32_t rate_bps)
163{
164 /* we always acknowledge all rates/clocks */
165 return 0;
166}
167
168
169static int iso_fsm_slot_init(struct ccid_slot *cs)
170{
171 void *ctx = NULL; /* FIXME */
172 struct iso_fsm_slot *ss = ccid_slot2iso_fsm_slot(cs);
173 struct card_uart *cuart = talloc_zero(ctx, struct card_uart);
174 char id_buf[16];
Harald Welte5835f382019-10-10 13:46:13 +0200175 char *devname = NULL;
Harald Welte727d6752019-09-30 21:46:44 +0200176 int rc;
177
178 LOGPCS(cs, LOGL_DEBUG, "%s\n", __func__);
179
Harald Welte5835f382019-10-10 13:46:13 +0200180 /* HACK: make this in some way configurable so it works both in the firmware
181 * and on the host (functionfs) */
Harald Welte727d6752019-09-30 21:46:44 +0200182 if (cs->slot_nr == 0) {
183 cs->icc_present = true;
184 devname = "/dev/ttyUSB5";
185 }
186
187 if (!cuart)
188 return -ENOMEM;
189
190 snprintf(id_buf, sizeof(id_buf), "SIM%d", cs->slot_nr);
Harald Welte5835f382019-10-10 13:46:13 +0200191 if (devname) {
192 rc = card_uart_open(cuart, "tty", devname);
193 if (rc < 0) {
194 LOGPCS(cs, LOGL_ERROR, "Cannot open UART %s: %d\n", devname, rc);
195 talloc_free(cuart);
196 return rc;
197 }
Harald Welte727d6752019-09-30 21:46:44 +0200198 }
199 ss->fi = iso7816_fsm_alloc(ctx, LOGL_DEBUG, id_buf, cuart, iso_fsm_clot_user_cb, ss);
200 if (!ss->fi) {
Harald Welte5835f382019-10-10 13:46:13 +0200201 LOGPCS(cs, LOGL_ERROR, "Cannot allocate ISO FSM\n");
Harald Welte727d6752019-09-30 21:46:44 +0200202 talloc_free(cuart);
203 return -1;
204 }
205
206 cs->default_pars = &iso_fsm_def_pars;
207 ss->cuart = cuart;
208 ss->cs = cs;
209
210
211 return 0;
212}
213
214const struct ccid_slot_ops iso_fsm_slot_ops = {
215 .init = iso_fsm_slot_init,
216 .pre_proc_cb = iso_fsm_slot_pre_proc_cb,
217 .icc_power_on_async = iso_fsm_slot_icc_power_on_async,
218 .xfr_block_async = iso_fsm_slot_xfr_block_async,
219 .set_power = iso_fsm_slot_set_power,
220 .set_clock = iso_fsm_slot_set_clock,
221 .set_params = iso_fsm_slot_set_params,
222 .set_rate_and_clock = iso_fsm_slot_set_rate_and_clock,
223};