blob: 8bdcfd546bcbb3471462409b543aa4e079ecee7f [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>
Harald Welte6def1cf2019-10-10 15:40:02 +02006#include <string.h>
Harald Welte727d6752019-09-30 21:46:44 +02007
8#include <osmocom/core/msgb.h>
9#include <osmocom/core/timer.h>
10#include <osmocom/core/logging.h>
11#include <osmocom/core/fsm.h>
12
13#include "ccid_device.h"
14#include "cuart.h"
15#include "iso7816_fsm.h"
Eric Wildad1edce2019-11-27 16:51:08 +010016#include "iso7816_3.h"
Harald Welte727d6752019-09-30 21:46:44 +020017
18struct iso_fsm_slot {
19 /* CCID slot above us */
20 struct ccid_slot *cs;
21 /* main ISO7816-3 FSM instance beneath us */
22 struct osmo_fsm_inst *fi;
23 /* UART beneath the ISO7816-3 FSM */
24 struct card_uart *cuart;
25 /* bSeq of the operation currently in progress */
26 uint8_t seq;
27};
28
29struct iso_fsm_slot_instance {
30 struct iso_fsm_slot slot[NR_SLOTS];
31};
32
33static struct iso_fsm_slot_instance g_si;
34
Harald Welte03d6ebb2019-09-28 23:19:31 +020035static struct iso_fsm_slot *ccid_slot2iso_fsm_slot(struct ccid_slot *cs)
Harald Welte727d6752019-09-30 21:46:44 +020036{
37 OSMO_ASSERT(cs->slot_nr < ARRAY_SIZE(g_si.slot));
38 return &g_si.slot[cs->slot_nr];
39}
40
Harald Welte03d6ebb2019-09-28 23:19:31 +020041struct card_uart *cuart4slot_nr(uint8_t slot_nr)
42{
43 OSMO_ASSERT(slot_nr < ARRAY_SIZE(g_si.slot));
44 return g_si.slot[slot_nr].cuart;
45}
46
Harald Welte727d6752019-09-30 21:46:44 +020047static const uint8_t sysmousim_sjs1_atr[] = {
48 0x3B, 0x9F, 0x96, 0x80, 0x1F, 0xC7, 0x80, 0x31,
49 0xA0, 0x73, 0xBE, 0x21, 0x13, 0x67, 0x43, 0x20,
50 0x07, 0x18, 0x00, 0x00, 0x01, 0xA5 };
51
52static const struct ccid_pars_decoded iso_fsm_def_pars = {
53 .fi = 372,
54 .di = 1,
55 .clock_stop = CCID_CLOCK_STOP_NOTALLOWED,
56 .inverse_convention = false,
57 .t0 = {
58 .guard_time_etu = 0,
59 .waiting_integer = 0,
60 },
61 /* FIXME: T=1 */
62};
63
64static void iso_fsm_slot_pre_proc_cb(struct ccid_slot *cs, struct msgb *msg)
65{
66 /* do nothing; real hardware would update the slot related state here */
67}
68
69static void iso_fsm_slot_icc_power_on_async(struct ccid_slot *cs, struct msgb *msg,
70 const struct ccid_pc_to_rdr_icc_power_on *ipo)
71{
72 struct iso_fsm_slot *ss = ccid_slot2iso_fsm_slot(cs);
73
74 ss->seq = ipo->hdr.bSeq;
75 LOGPCS(cs, LOGL_DEBUG, "scheduling power-up\n");
76
77 /* FIXME: do this via a FSM? */
78 card_uart_ctrl(ss->cuart, CUART_CTL_RST, true);
Harald Weltef54a6b22019-10-10 13:30:24 +020079 osmo_fsm_inst_dispatch(ss->fi, ISO7816_E_RESET_ACT_IND, NULL);
Harald Welte727d6752019-09-30 21:46:44 +020080 card_uart_ctrl(ss->cuart, CUART_CTL_POWER, true);
81 osmo_fsm_inst_dispatch(ss->fi, ISO7816_E_POWER_UP_IND, NULL);
82 cs->icc_powered = true;
83 card_uart_ctrl(ss->cuart, CUART_CTL_CLOCK, true);
Harald Welte03d6ebb2019-09-28 23:19:31 +020084 delay_us(10000);
85
Harald Welte727d6752019-09-30 21:46:44 +020086 osmo_fsm_inst_dispatch(ss->fi, ISO7816_E_RESET_REL_IND, NULL);
Harald Welte03d6ebb2019-09-28 23:19:31 +020087 card_uart_ctrl(ss->cuart, CUART_CTL_RST, false);
Harald Welte727d6752019-09-30 21:46:44 +020088
89 msgb_free(msg);
90 /* continues in iso_fsm_clot_user_cb once ATR is received */
91}
92static void iso_fsm_clot_user_cb(struct osmo_fsm_inst *fi, int event, int cause, void *data)
93{
94 struct iso_fsm_slot *ss = iso7816_fsm_get_user_priv(fi);
95 struct ccid_slot *cs = ss->cs;
96 struct msgb *tpdu, *resp;
97
Harald Welte727d6752019-09-30 21:46:44 +020098 switch (event) {
99 case ISO7816_E_ATR_DONE_IND:
100 tpdu = data;
Harald Welte22dd1ff2019-10-10 15:40:53 +0200101 LOGPCS(cs, LOGL_DEBUG, "%s(event=%d, cause=%d, data=%s)\n", __func__, event, cause,
102 msgb_hexdump(tpdu));
Harald Welte727d6752019-09-30 21:46:44 +0200103 resp = ccid_gen_data_block(cs, ss->seq, CCID_CMD_STATUS_OK, 0,
104 msgb_data(tpdu), msgb_length(tpdu));
105 ccid_slot_send_unbusy(cs, resp);
Harald Weltebbb50092019-10-10 14:55:25 +0200106 /* Don't free "TPDU" here, as the ATR should survive */
Harald Welte727d6752019-09-30 21:46:44 +0200107 break;
108 case ISO7816_E_TPDU_DONE_IND:
109 tpdu = data;
Harald Welte22dd1ff2019-10-10 15:40:53 +0200110 LOGPCS(cs, LOGL_DEBUG, "%s(event=%d, cause=%d, data=%s)\n", __func__, event, cause,
111 msgb_hexdump(tpdu));
Harald Welte727d6752019-09-30 21:46:44 +0200112 resp = ccid_gen_data_block(cs, ss->seq, CCID_CMD_STATUS_OK, 0, msgb_l2(tpdu), msgb_l2len(tpdu));
113 ccid_slot_send_unbusy(cs, resp);
114 msgb_free(tpdu);
115 break;
Eric Wildad1edce2019-11-27 16:51:08 +0100116 case ISO7816_E_PPS_DONE_IND:
117 tpdu = data;
118 /* pps was successful, so we know these values are fine */
119 uint16_t F = iso7816_3_fi_table[cs->proposed_pars.fi];
120 uint8_t D = iso7816_3_di_table[cs->proposed_pars.di];
121 uint32_t fmax = iso7816_3_fmax_table[cs->proposed_pars.fi];
122
123 card_uart_ctrl(ss->cuart, CUART_CTL_CLOCK_FREQ, fmax);
124 card_uart_ctrl(ss->cuart, CUART_CTL_FD, F/D);
125 card_uart_ctrl(ss->cuart, CUART_CTL_WTIME, cs->proposed_pars.t0.waiting_integer);
126
127 cs->pars = cs->proposed_pars;
128 resp = ccid_gen_parameters_t0(cs, ss->seq, CCID_CMD_STATUS_OK, 0);
129
130 ccid_slot_send_unbusy(cs, resp);
131
132 /* this frees the pps req from the host, pps resp buffer stays with the pps fsm */
133 msgb_free(tpdu);
134 break;
135 case ISO7816_E_PPS_FAILED_IND:
136 tpdu = data;
137 /* failed fi/di */
138 resp = ccid_gen_parameters_t0(cs, ss->seq, CCID_CMD_STATUS_FAILED, 10);
139 ccid_slot_send_unbusy(cs, resp);
140 /* this frees the pps req from the host, pps resp buffer stays with the pps fsm */
141 msgb_free(tpdu);
142 break;
Harald Welte22dd1ff2019-10-10 15:40:53 +0200143 default:
144 LOGPCS(cs, LOGL_NOTICE, "%s(event=%d, cause=%d, data=%p) unhandled\n",
145 __func__, event, cause, data);
146 break;
Harald Welte727d6752019-09-30 21:46:44 +0200147 }
148}
149
150static void iso_fsm_slot_xfr_block_async(struct ccid_slot *cs, struct msgb *msg,
151 const struct ccid_pc_to_rdr_xfr_block *xfb)
152{
153 struct iso_fsm_slot *ss = ccid_slot2iso_fsm_slot(cs);
Harald Welte6def1cf2019-10-10 15:40:02 +0200154 struct msgb *tpdu;
Harald Welte727d6752019-09-30 21:46:44 +0200155
Harald Welte727d6752019-09-30 21:46:44 +0200156 ss->seq = xfb->hdr.bSeq;
Harald Welte6def1cf2019-10-10 15:40:02 +0200157
158 /* must be '0' for TPDU level exchanges or for short APDU */
159 OSMO_ASSERT(xfb->wLevelParameter == 0x0000);
160 OSMO_ASSERT(msgb_length(msg) > xfb->hdr.dwLength);
161
162 /* 'msg' contains the raw CCID message as received from USB. We could create
163 * a new message buffer for the ISO7816 side here or we could 'strip the CCID
164 * header off the start of the message. Let's KISS and do a copy here */
165 tpdu = msgb_alloc(512, "TPDU");
166 OSMO_ASSERT(tpdu);
167 memcpy(msgb_data(tpdu), xfb->abData, xfb->hdr.dwLength);
168 msgb_put(tpdu, xfb->hdr.dwLength);
169 msgb_free(msg);
170
171 LOGPCS(cs, LOGL_DEBUG, "scheduling TPDU transfer: %s\n", msgb_hexdump(tpdu));
172 osmo_fsm_inst_dispatch(ss->fi, ISO7816_E_XCEIVE_TPDU_CMD, tpdu);
Harald Welte727d6752019-09-30 21:46:44 +0200173 /* continues in iso_fsm_clot_user_cb once response/error/timeout is received */
174}
175
176
177static void iso_fsm_slot_set_power(struct ccid_slot *cs, bool enable)
178{
179 struct iso_fsm_slot *ss = ccid_slot2iso_fsm_slot(cs);
180
181 if (enable) {
182 card_uart_ctrl(ss->cuart, CUART_CTL_POWER, true);
Harald Welte03d6ebb2019-09-28 23:19:31 +0200183 cs->icc_powered = true;
Harald Welte727d6752019-09-30 21:46:44 +0200184 } else {
185 card_uart_ctrl(ss->cuart, CUART_CTL_POWER, false);
Harald Welte03d6ebb2019-09-28 23:19:31 +0200186 cs->icc_powered = false;
Harald Welte727d6752019-09-30 21:46:44 +0200187 }
188}
189
190static void iso_fsm_slot_set_clock(struct ccid_slot *cs, enum ccid_clock_command cmd)
191{
192 struct iso_fsm_slot *ss = ccid_slot2iso_fsm_slot(cs);
193
194 switch (cmd) {
195 case CCID_CLOCK_CMD_STOP:
196 card_uart_ctrl(ss->cuart, CUART_CTL_CLOCK, false);
197 break;
198 case CCID_CLOCK_CMD_RESTART:
199 card_uart_ctrl(ss->cuart, CUART_CTL_CLOCK, true);
200 break;
201 default:
202 OSMO_ASSERT(0);
203 }
204}
205
Eric Wildad1edce2019-11-27 16:51:08 +0100206static int iso_fsm_slot_set_params(struct ccid_slot *cs, uint8_t seq, enum ccid_protocol_num proto,
Harald Welte727d6752019-09-30 21:46:44 +0200207 const struct ccid_pars_decoded *pars_dec)
208{
Eric Wildad1edce2019-11-27 16:51:08 +0100209 struct iso_fsm_slot *ss = ccid_slot2iso_fsm_slot(cs);
210 struct msgb *tpdu;
211
212 /* see 6.1.7 for error offsets */
213 if(proto != CCID_PROTOCOL_NUM_T0)
214 return -7;
215
216 if(pars_dec->t0.guard_time_etu != 0)
217 return -12;
218
219 if(pars_dec->clock_stop != CCID_CLOCK_STOP_NOTALLOWED)
220 return -14;
221
222 ss->seq = seq;
223
224 /* Hardware does not support SPU, so no PPS2, and PPS3 is reserved anyway */
225 tpdu = msgb_alloc(6, "PPSRQ");
226 OSMO_ASSERT(tpdu);
227 msgb_put_u8(tpdu, 0xff);
228 msgb_put_u8(tpdu, (1 << 4)); /* only PPS1, T=0 */
229 msgb_put_u8(tpdu, (pars_dec->fi << 4 | pars_dec->di));
230 msgb_put_u8(tpdu, 0xff ^ (1 << 4) ^ (pars_dec->fi << 4 | pars_dec->di));
231
232
233 LOGPCS(cs, LOGL_DEBUG, "scheduling PPS transfer: %s\n", msgb_hexdump(tpdu));
234 osmo_fsm_inst_dispatch(ss->fi, ISO7816_E_XCEIVE_PPS_CMD, tpdu);
235 /* continues in iso_fsm_clot_user_cb once response/error/timeout is received */
Harald Welte727d6752019-09-30 21:46:44 +0200236 return 0;
237}
238
239static int iso_fsm_slot_set_rate_and_clock(struct ccid_slot *cs, uint32_t freq_hz, uint32_t rate_bps)
240{
241 /* we always acknowledge all rates/clocks */
242 return 0;
243}
244
Harald Welte03d6ebb2019-09-28 23:19:31 +0200245extern void *g_tall_ctx;
Harald Welte727d6752019-09-30 21:46:44 +0200246static int iso_fsm_slot_init(struct ccid_slot *cs)
247{
Harald Welte03d6ebb2019-09-28 23:19:31 +0200248 void *ctx = g_tall_ctx; /* FIXME */
Harald Welte727d6752019-09-30 21:46:44 +0200249 struct iso_fsm_slot *ss = ccid_slot2iso_fsm_slot(cs);
250 struct card_uart *cuart = talloc_zero(ctx, struct card_uart);
Harald Welte03d6ebb2019-09-28 23:19:31 +0200251 char id_buf[16] = "SIM0";
252 char devname[] = "foobar";
Harald Welte727d6752019-09-30 21:46:44 +0200253 int rc;
254
255 LOGPCS(cs, LOGL_DEBUG, "%s\n", __func__);
256
Harald Welte515d5b22019-10-10 13:46:13 +0200257 /* HACK: make this in some way configurable so it works both in the firmware
258 * and on the host (functionfs) */
Harald Welte03d6ebb2019-09-28 23:19:31 +0200259// if (cs->slot_nr == 0) {
260// cs->icc_present = true;
261// devname = "/dev/ttyUSB5";
262// }
263 devname[0] = cs->slot_nr +0x30;
264 devname[1] = 0;
265 //sprintf(devname, "%d", cs->slot_nr);
Harald Welte727d6752019-09-30 21:46:44 +0200266
267 if (!cuart)
268 return -ENOMEM;
269
Harald Welte03d6ebb2019-09-28 23:19:31 +0200270 //snprintf(id_buf, sizeof(id_buf), "SIM%d", cs->slot_nr);
271 id_buf[3] = cs->slot_nr +0x30;
Harald Welte515d5b22019-10-10 13:46:13 +0200272 if (devname) {
Harald Welte03d6ebb2019-09-28 23:19:31 +0200273 rc = card_uart_open(cuart, "asf4", devname);
Harald Welte515d5b22019-10-10 13:46:13 +0200274 if (rc < 0) {
275 LOGPCS(cs, LOGL_ERROR, "Cannot open UART %s: %d\n", devname, rc);
276 talloc_free(cuart);
277 return rc;
278 }
Harald Welte727d6752019-09-30 21:46:44 +0200279 }
280 ss->fi = iso7816_fsm_alloc(ctx, LOGL_DEBUG, id_buf, cuart, iso_fsm_clot_user_cb, ss);
281 if (!ss->fi) {
Harald Welte515d5b22019-10-10 13:46:13 +0200282 LOGPCS(cs, LOGL_ERROR, "Cannot allocate ISO FSM\n");
Harald Welte727d6752019-09-30 21:46:44 +0200283 talloc_free(cuart);
284 return -1;
285 }
286
287 cs->default_pars = &iso_fsm_def_pars;
288 ss->cuart = cuart;
289 ss->cs = cs;
290
291
292 return 0;
293}
294
295const struct ccid_slot_ops iso_fsm_slot_ops = {
296 .init = iso_fsm_slot_init,
297 .pre_proc_cb = iso_fsm_slot_pre_proc_cb,
298 .icc_power_on_async = iso_fsm_slot_icc_power_on_async,
299 .xfr_block_async = iso_fsm_slot_xfr_block_async,
300 .set_power = iso_fsm_slot_set_power,
301 .set_clock = iso_fsm_slot_set_clock,
302 .set_params = iso_fsm_slot_set_params,
303 .set_rate_and_clock = iso_fsm_slot_set_rate_and_clock,
304};