blob: 870cf35efc8b04ceb2edba1c34106268723321bb [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"
16
17struct iso_fsm_slot {
18 /* CCID slot above us */
19 struct ccid_slot *cs;
20 /* main ISO7816-3 FSM instance beneath us */
21 struct osmo_fsm_inst *fi;
22 /* UART beneath the ISO7816-3 FSM */
23 struct card_uart *cuart;
24 /* bSeq of the operation currently in progress */
25 uint8_t seq;
26};
27
28struct iso_fsm_slot_instance {
29 struct iso_fsm_slot slot[NR_SLOTS];
30};
31
32static struct iso_fsm_slot_instance g_si;
33
Harald Welte03d6ebb2019-09-28 23:19:31 +020034static struct iso_fsm_slot *ccid_slot2iso_fsm_slot(struct ccid_slot *cs)
Harald Welte727d6752019-09-30 21:46:44 +020035{
36 OSMO_ASSERT(cs->slot_nr < ARRAY_SIZE(g_si.slot));
37 return &g_si.slot[cs->slot_nr];
38}
39
Harald Welte03d6ebb2019-09-28 23:19:31 +020040struct card_uart *cuart4slot_nr(uint8_t slot_nr)
41{
42 OSMO_ASSERT(slot_nr < ARRAY_SIZE(g_si.slot));
43 return g_si.slot[slot_nr].cuart;
44}
45
Harald Welte727d6752019-09-30 21:46:44 +020046static const uint8_t sysmousim_sjs1_atr[] = {
47 0x3B, 0x9F, 0x96, 0x80, 0x1F, 0xC7, 0x80, 0x31,
48 0xA0, 0x73, 0xBE, 0x21, 0x13, 0x67, 0x43, 0x20,
49 0x07, 0x18, 0x00, 0x00, 0x01, 0xA5 };
50
51static const struct ccid_pars_decoded iso_fsm_def_pars = {
52 .fi = 372,
53 .di = 1,
54 .clock_stop = CCID_CLOCK_STOP_NOTALLOWED,
55 .inverse_convention = false,
56 .t0 = {
57 .guard_time_etu = 0,
58 .waiting_integer = 0,
59 },
60 /* FIXME: T=1 */
61};
62
63static void iso_fsm_slot_pre_proc_cb(struct ccid_slot *cs, struct msgb *msg)
64{
65 /* do nothing; real hardware would update the slot related state here */
66}
67
68static void iso_fsm_slot_icc_power_on_async(struct ccid_slot *cs, struct msgb *msg,
69 const struct ccid_pc_to_rdr_icc_power_on *ipo)
70{
71 struct iso_fsm_slot *ss = ccid_slot2iso_fsm_slot(cs);
72
73 ss->seq = ipo->hdr.bSeq;
74 LOGPCS(cs, LOGL_DEBUG, "scheduling power-up\n");
75
76 /* FIXME: do this via a FSM? */
77 card_uart_ctrl(ss->cuart, CUART_CTL_RST, true);
Harald Weltef54a6b22019-10-10 13:30:24 +020078 osmo_fsm_inst_dispatch(ss->fi, ISO7816_E_RESET_ACT_IND, NULL);
Harald Welte727d6752019-09-30 21:46:44 +020079 card_uart_ctrl(ss->cuart, CUART_CTL_POWER, true);
80 osmo_fsm_inst_dispatch(ss->fi, ISO7816_E_POWER_UP_IND, NULL);
81 cs->icc_powered = true;
82 card_uart_ctrl(ss->cuart, CUART_CTL_CLOCK, true);
Harald Welte03d6ebb2019-09-28 23:19:31 +020083 delay_us(10000);
84
Harald Welte727d6752019-09-30 21:46:44 +020085 osmo_fsm_inst_dispatch(ss->fi, ISO7816_E_RESET_REL_IND, NULL);
Harald Welte03d6ebb2019-09-28 23:19:31 +020086 card_uart_ctrl(ss->cuart, CUART_CTL_RST, false);
Harald Welte727d6752019-09-30 21:46:44 +020087
88 msgb_free(msg);
89 /* continues in iso_fsm_clot_user_cb once ATR is received */
90}
91static void iso_fsm_clot_user_cb(struct osmo_fsm_inst *fi, int event, int cause, void *data)
92{
93 struct iso_fsm_slot *ss = iso7816_fsm_get_user_priv(fi);
94 struct ccid_slot *cs = ss->cs;
95 struct msgb *tpdu, *resp;
96
Harald Welte727d6752019-09-30 21:46:44 +020097 switch (event) {
98 case ISO7816_E_ATR_DONE_IND:
99 tpdu = data;
Harald Welte22dd1ff2019-10-10 15:40:53 +0200100 LOGPCS(cs, LOGL_DEBUG, "%s(event=%d, cause=%d, data=%s)\n", __func__, event, cause,
101 msgb_hexdump(tpdu));
Harald Welte727d6752019-09-30 21:46:44 +0200102 resp = ccid_gen_data_block(cs, ss->seq, CCID_CMD_STATUS_OK, 0,
103 msgb_data(tpdu), msgb_length(tpdu));
104 ccid_slot_send_unbusy(cs, resp);
Harald Weltebbb50092019-10-10 14:55:25 +0200105 /* Don't free "TPDU" here, as the ATR should survive */
Harald Welte727d6752019-09-30 21:46:44 +0200106 break;
107 case ISO7816_E_TPDU_DONE_IND:
108 tpdu = data;
Harald Welte22dd1ff2019-10-10 15:40:53 +0200109 LOGPCS(cs, LOGL_DEBUG, "%s(event=%d, cause=%d, data=%s)\n", __func__, event, cause,
110 msgb_hexdump(tpdu));
Harald Welte727d6752019-09-30 21:46:44 +0200111 resp = ccid_gen_data_block(cs, ss->seq, CCID_CMD_STATUS_OK, 0, msgb_l2(tpdu), msgb_l2len(tpdu));
112 ccid_slot_send_unbusy(cs, resp);
113 msgb_free(tpdu);
114 break;
Harald Welte22dd1ff2019-10-10 15:40:53 +0200115 default:
116 LOGPCS(cs, LOGL_NOTICE, "%s(event=%d, cause=%d, data=%p) unhandled\n",
117 __func__, event, cause, data);
118 break;
Harald Welte727d6752019-09-30 21:46:44 +0200119 }
120}
121
122static void iso_fsm_slot_xfr_block_async(struct ccid_slot *cs, struct msgb *msg,
123 const struct ccid_pc_to_rdr_xfr_block *xfb)
124{
125 struct iso_fsm_slot *ss = ccid_slot2iso_fsm_slot(cs);
Harald Welte6def1cf2019-10-10 15:40:02 +0200126 struct msgb *tpdu;
Harald Welte727d6752019-09-30 21:46:44 +0200127
Harald Welte727d6752019-09-30 21:46:44 +0200128 ss->seq = xfb->hdr.bSeq;
Harald Welte6def1cf2019-10-10 15:40:02 +0200129
130 /* must be '0' for TPDU level exchanges or for short APDU */
131 OSMO_ASSERT(xfb->wLevelParameter == 0x0000);
132 OSMO_ASSERT(msgb_length(msg) > xfb->hdr.dwLength);
133
134 /* 'msg' contains the raw CCID message as received from USB. We could create
135 * a new message buffer for the ISO7816 side here or we could 'strip the CCID
136 * header off the start of the message. Let's KISS and do a copy here */
137 tpdu = msgb_alloc(512, "TPDU");
138 OSMO_ASSERT(tpdu);
139 memcpy(msgb_data(tpdu), xfb->abData, xfb->hdr.dwLength);
140 msgb_put(tpdu, xfb->hdr.dwLength);
141 msgb_free(msg);
142
143 LOGPCS(cs, LOGL_DEBUG, "scheduling TPDU transfer: %s\n", msgb_hexdump(tpdu));
144 osmo_fsm_inst_dispatch(ss->fi, ISO7816_E_XCEIVE_TPDU_CMD, tpdu);
Harald Welte727d6752019-09-30 21:46:44 +0200145 /* continues in iso_fsm_clot_user_cb once response/error/timeout is received */
146}
147
148
149static void iso_fsm_slot_set_power(struct ccid_slot *cs, bool enable)
150{
151 struct iso_fsm_slot *ss = ccid_slot2iso_fsm_slot(cs);
152
153 if (enable) {
154 card_uart_ctrl(ss->cuart, CUART_CTL_POWER, true);
Harald Welte03d6ebb2019-09-28 23:19:31 +0200155 cs->icc_powered = true;
Harald Welte727d6752019-09-30 21:46:44 +0200156 } else {
157 card_uart_ctrl(ss->cuart, CUART_CTL_POWER, false);
Harald Welte03d6ebb2019-09-28 23:19:31 +0200158 cs->icc_powered = false;
Harald Welte727d6752019-09-30 21:46:44 +0200159 }
160}
161
162static void iso_fsm_slot_set_clock(struct ccid_slot *cs, enum ccid_clock_command cmd)
163{
164 struct iso_fsm_slot *ss = ccid_slot2iso_fsm_slot(cs);
165
166 switch (cmd) {
167 case CCID_CLOCK_CMD_STOP:
168 card_uart_ctrl(ss->cuart, CUART_CTL_CLOCK, false);
169 break;
170 case CCID_CLOCK_CMD_RESTART:
171 card_uart_ctrl(ss->cuart, CUART_CTL_CLOCK, true);
172 break;
173 default:
174 OSMO_ASSERT(0);
175 }
176}
177
178static int iso_fsm_slot_set_params(struct ccid_slot *cs, enum ccid_protocol_num proto,
179 const struct ccid_pars_decoded *pars_dec)
180{
181 /* we always acknowledge all parameters */
182 return 0;
183}
184
185static int iso_fsm_slot_set_rate_and_clock(struct ccid_slot *cs, uint32_t freq_hz, uint32_t rate_bps)
186{
187 /* we always acknowledge all rates/clocks */
188 return 0;
189}
190
Harald Welte03d6ebb2019-09-28 23:19:31 +0200191extern void *g_tall_ctx;
Harald Welte727d6752019-09-30 21:46:44 +0200192static int iso_fsm_slot_init(struct ccid_slot *cs)
193{
Harald Welte03d6ebb2019-09-28 23:19:31 +0200194 void *ctx = g_tall_ctx; /* FIXME */
Harald Welte727d6752019-09-30 21:46:44 +0200195 struct iso_fsm_slot *ss = ccid_slot2iso_fsm_slot(cs);
196 struct card_uart *cuart = talloc_zero(ctx, struct card_uart);
Harald Welte03d6ebb2019-09-28 23:19:31 +0200197 char id_buf[16] = "SIM0";
198 char devname[] = "foobar";
Harald Welte727d6752019-09-30 21:46:44 +0200199 int rc;
200
201 LOGPCS(cs, LOGL_DEBUG, "%s\n", __func__);
202
Harald Welte515d5b22019-10-10 13:46:13 +0200203 /* HACK: make this in some way configurable so it works both in the firmware
204 * and on the host (functionfs) */
Harald Welte03d6ebb2019-09-28 23:19:31 +0200205// if (cs->slot_nr == 0) {
206// cs->icc_present = true;
207// devname = "/dev/ttyUSB5";
208// }
209 devname[0] = cs->slot_nr +0x30;
210 devname[1] = 0;
211 //sprintf(devname, "%d", cs->slot_nr);
Harald Welte727d6752019-09-30 21:46:44 +0200212
213 if (!cuart)
214 return -ENOMEM;
215
Harald Welte03d6ebb2019-09-28 23:19:31 +0200216 //snprintf(id_buf, sizeof(id_buf), "SIM%d", cs->slot_nr);
217 id_buf[3] = cs->slot_nr +0x30;
Harald Welte515d5b22019-10-10 13:46:13 +0200218 if (devname) {
Harald Welte03d6ebb2019-09-28 23:19:31 +0200219 rc = card_uart_open(cuart, "asf4", devname);
Harald Welte515d5b22019-10-10 13:46:13 +0200220 if (rc < 0) {
221 LOGPCS(cs, LOGL_ERROR, "Cannot open UART %s: %d\n", devname, rc);
222 talloc_free(cuart);
223 return rc;
224 }
Harald Welte727d6752019-09-30 21:46:44 +0200225 }
226 ss->fi = iso7816_fsm_alloc(ctx, LOGL_DEBUG, id_buf, cuart, iso_fsm_clot_user_cb, ss);
227 if (!ss->fi) {
Harald Welte515d5b22019-10-10 13:46:13 +0200228 LOGPCS(cs, LOGL_ERROR, "Cannot allocate ISO FSM\n");
Harald Welte727d6752019-09-30 21:46:44 +0200229 talloc_free(cuart);
230 return -1;
231 }
232
233 cs->default_pars = &iso_fsm_def_pars;
234 ss->cuart = cuart;
235 ss->cs = cs;
236
237
238 return 0;
239}
240
241const struct ccid_slot_ops iso_fsm_slot_ops = {
242 .init = iso_fsm_slot_init,
243 .pre_proc_cb = iso_fsm_slot_pre_proc_cb,
244 .icc_power_on_async = iso_fsm_slot_icc_power_on_async,
245 .xfr_block_async = iso_fsm_slot_xfr_block_async,
246 .set_power = iso_fsm_slot_set_power,
247 .set_clock = iso_fsm_slot_set_clock,
248 .set_params = iso_fsm_slot_set_params,
249 .set_rate_and_clock = iso_fsm_slot_set_rate_and_clock,
250};