blob: beda7ab04377f23e814c8cda916057dae3d284c3 [file] [log] [blame]
Harald Welte06348362019-05-19 00:45:17 +02001/* ISO 7816-3 Finite State Machine (reader side)
2 *
3 * (C) 2019 by Harald Welte <laforge@gnumonks.org>
4 *
5 * inspired by earlier work
6 * (C) 2016-2017 by Harald Welte <hwelte@hmw-consulting.de>
7 * (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
22 */
23
24#include <string.h>
25
26#include <osmocom/core/utils.h>
27#include <osmocom/core/msgb.h>
28#include <osmocom/core/fsm.h>
29#include <osmocom/core/logging.h>
30#include <osmocom/sim/sim.h>
31
32#include "logging.h"
33#include "cuart.h"
34#include "iso7816_fsm.h"
35
36/* Section 8.2: the Answer-to-Reset (... a string of at most 32 bytes) */
37#define MAX_ATR_SIZE 32
38
39#define S(x) (1 << (x))
40
41/*! ISO 7816-3 states */
42enum iso7816_3_state {
43 ISO7816_S_RESET, /*!< in Reset */
44 ISO7816_S_WAIT_ATR, /*!< waiting for ATR to start */
45 ISO7816_S_IN_ATR, /*!< while we are receiving the ATR */
46 ISO7816_S_WAIT_TPDU, /*!< waiting for start of new TPDU */
47 ISO7816_S_IN_TPDU, /*!< inside a single TPDU */
48 ISO7816_S_IN_PPS_REQ, /*!< while we are inside the PPS request */
49 ISO7816_S_WAIT_PPS_RSP, /*!< waiting for start of the PPS response */
50 ISO7816_S_IN_PPS_RSP, /*!< while we are inside the PPS request */
51};
52
53/*! Answer-To-Reset (ATR) sub-states of ISO7816_S_IN_ATR
54 * @note defined in ISO/IEC 7816-3:2006(E) section 8
55 */
56enum atr_state {
57 ATR_S_WAIT_TS, /*!< initial byte */
58 ATR_S_WAIT_T0, /*!< format byte */
59 ATR_S_WAIT_TA, /*!< first sub-group interface byte */
60 ATR_S_WAIT_TB, /*!< second sub-group interface byte */
61 ATR_S_WAIT_TC, /*!< third sub-group interface byte */
62 ATR_S_WAIT_TD, /*!< fourth sub-group interface byte */
63 ATR_S_WAIT_HIST, /*!< historical byte */
64 ATR_S_WAIT_TCK, /*!< check byte */
65 ATR_S_DONE
66};
67
68/*! Protocol and Parameters Selection (PPS) sub-states of ISO7816_S_IN_PTS_REQ/ISO7816_S_IN_PTS_RSP
69 * @note defined in ISO/IEC 7816-3:2006(E) section 9
70 */
71enum pps_state {
72 PPS_S_WAIT_PPSS, /*!< initial byte */
73 PPS_S_WAIT_PPS0, /*!< format byte */
74 PPS_S_WAIT_PPS1, /*!< first parameter byte */
75 PPS_S_WAIT_PPS2, /*!< second parameter byte */
76 PPS_S_WAIT_PPS3, /*!< third parameter byte */
77 PPS_S_WAIT_PCK, /*!< check byte */
78 PPS_S_WAIT_END, /*!< all done */
79 PPS_S_DONE
80};
81
82/*! Transport Protocol Data Unit (TPDU) sub-states of ISO7816_S_IN_TPDU
83 * @note defined in ISO/IEC 7816-3:2006(E) section 10 and 12
84 * @remark APDUs are formed by one or more command+response TPDUs
85 */
86enum tpdu_state {
87 TPDU_S_INIT, /*!< initial state */
88 TPDU_S_TX_HDR, /*!< transmitting hdr, waiting for completion */
89 TPDU_S_PROCEDURE, /*!< procedure byte (could also be SW1) */
90 TPDU_S_TX_REMAINING, /*!< Tx remaining data bytes */
91 TPDU_S_TX_SINGLE, /*!< Tx single data byte */
92 TPDU_S_RX_REMAINING, /*!< Rx remaining data bytes */
93 TPDU_S_RX_SINGLE, /*!< Rx single data byte */
94 TPDU_S_SW1, /*!< first status word */
95 TPDU_S_SW2, /*!< second status word */
96 TPDU_S_DONE,
97};
98
99/* FSM timer enumeration */
100enum iso7816_3_timer {
101 T_WAIT_ATR = 1,
102 T_GUARD,
103};
104
105/* forward declarations */
106static struct osmo_fsm iso7816_3_fsm;
107static struct osmo_fsm atr_fsm;
108static struct osmo_fsm tpdu_fsm;
109static struct osmo_fsm pps_fsm;
110
111/* look-up table for bit-wise inversion to convert from "inverse convention" to normal */
112static const uint8_t convention_convert_lut[256] = {
113 0xff, 0x7f, 0xbf, 0x3f, 0xdf, 0x5f, 0x9f, 0x1f, 0xef, 0x6f, 0xaf, 0x2f, 0xcf, 0x4f, 0x8f, 0x0f,
114 0xf7, 0x77, 0xb7, 0x37, 0xd7, 0x57, 0x97, 0x17, 0xe7, 0x67, 0xa7, 0x27, 0xc7, 0x47, 0x87, 0x07,
115 0xfb, 0x7b, 0xbb, 0x3b, 0xdb, 0x5b, 0x9b, 0x1b, 0xeb, 0x6b, 0xab, 0x2b, 0xcb, 0x4b, 0x8b, 0x0b,
116 0xf3, 0x73, 0xb3, 0x33, 0xd3, 0x53, 0x93, 0x13, 0xe3, 0x63, 0xa3, 0x23, 0xc3, 0x43, 0x83, 0x03,
117 0xfd, 0x7d, 0xbd, 0x3d, 0xdd, 0x5d, 0x9d, 0x1d, 0xed, 0x6d, 0xad, 0x2d, 0xcd, 0x4d, 0x8d, 0x0d,
118 0xf5, 0x75, 0xb5, 0x35, 0xd5, 0x55, 0x95, 0x15, 0xe5, 0x65, 0xa5, 0x25, 0xc5, 0x45, 0x85, 0x05,
119 0xf9, 0x79, 0xb9, 0x39, 0xd9, 0x59, 0x99, 0x19, 0xe9, 0x69, 0xa9, 0x29, 0xc9, 0x49, 0x89, 0x09,
120 0xf1, 0x71, 0xb1, 0x31, 0xd1, 0x51, 0x91, 0x11, 0xe1, 0x61, 0xa1, 0x21, 0xc1, 0x41, 0x81, 0x01,
121 0xfe, 0x7e, 0xbe, 0x3e, 0xde, 0x5e, 0x9e, 0x1e, 0xee, 0x6e, 0xae, 0x2e, 0xce, 0x4e, 0x8e, 0x0e,
122 0xf6, 0x76, 0xb6, 0x36, 0xd6, 0x56, 0x96, 0x16, 0xe6, 0x66, 0xa6, 0x26, 0xc6, 0x46, 0x86, 0x06,
123 0xfa, 0x7a, 0xba, 0x3a, 0xda, 0x5a, 0x9a, 0x1a, 0xea, 0x6a, 0xaa, 0x2a, 0xca, 0x4a, 0x8a, 0x0a,
124 0xf2, 0x72, 0xb2, 0x32, 0xd2, 0x52, 0x92, 0x12, 0xe2, 0x62, 0xa2, 0x22, 0xc2, 0x42, 0x82, 0x02,
125 0xfc, 0x7c, 0xbc, 0x3c, 0xdc, 0x5c, 0x9c, 0x1c, 0xec, 0x6c, 0xac, 0x2c, 0xcc, 0x4c, 0x8c, 0x0c,
126 0xf4, 0x74, 0xb4, 0x34, 0xd4, 0x54, 0x94, 0x14, 0xe4, 0x64, 0xa4, 0x24, 0xc4, 0x44, 0x84, 0x04,
127 0xf8, 0x78, 0xb8, 0x38, 0xd8, 0x58, 0x98, 0x18, 0xe8, 0x68, 0xa8, 0x28, 0xc8, 0x48, 0x88, 0x08,
128 0xf0, 0x70, 0xb0, 0x30, 0xd0, 0x50, 0x90, 0x10, 0xe0, 0x60, 0xa0, 0x20, 0xc0, 0x40, 0x80, 0x00,
129};
130
131/***********************************************************************
132 * ISO7816-3 Main FSM
133 ***********************************************************************/
134
135static const struct value_string iso7816_3_event_names[] = {
136 { ISO7816_E_RX_SINGLE, "UART_RX_SINGLE" },
137 { ISO7816_E_RX_COMPL, "UART_RX_COMPL" },
138 { ISO7816_E_TX_COMPL, "UART_TX_COMPL" },
139 { ISO7816_E_POWER_UP_IND, "POWER_UP_IND" },
140 { ISO7816_E_RESET_REL_IND, "RESET_REL_IND" },
141 { ISO7816_E_RX_ERR_IND, "RX_ERR_IND" },
142 { ISO7816_E_TX_ERR_IND, "TX_ERR_IND" },
143 { ISO7816_E_ATR_DONE_IND, "ATR_DONE_IND" },
Harald Welte1ac9ef92019-10-09 22:20:16 +0200144 { ISO7816_E_ATR_ERR_IND, "ATR_ERR_IND" },
Harald Welte06348362019-05-19 00:45:17 +0200145 { ISO7816_E_TPDU_DONE_IND, "TPDU_DONE_IND" },
146 { ISO7816_E_XCEIVE_TPDU_CMD, "XCEIVE_TPDU_CMD" },
147 /* allstate events */
148 { ISO7816_E_WTIME_EXP, "WAIT_TIME_EXP" },
149 { ISO7816_E_HW_ERR_IND, "HW_ERR_IND" },
150 { ISO7816_E_SW_ERR_IND, "SW_ERR_IND" },
151 { ISO7816_E_CARD_REMOVAL, "CARD_REMOVAL" },
152 { ISO7816_E_POWER_DN_IND, "POWER_DN_IND" },
153 { ISO7816_E_RESET_ACT_IND, "RESET_ACT_IND" },
154 { ISO7816_E_ABORT_REQ, "ABORT_REQ" },
155 { ISO7816_E_TPDU_CLEAR_REQ, "TPDU_CLEAR_REQ" },
156 { 0, NULL }
157};
158
159struct iso7816_3_priv {
160 uint8_t slot_nr;
161 /* child FSM instances */
162 struct osmo_fsm_inst *atr_fi;
163 struct osmo_fsm_inst *pps_fi;
164 struct osmo_fsm_inst *tpdu_fi;
165 /* other data */
166 bool convention_convert;/*!< If convention conversion is needed */
167 uint16_t guard_time_ms;
168 /* underlying UART */
169 struct card_uart *uart;
170 iso7816_user_cb user_cb;
171 void *user_priv;
172};
173
174/* type-safe method to obtain iso7816_3_priv from fi */
175static struct iso7816_3_priv *get_iso7816_3_priv(struct osmo_fsm_inst *fi)
176{
177 OSMO_ASSERT(fi);
178 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
179 return (struct iso7816_3_priv *) fi->priv;
180}
181
182/* convert from clock cycles of the CLK line to milli-seconds */
183uint32_t fi_cycles2ms(struct osmo_fsm_inst *fi, uint32_t cyclces)
184{
185 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
186 /* FIXME */
187 return 1000;
188}
189
190/* card UART notifies us: dispatch to (main ISO7816-3) FSM */
191static void tpdu_uart_notification(struct card_uart *cuart, enum card_uart_event evt, void *data)
192{
193 struct osmo_fsm_inst *fi = (struct osmo_fsm_inst *) cuart->priv;
194 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
195
196 LOGPFSML(fi, LOGL_DEBUG, "UART Notification '%s'\n",
197 get_value_string(card_uart_event_vals, evt));
198
199 /* FIXME: Set only flags here; Main loop polls flags and dispatches events */
200
201 switch (evt) {
202 case CUART_E_RX_SINGLE:
203 osmo_fsm_inst_dispatch(fi, ISO7816_E_RX_SINGLE, data);
204 break;
205 case CUART_E_RX_COMPLETE:
206 osmo_fsm_inst_dispatch(fi, ISO7816_E_RX_COMPL, data);
207 break;
208 case CUART_E_RX_TIMEOUT:
209 osmo_fsm_inst_dispatch(fi, ISO7816_E_WTIME_EXP, data);
210 break;
211 case CUART_E_TX_COMPLETE:
212 osmo_fsm_inst_dispatch(fi, ISO7816_E_TX_COMPL, data);
213 break;
214 }
215}
216
217static void iso7816_3_reset_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
218{
219 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
220 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
221
222 /* go back to initial state in child FSMs */
223 osmo_fsm_inst_state_chg(ip->atr_fi, ATR_S_WAIT_TS, 0, 0);
224 //osmo_fsm_inst_state_chg(ip->pps_fi, PPS_S_WAIT_PPSS, 0, 0);
225 osmo_fsm_inst_state_chg(ip->tpdu_fi, TPDU_S_INIT, 0, 0);
226}
227
228static void iso7816_3_reset_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
229{
230 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
231 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
232
233 switch (event) {
234 case ISO7816_E_RESET_REL_IND:
235 /* TOOD: this should happen before reset is released */
236 card_uart_ctrl(ip->uart, CUART_CTL_RX, true);
237 osmo_fsm_inst_state_chg_ms(fi, ISO7816_S_WAIT_ATR,
238 fi_cycles2ms(fi, 40000), T_WAIT_ATR);
239 break;
240 default:
241 OSMO_ASSERT(0);
242 }
243}
244
245static void iso7816_3_wait_atr_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
246{
247 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
248 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
249
250 switch (event) {
251 case ISO7816_E_RX_SINGLE:
252 osmo_fsm_inst_state_chg(fi, ISO7816_S_IN_ATR, 0, 0);
253 osmo_fsm_inst_dispatch(ip->atr_fi, event, data);
254 break;
Harald Welte1ac9ef92019-10-09 22:20:16 +0200255 case ISO7816_E_WTIME_EXP:
256 ip->user_cb(fi, event, 0, NULL);
257 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
258 break;
Harald Welte06348362019-05-19 00:45:17 +0200259 default:
260 OSMO_ASSERT(0);
261 }
262}
263
264static void iso7816_3_in_atr_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
265{
266 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
267 struct msgb *atr;
268 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
269
270 switch (event) {
271 case ISO7816_E_RX_SINGLE:
272 case ISO7816_E_RX_ERR_IND:
Harald Welte1ac9ef92019-10-09 22:20:16 +0200273 case ISO7816_E_WTIME_EXP:
Harald Welte06348362019-05-19 00:45:17 +0200274 /* simply pass this through to the child FSM for the ATR */
275 osmo_fsm_inst_dispatch(ip->atr_fi, event, data);
276 break;
277 case ISO7816_E_ATR_DONE_IND:
278 atr = data;
279 /* FIXME: verify ATR result: success / failure */
280 osmo_fsm_inst_state_chg(fi, ISO7816_S_WAIT_TPDU, 0, 0);
281 /* notify user about ATR */
282 ip->user_cb(fi, event, 0, atr);
283 break;
Harald Welte1ac9ef92019-10-09 22:20:16 +0200284 case ISO7816_E_ATR_ERR_IND:
285 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
286 ip->user_cb(fi, event, 0, atr);
287 break;
Harald Welte06348362019-05-19 00:45:17 +0200288 default:
289 OSMO_ASSERT(0);
290 }
291}
292
293static void iso7816_3_wait_tpdu_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
294{
295 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
296 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
Harald Weltebe86f852019-10-09 22:25:48 +0200297 card_uart_ctrl(ip->uart, CUART_CTL_RX, false);
Harald Welte06348362019-05-19 00:45:17 +0200298 /* reset the TPDU state machine */
299 osmo_fsm_inst_dispatch(ip->tpdu_fi, ISO7816_E_TPDU_CLEAR_REQ, NULL);
300}
301
302static void iso7816_3_wait_tpdu_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
303{
304 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
305 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
306
307 switch (event) {
308 case ISO7816_E_XCEIVE_TPDU_CMD:
309 /* "data" contains a msgb-wrapped TPDU */
310 osmo_fsm_inst_state_chg(fi, ISO7816_S_IN_TPDU, 0, 0);
311 /* pass on to sub-fsm */
312 osmo_fsm_inst_dispatch(ip->tpdu_fi, event, data);
313 break;
314 default:
315 OSMO_ASSERT(0);
316 }
317}
318
319static void iso7816_3_in_tpdu_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
320{
321 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
322 struct msgb *apdu;
323 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
324
325 switch (event) {
326 case ISO7816_E_RX_SINGLE:
327 case ISO7816_E_RX_COMPL:
328 case ISO7816_E_RX_ERR_IND:
329 case ISO7816_E_TX_COMPL:
330 case ISO7816_E_TX_ERR_IND:
331 /* simply pass this through to the child FSM for the ATR */
332 osmo_fsm_inst_dispatch(ip->tpdu_fi, event, data);
333 break;
334 case ISO7816_E_TPDU_DONE_IND:
335 apdu = data;
336 osmo_fsm_inst_state_chg(fi, ISO7816_S_WAIT_TPDU, 0, 0);
337 /* hand finished TPDU to user */
338 ip->user_cb(fi, event, 0, apdu);
339 break;
Harald Welte1ac9ef92019-10-09 22:20:16 +0200340 case ISO7816_E_WTIME_EXP:
341 /* FIXME: power off? */
342 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
343 break;
Harald Welte06348362019-05-19 00:45:17 +0200344 default:
345 OSMO_ASSERT(0);
346 }
347}
348
349static void iso7816_3_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
350{
351 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
352
353 switch (event) {
Harald Welte06348362019-05-19 00:45:17 +0200354 case ISO7816_E_HW_ERR_IND:
355 case ISO7816_E_CARD_REMOVAL:
356 /* FIXME: power off? */
357 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
358 break;
359 case ISO7816_E_POWER_DN_IND:
360 case ISO7816_E_RESET_ACT_IND:
361 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
362 break;
363 case ISO7816_E_ABORT_REQ:
364 /* FIXME */
365 break;
366 default:
367 OSMO_ASSERT(0);
368 break;
369 }
370}
371
372static const struct osmo_fsm_state iso7816_3_states[] = {
373 [ISO7816_S_RESET] = {
374 .name = "RESET",
375 .in_event_mask = S(ISO7816_E_RESET_REL_IND),
376 .out_state_mask = S(ISO7816_S_WAIT_ATR) |
377 S(ISO7816_S_RESET),
378 .action = iso7816_3_reset_action,
379 .onenter = iso7816_3_reset_onenter,
380 },
381 [ISO7816_S_WAIT_ATR] = {
382 .name = "WAIT_ATR",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200383 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
384 S(ISO7816_E_WTIME_EXP),
Harald Welte06348362019-05-19 00:45:17 +0200385 .out_state_mask = S(ISO7816_S_RESET) |
386 S(ISO7816_S_IN_ATR),
387 .action = iso7816_3_wait_atr_action,
388 },
389 [ISO7816_S_IN_ATR] = {
390 .name = "IN_ATR",
391 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
392 S(ISO7816_E_RX_ERR_IND) |
Harald Welte1ac9ef92019-10-09 22:20:16 +0200393 S(ISO7816_E_ATR_DONE_IND) |
394 S(ISO7816_E_ATR_ERR_IND) |
395 S(ISO7816_E_WTIME_EXP),
Harald Welte06348362019-05-19 00:45:17 +0200396 .out_state_mask = S(ISO7816_S_RESET) |
397 S(ISO7816_S_IN_ATR) |
398 S(ISO7816_S_WAIT_TPDU),
399 .action = iso7816_3_in_atr_action,
400 },
401 [ISO7816_S_WAIT_TPDU] = {
402 .name = "WAIT_TPDU",
403 .in_event_mask = S(ISO7816_E_XCEIVE_TPDU_CMD),
404 .out_state_mask = S(ISO7816_S_RESET) |
405 S(ISO7816_S_WAIT_TPDU) |
406 S(ISO7816_S_IN_TPDU) |
407 S(ISO7816_S_IN_PPS_REQ),
408 .action = iso7816_3_wait_tpdu_action,
409 .onenter = iso7816_3_wait_tpdu_onenter,
410 },
411 [ISO7816_S_IN_TPDU] = {
412 .name = "IN_TPDU",
413 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
414 S(ISO7816_E_RX_COMPL) |
415 S(ISO7816_E_TX_COMPL) |
416 S(ISO7816_E_RX_ERR_IND) |
417 S(ISO7816_E_TX_ERR_IND) |
Harald Welte1ac9ef92019-10-09 22:20:16 +0200418 S(ISO7816_E_TPDU_DONE_IND) |
419 S(ISO7816_E_WTIME_EXP),
Harald Welte06348362019-05-19 00:45:17 +0200420 .out_state_mask = S(ISO7816_S_RESET) |
421 S(ISO7816_S_WAIT_TPDU) |
422 S(ISO7816_S_IN_TPDU),
423 .action = iso7816_3_in_tpdu_action,
424 },
425 [ISO7816_S_IN_PPS_REQ] = {
426 .name = "IN_PPS_REQ",
427 .in_event_mask = 0, /* FIXME */
428 .out_state_mask = S(ISO7816_S_RESET) |
429 S(ISO7816_S_WAIT_TPDU) |
430 S(ISO7816_S_IN_PPS_REQ) |
431 S(ISO7816_S_WAIT_PPS_RSP),
432 },
433 [ISO7816_S_WAIT_PPS_RSP] = {
434 .name = "WAIT_PPS_RESP",
435 .in_event_mask = 0, /* FIXME */
436 .out_state_mask = S(ISO7816_S_RESET) |
437 S(ISO7816_S_WAIT_TPDU) |
438 S(ISO7816_S_WAIT_PPS_RSP) |
439 S(ISO7816_S_IN_PPS_RSP),
440 },
441 [ISO7816_S_IN_PPS_RSP] = {
442 .name = "IN_PPS_RESP",
443 .in_event_mask = 0, /* FIXME */
444 .out_state_mask = S(ISO7816_S_RESET) |
445 S(ISO7816_S_WAIT_TPDU) |
446 S(ISO7816_S_IN_PPS_RSP),
447 },
448};
449static struct osmo_fsm iso7816_3_fsm = {
450 .name = "ISO7816-3",
451 .states = iso7816_3_states,
452 .num_states = ARRAY_SIZE(iso7816_3_states),
453 .log_subsys = DISO7816,
454 .event_names = iso7816_3_event_names,
455 .allstate_action = iso7816_3_allstate_action,
Harald Welte1ac9ef92019-10-09 22:20:16 +0200456 .allstate_event_mask = S(ISO7816_E_CARD_REMOVAL) |
Harald Welte06348362019-05-19 00:45:17 +0200457 S(ISO7816_E_POWER_DN_IND) |
458 S(ISO7816_E_RESET_ACT_IND) |
459 S(ISO7816_E_HW_ERR_IND) |
460 S(ISO7816_E_ABORT_REQ),
461};
462
463/***********************************************************************
464 * ATR FSM
465 ***********************************************************************/
466
467struct atr_fsm_priv {
468 uint8_t hist_len; /*!< store the number of expected historical bytes */
469 uint8_t y; /*!< last mask of the upcoming TA, TB, TC, TD interface bytes */
470 uint8_t i; /*!< interface byte subgroup number */
471 struct msgb *atr; /*!< ATR data */
472 uint8_t computed_checksum;
473 uint16_t protocol_support;
474};
475
476/* obtain the [software] guard time in milli-seconds from the atr fsm_inst */
477static uint32_t atr_fi_gt_ms(struct osmo_fsm_inst *fi)
478{
479 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
480 struct iso7816_3_priv *ip;
481
482 OSMO_ASSERT(fi->fsm == &atr_fsm);
483 OSMO_ASSERT(parent_fi);
484 ip = get_iso7816_3_priv(parent_fi);
485
486 return ip->guard_time_ms;
487}
488
489/* obtain the 'byte' parmeter of an ISO7816_E_RX event */
490static uint8_t get_rx_byte_evt(struct osmo_fsm_inst *fi, void *data)
491{
492 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
493 uint8_t byte = *(uint8_t *)data;
494
495 /* apply inverse convention */
496 if (ip->convention_convert)
497 byte = convention_convert_lut[byte];
498
499 return byte;
500}
501
502/* append a single byte to the ATR */
503static int atr_append_byte(struct osmo_fsm_inst *fi, uint8_t byte)
504{
505 struct atr_fsm_priv *atp = fi->priv;
506
507 if (!msgb_tailroom(atp->atr)) {
508 LOGPFSML(fi, LOGL_ERROR, "ATR overflow !?!");
509 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_SW_ERR_IND, NULL);
510 return -1;
511 }
512 msgb_put_u8(atp->atr, byte);
513 return 0;
514}
515
516static void atr_wait_ts_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
517{
518 struct atr_fsm_priv *atp = fi->priv;
519
520 /* reset state to its initial value */
521 atp->hist_len = 0;
522 atp->y = 0;
523 atp->i = 0;
524 if (!atp->atr)
525 atp->atr = msgb_alloc_c(fi, 33, "ATR"); /* TS + 32 chars */
526 else
527 msgb_reset(atp->atr);
528 atp->computed_checksum = 0;
529 atp->protocol_support = 0;
530}
531
532static void atr_wait_ts_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
533{
534 struct atr_fsm_priv *atp = fi->priv;
535 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
536 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
537 uint8_t byte;
538
539 switch (event) {
540 case ISO7816_E_RX_SINGLE:
541 OSMO_ASSERT(msgb_length(atp->atr) == 0);
542restart:
543 byte = get_rx_byte_evt(parent_fi, data);
544 LOGPFSML(fi, LOGL_DEBUG, "RX byte '%02x'\n", byte);
545 switch (byte) {
546 case 0x23:
547 /* direct convention used, but decoded using inverse
548 * convention (a parity error should also have occurred) */
549 /* fall-through */
550 case 0x30:
551 /* inverse convention used, but decoded using direct
552 * convention (a parity error should also have occurred) */
553 ip->convention_convert = !ip->convention_convert;
554 goto restart;
555 break;
556 case 0x3b: /* direct convention used and correctly decoded */
557 /* fall-through */
558 case 0x3f: /* inverse convention used and correctly decoded */
559 atr_append_byte(fi, byte);
560 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_T0, atr_fi_gt_ms(fi), T_GUARD);
561 break;
562 default:
563 LOGPFSML(fi, LOGL_ERROR, "Invalid TS received: 0x%02X\n", byte);
564 /* FIXME: somehow indiicate to user */
565 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_SW_ERR_IND, NULL);
566 break;
567 }
568 atp->i = 0; /* first interface byte sub-group is coming (T0 is kind of TD0) */
569 break;
Harald Welte1ac9ef92019-10-09 22:20:16 +0200570 case ISO7816_E_WTIME_EXP:
571 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_ATR_ERR_IND, NULL);
572 break;
Harald Welte06348362019-05-19 00:45:17 +0200573 default:
574 OSMO_ASSERT(0);
575 }
576}
577
578static void atr_wait_tX_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
579{
580 struct atr_fsm_priv *atp = fi->priv;
581 uint32_t guard_time_ms = atr_fi_gt_ms(fi);
582 uint8_t byte;
583
584 switch (event) {
585 case ISO7816_E_RX_SINGLE:
586 byte = get_rx_byte_evt(fi->proc.parent, data);
587 LOGPFSML(fi, LOGL_DEBUG, "RX byte '%02x'\n", byte);
588 atr_append_byte(fi, byte);
589 switch (fi->state) {
590 case ATR_S_WAIT_T0: /* see ISO/IEC 7816-3:2006 section 8.2.2 */
591 case ATR_S_WAIT_TD: /* see ISO/IEC 7816-3:2006 section 8.2.3 */
592 if (fi->state == ATR_S_WAIT_T0) {
593 /* save number of hist. bytes */
594 atp->hist_len = (byte & 0x0f);
595 } else {
596 /* remember supported protocol to know if TCK will be present */
597 atp->protocol_support |= (1<<(byte & 0x0f));
598 }
599 atp->y = (byte & 0xf0); /* remember incoming interface bytes */
600 atp->i++;
601 if (atp->y & 0x10) {
602 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_TA, guard_time_ms, T_GUARD);
603 break;
604 }
605 /* fall-through */
606 case ATR_S_WAIT_TA: /* see ISO/IEC 7816-3:2006 section 8.2.3 */
607 if (atp->y & 0x20) {
608 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_TB, guard_time_ms, T_GUARD);
609 break;
610 }
611 /* fall-through */
612 case ATR_S_WAIT_TB: /* see ISO/IEC 7816-3:2006 section 8.2.3 */
613 if (atp->y & 0x40) {
614 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_TC, guard_time_ms, T_GUARD);
615 break;
616 }
617 /* fall-through */
618 case ATR_S_WAIT_TC: /* see ISO/IEC 7816-3:2006 section 8.2.3 */
619 if (atp->y & 0x80) {
620 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_TD, guard_time_ms, T_GUARD);
621 break;
622 } else if (atp->hist_len) {
623 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_HIST, guard_time_ms, T_GUARD);
624 break;
625 }
626 /* fall-through */
627 case ATR_S_WAIT_HIST: /* see ISO/IEC 7816-3:2006 section 8.2.4 */
628 if (atp->hist_len)
629 atp->hist_len--;
630 if (atp->hist_len == 0) {
631 if (atp->protocol_support > 1) {
632 /* wait for check byte */
633 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_TCK,
634 guard_time_ms, T_GUARD);
635 break;
Eric Wild70d212d2019-11-27 15:05:09 +0100636 } else {
637 /* no TCK present, ATR complete; notify parent */
638 osmo_fsm_inst_state_chg(fi, ATR_S_DONE, 0, 0);
639 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_ATR_DONE_IND, atp->atr);
Harald Welte06348362019-05-19 00:45:17 +0200640 }
641 } else {
642 break;
643 }
644 /* fall-through */
645 case ATR_S_WAIT_TCK: /* see ISO/IEC 7816-3:2006 section 8.2.5 */
646 /* verify checksum if present */
647 if (fi->state == ATR_S_WAIT_TCK) {
648 uint8_t ui;
649 uint8_t *atr = msgb_data(atp->atr);
650 LOGPFSML(fi, LOGL_INFO, "Complete ATR: %s\n", msgb_hexdump(atp->atr));
651 for (ui = 1; ui < msgb_length(atp->atr)-1; ui++) {
652 atp->computed_checksum ^= atr[ui];
653 }
654 if (atp->computed_checksum != byte) {
655 /* checkum error. report to user? */
656 LOGPFSML(fi, LOGL_ERROR,
657 "computed checksum %02x doesn't match TCK=%02x\n",
658 atp->computed_checksum, byte);
659 }
660 /* ATR complete; notify parent */
661 osmo_fsm_inst_state_chg(fi, ATR_S_DONE, 0, 0);
662 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_ATR_DONE_IND, atp->atr);
663 }
664 break;
665 default:
666 OSMO_ASSERT(0);
667 }
668 break;
Harald Welte1ac9ef92019-10-09 22:20:16 +0200669 case ISO7816_E_WTIME_EXP:
670 switch (fi->state) {
671 case ATR_S_WAIT_HIST:
672 case ATR_S_WAIT_TCK:
673 /* Some cards have an ATR with long indication of historical bytes */
674 /* FIXME: should we check the checksum? */
675 osmo_fsm_inst_state_chg(fi, ATR_S_DONE, 0, 0);
676 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_ATR_DONE_IND, atp->atr);
677 break;
678 default:
679 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_ATR_ERR_IND, NULL);
680 break;
681 }
682 break;
Harald Welte06348362019-05-19 00:45:17 +0200683 default:
684 OSMO_ASSERT(0);
685 }
686}
687
688static const struct osmo_fsm_state atr_states[] = {
689 [ATR_S_WAIT_TS] = {
690 .name = "WAIT_TS",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200691 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
692 S(ISO7816_E_WTIME_EXP),
Harald Welte06348362019-05-19 00:45:17 +0200693 .out_state_mask = S(ATR_S_WAIT_TS) |
694 S(ATR_S_WAIT_T0),
695 .action = atr_wait_ts_action,
696 .onenter = atr_wait_ts_onenter,
697 },
698 [ATR_S_WAIT_T0] = {
699 .name = "WAIT_T0",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200700 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
701 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200702 .out_state_mask = S(ATR_S_WAIT_TS) |
703 S(ATR_S_WAIT_TA) |
Harald Welte06348362019-05-19 00:45:17 +0200704 S(ATR_S_WAIT_TB) |
705 S(ATR_S_WAIT_TC) |
706 S(ATR_S_WAIT_TD) |
707 S(ATR_S_WAIT_HIST) |
708 S(ATR_S_WAIT_TCK) |
709 S(ATR_S_WAIT_T0),
710 .action = atr_wait_tX_action,
711 },
712 [ATR_S_WAIT_TA] = {
713 .name = "WAIT_TA",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200714 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
715 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200716 .out_state_mask = S(ATR_S_WAIT_TS) |
717 S(ATR_S_WAIT_TB) |
Harald Welte06348362019-05-19 00:45:17 +0200718 S(ATR_S_WAIT_TC) |
719 S(ATR_S_WAIT_TD) |
720 S(ATR_S_WAIT_HIST) |
721 S(ATR_S_WAIT_TCK) |
722 S(ATR_S_WAIT_T0),
723 .action = atr_wait_tX_action,
724 },
725 [ATR_S_WAIT_TB] = {
726 .name = "WAIT_TB",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200727 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
728 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200729 .out_state_mask = S(ATR_S_WAIT_TS) |
730 S(ATR_S_WAIT_TC) |
Harald Welte06348362019-05-19 00:45:17 +0200731 S(ATR_S_WAIT_TD) |
732 S(ATR_S_WAIT_HIST) |
733 S(ATR_S_WAIT_TCK) |
734 S(ATR_S_WAIT_T0),
735 .action = atr_wait_tX_action,
736 },
737 [ATR_S_WAIT_TC] = {
738 .name = "WAIT_TC",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200739 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
740 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200741 .out_state_mask = S(ATR_S_WAIT_TS) |
742 S(ATR_S_WAIT_TD) |
Harald Welte06348362019-05-19 00:45:17 +0200743 S(ATR_S_WAIT_HIST) |
744 S(ATR_S_WAIT_TCK) |
745 S(ATR_S_WAIT_T0),
746 .action = atr_wait_tX_action,
747 },
748 [ATR_S_WAIT_TD] = {
749 .name = "WAIT_TD",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200750 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
751 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200752 .out_state_mask = S(ATR_S_WAIT_TS) |
753 S(ATR_S_WAIT_TA) |
Harald Welte06348362019-05-19 00:45:17 +0200754 S(ATR_S_WAIT_TB) |
755 S(ATR_S_WAIT_TC) |
756 S(ATR_S_WAIT_TD) |
757 S(ATR_S_WAIT_HIST) |
758 S(ATR_S_WAIT_TCK) |
759 S(ATR_S_WAIT_T0),
760 .action = atr_wait_tX_action,
761 },
762 [ATR_S_WAIT_HIST] = {
763 .name = "WAIT_HIST",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200764 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
765 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200766 .out_state_mask = S(ATR_S_WAIT_TS) |
767 S(ATR_S_WAIT_TCK) |
Harald Welte1ac9ef92019-10-09 22:20:16 +0200768 S(ATR_S_WAIT_T0) |
769 S(ATR_S_DONE),
Harald Welte06348362019-05-19 00:45:17 +0200770 .action = atr_wait_tX_action,
771 },
772 [ATR_S_WAIT_TCK] = {
773 .name = "WAIT_TCK",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200774 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
775 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200776 .out_state_mask = S(ATR_S_WAIT_TS) |
777 S(ATR_S_DONE),
Harald Welte06348362019-05-19 00:45:17 +0200778 .action = atr_wait_tX_action,
779 },
780 [ATR_S_DONE] = {
781 .name = "DONE",
782 .in_event_mask = 0,
Harald Welte704d99a2019-10-09 21:39:27 +0200783 .out_state_mask = S(ATR_S_WAIT_TS),
Harald Welte06348362019-05-19 00:45:17 +0200784 //.action = atr_done_action,
785 },
786
787};
788static struct osmo_fsm atr_fsm = {
789 .name = "ATR",
790 .states = atr_states,
791 .num_states = ARRAY_SIZE(atr_states),
792 .log_subsys = DATR,
793 .event_names = iso7816_3_event_names,
794};
795
796/***********************************************************************
797 * PPS FSM
798 ***********************************************************************/
799
800static const struct osmo_fsm_state pps_states[] = {
801 [PPS_S_WAIT_PPSS] = {
802 .name = "WAIT_PPSS",
803 },
804 [PPS_S_WAIT_PPS0] = {
805 .name = "WAIT_PPS0",
806 },
807 [PPS_S_WAIT_PPS1] = {
808 .name = "WAIT_PPS1",
809 },
810 [PPS_S_WAIT_PPS2] = {
811 .name = "WAIT_PPS2",
812 },
813 [PPS_S_WAIT_PPS3] = {
814 .name = "WAIT_PPS3",
815 },
816 [PPS_S_WAIT_PCK] = {
817 .name = "WAIT_PCK",
818 },
819 [PPS_S_WAIT_END] = {
820 .name = "WAIT_END",
821 },
822};
823
824static struct osmo_fsm pps_fsm = {
825 .name = "PPS",
826 .states = pps_states,
827 .num_states = ARRAY_SIZE(pps_states),
828 .log_subsys = DPPS,
829 .event_names = iso7816_3_event_names,
830};
831
832/***********************************************************************
833 * TPDU FSM
834 ***********************************************************************/
835
Harald Welte65087832019-10-01 09:16:49 +0200836/* In this FSM weu use the msgb for the TPDU as follows:
837 * - 5-byte TPDU header is at msg->data
838 * - COMMAND TPDU:
839 * - command bytes are provided after the header at msg->l2h
840 * - in case of incremental transmission, l3h points to next to-be-transmitted byte
841 * - RESPONSE TPDU:
842 * - any response bytes are stored after the header at msg->l2h
843 */
844
845static inline struct osim_apdu_cmd_hdr *msgb_tpdu_hdr(struct msgb *msg) {
846 return (struct osim_apdu_cmd_hdr *) msgb_data(msg);
847}
848
Harald Welte06348362019-05-19 00:45:17 +0200849struct tpdu_fsm_priv {
850 struct msgb *tpdu;
Harald Welte65087832019-10-01 09:16:49 +0200851 bool is_command; /* is this a command TPDU (true) or a response (false) */
Harald Welte06348362019-05-19 00:45:17 +0200852};
853
854/* type-safe method to obtain iso7816_3_priv from fi */
855static struct tpdu_fsm_priv *get_tpdu_fsm_priv(struct osmo_fsm_inst *fi)
856{
857 OSMO_ASSERT(fi);
858 OSMO_ASSERT(fi->fsm == &tpdu_fsm);
859 return (struct tpdu_fsm_priv *) fi->priv;
860}
861
862
863static void tpdu_s_init_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
864{
865 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
866 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
867 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
868 struct osim_apdu_cmd_hdr *tpduh;
869
870 switch (event) {
871 case ISO7816_E_XCEIVE_TPDU_CMD:
872 /* start transmission of a TPDU by sending the 5-byte header */
873 tfp->tpdu = (struct msgb *)data;
874 OSMO_ASSERT(msgb_length(tfp->tpdu) >= sizeof(*tpduh));
875 tfp->tpdu->l2h = msgb_data(tfp->tpdu) + sizeof(*tpduh);
Harald Welte65087832019-10-01 09:16:49 +0200876 if (msgb_l2len(tfp->tpdu)) {
877 tfp->is_command = true;
878 tfp->tpdu->l3h = tfp->tpdu->l2h; /* next tx byte == first byte of body */
879 } else
880 tfp->is_command = false;
881 tpduh = msgb_tpdu_hdr(tfp->tpdu);
882 LOGPFSML(fi, LOGL_DEBUG, "Transmitting %s TPDU header %s via UART\n",
883 tfp->is_command ? "COMMAND" : "RESPONSE",
Harald Welte06348362019-05-19 00:45:17 +0200884 osmo_hexdump_nospc((uint8_t *) tpduh, sizeof(*tpduh)));
885 osmo_fsm_inst_state_chg(fi, TPDU_S_TX_HDR, 0, 0);
Harald Welte6603d952019-10-09 20:50:13 +0200886 card_uart_tx(ip->uart, (uint8_t *) tpduh, sizeof(*tpduh), true);
Harald Welte06348362019-05-19 00:45:17 +0200887 break;
888 default:
889 OSMO_ASSERT(0);
890 }
891}
892
893static void tpdu_s_tx_hdr_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
894{
895 OSMO_ASSERT(fi->fsm == &tpdu_fsm);
896 switch (event) {
897 case ISO7816_E_TX_COMPL:
898 /* Rx of single byte is already enabled by previous card_uart_tx() call */
899 osmo_fsm_inst_state_chg(fi, TPDU_S_PROCEDURE, 0, 0);
900 break;
901 default:
902 OSMO_ASSERT(0);
903 }
904}
905
906
907
908static void tpdu_s_procedure_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
909{
910 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
Harald Welte65087832019-10-01 09:16:49 +0200911 struct osim_apdu_cmd_hdr *tpduh = msgb_tpdu_hdr(tfp->tpdu);
Harald Welte06348362019-05-19 00:45:17 +0200912 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
913 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
914 uint8_t byte;
915
916 switch (event) {
917 case ISO7816_E_RX_SINGLE:
918 byte = get_rx_byte_evt(fi->proc.parent, data);
919 LOGPFSML(fi, LOGL_DEBUG, "Received 0x%02x from UART\n", byte);
920 if (byte == 0x60) {
921 /* NULL: wait for another procedure byte */
922 osmo_fsm_inst_state_chg(fi, TPDU_S_PROCEDURE, 0, 0);
923 } else if ((byte >= 0x60 && byte <= 0x6f) || (byte >= 0x90 && byte <= 0x9f)) {
924 //msgb_apdu_sw(tfp->apdu) = byte << 8;
925 msgb_put(tfp->tpdu, byte);
926 /* receive second SW byte (SW2) */
927 osmo_fsm_inst_state_chg(fi, TPDU_S_SW2, 0, 0);
928 break;
929 } else if (byte == tpduh->ins) {
Harald Welte65087832019-10-01 09:16:49 +0200930 if (tfp->is_command) {
Harald Welte06348362019-05-19 00:45:17 +0200931 /* transmit all remaining bytes */
Harald Welte6603d952019-10-09 20:50:13 +0200932 card_uart_tx(ip->uart, msgb_l2(tfp->tpdu), msgb_l2len(tfp->tpdu), true);
Harald Welte06348362019-05-19 00:45:17 +0200933 osmo_fsm_inst_state_chg(fi, TPDU_S_TX_REMAINING, 0, 0);
934 } else {
935 card_uart_set_rx_threshold(ip->uart, tpduh->p3);
936 osmo_fsm_inst_state_chg(fi, TPDU_S_RX_REMAINING, 0, 0);
937 }
938 } else if (byte == (tpduh->ins ^ 0xFF)) {
Harald Welte65087832019-10-01 09:16:49 +0200939 /* transmit/recieve single byte then wait for proc */
940 if (tfp->is_command) {
941 /* transmit *next*, not first byte */
942 OSMO_ASSERT(msgb_l3len(tfp->tpdu) >= 0);
Harald Welte6603d952019-10-09 20:50:13 +0200943 card_uart_tx(ip->uart, msgb_l3(tfp->tpdu), 1, false);
Harald Welte65087832019-10-01 09:16:49 +0200944 osmo_fsm_inst_state_chg(fi, TPDU_S_TX_SINGLE, 0, 0);
945 } else {
946 osmo_fsm_inst_state_chg(fi, TPDU_S_RX_SINGLE, 0, 0);
947 }
Harald Welte06348362019-05-19 00:45:17 +0200948 } else
949 OSMO_ASSERT(0);
950 break;
951 default:
952 OSMO_ASSERT(0);
953 }
954}
955
956/* UART is transmitting remaining data; we wait for ISO7816_E_TX_COMPL */
957static void tpdu_s_tx_remaining_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
958{
959 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
960 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
961
962 switch (event) {
963 case ISO7816_E_TX_COMPL:
964 card_uart_set_rx_threshold(ip->uart, 1);
965 osmo_fsm_inst_state_chg(fi, TPDU_S_SW1, 0, 0);
966 break;
967 default:
968 OSMO_ASSERT(0);
969 }
970}
971
972/* UART is transmitting single byte of data; we wait for ISO7816_E_TX_COMPL */
973static void tpdu_s_tx_single_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
974{
Harald Welte65087832019-10-01 09:16:49 +0200975 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
976
Harald Welte06348362019-05-19 00:45:17 +0200977 switch (event) {
978 case ISO7816_E_TX_COMPL:
Harald Welte65087832019-10-01 09:16:49 +0200979 tfp->tpdu->l3h += 1;
980 if (msgb_l3len(tfp->tpdu))
981 osmo_fsm_inst_state_chg(fi, TPDU_S_PROCEDURE, 0, 0);
982 else
983 osmo_fsm_inst_state_chg(fi, TPDU_S_SW1, 0, 0);
Harald Welte06348362019-05-19 00:45:17 +0200984 break;
985 default:
986 OSMO_ASSERT(0);
987 }
988}
989
990/* UART is receiving remaining data; we wait for ISO7816_E_RX_COMPL */
991static void tpdu_s_rx_remaining_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
992{
993 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
Harald Welte65087832019-10-01 09:16:49 +0200994 struct osim_apdu_cmd_hdr *tpduh = msgb_tpdu_hdr(tfp->tpdu);
Harald Welte06348362019-05-19 00:45:17 +0200995 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
996 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
997 int rc;
998
999 switch (event) {
1000 case ISO7816_E_RX_COMPL:
1001 /* retrieve pending byte(s) */
1002 rc = card_uart_rx(ip->uart, msgb_l2(tfp->tpdu), tpduh->p3);
Harald Welte65087832019-10-01 09:16:49 +02001003 OSMO_ASSERT(rc > 0);
1004 msgb_put(tfp->tpdu, rc);
1005 if (msgb_l2len(tfp->tpdu) != tpduh->p3) {
1006 LOGPFSML(fi, LOGL_ERROR, "expected %u bytes; read %d\n", tpduh->p3,
1007 msgb_l2len(tfp->tpdu));
1008 }
Harald Welte06348362019-05-19 00:45:17 +02001009 card_uart_set_rx_threshold(ip->uart, 1);
1010 osmo_fsm_inst_state_chg(fi, TPDU_S_SW1, 0, 0);
1011 break;
1012 default:
1013 OSMO_ASSERT(0);
1014 }
1015}
1016
1017/* UART is receiving single byte of data; we wait for ISO7816_E_RX_SINGLE */
1018static void tpdu_s_rx_single_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1019{
1020 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
Harald Welte65087832019-10-01 09:16:49 +02001021 struct osim_apdu_cmd_hdr *tpduh = msgb_tpdu_hdr(tfp->tpdu);
Harald Welte06348362019-05-19 00:45:17 +02001022 uint8_t byte;
1023
1024 switch (event) {
1025 case ISO7816_E_RX_SINGLE:
1026 byte = get_rx_byte_evt(fi->proc.parent, data);
1027 LOGPFSML(fi, LOGL_DEBUG, "Received 0x%02x from UART\n", byte);
Harald Welte65087832019-10-01 09:16:49 +02001028 msgb_put_u8(tfp->tpdu, byte);
1029 /* determine if number of expected bytes received */
1030 if (msgb_l2len(tfp->tpdu) == tpduh->p3)
Harald Welte06348362019-05-19 00:45:17 +02001031 osmo_fsm_inst_state_chg(fi, TPDU_S_SW1, 0, 0);
Harald Welte65087832019-10-01 09:16:49 +02001032 else
Harald Welte06348362019-05-19 00:45:17 +02001033 osmo_fsm_inst_state_chg(fi, TPDU_S_PROCEDURE, 0, 0);
1034 break;
1035 default:
1036 OSMO_ASSERT(0);
1037 }
1038}
1039
1040static void tpdu_s_sw1_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1041{
1042 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
1043 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1044 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1045 uint8_t byte;
1046
1047 switch (event) {
1048 case ISO7816_E_RX_SINGLE:
1049 byte = get_rx_byte_evt(fi->proc.parent, data);
1050 LOGPFSML(fi, LOGL_DEBUG, "Received 0x%02x from UART\n", byte);
1051 /* record byte */
1052 //msgb_apdu_sw(tfp->apdu) = byte << 8;
1053 msgb_put_u8(tfp->tpdu, byte);
1054 card_uart_set_rx_threshold(ip->uart, 1);
1055 osmo_fsm_inst_state_chg(fi, TPDU_S_SW2, 0, 0);
1056 break;
1057 default:
1058 OSMO_ASSERT(0);
1059 }
1060}
1061
1062static void tpdu_s_sw2_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1063{
1064 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
1065 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1066 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1067 uint8_t byte;
1068
1069 switch (event) {
1070 case ISO7816_E_RX_SINGLE:
1071 byte = get_rx_byte_evt(fi->proc.parent, data);
1072 LOGPFSML(fi, LOGL_DEBUG, "Received 0x%02x from UART\n", byte);
1073 /* record SW2 byte */
1074 //msgb_apdu_sw(tfp->apdu) &= 0xFF00;
1075 //msgb_apdu_sw(tfp->apdu) |= byte;
1076 msgb_put_u8(tfp->tpdu, byte);
1077 osmo_fsm_inst_state_chg(fi, TPDU_S_DONE, 0, 0);
1078 /* Notify parent FSM */
1079 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_TPDU_DONE_IND, tfp->tpdu);
1080 break;
1081 default:
1082 OSMO_ASSERT(0);
1083 }
1084}
1085
1086static void tpdu_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1087{
1088 OSMO_ASSERT(fi->fsm == &tpdu_fsm);
1089
1090 switch (event) {
1091 case ISO7816_E_RX_ERR_IND:
1092 case ISO7816_E_TX_ERR_IND:
1093 /* FIXME: handle this in some different way */
1094 osmo_fsm_inst_state_chg(fi, TPDU_S_DONE, 0, 0);
1095 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_TPDU_DONE_IND, NULL);
1096 break;
1097 case ISO7816_E_TPDU_CLEAR_REQ:
1098 osmo_fsm_inst_state_chg(fi, TPDU_S_INIT, 0, 0);
1099 break;
1100 }
1101}
1102
1103static const struct osmo_fsm_state tpdu_states[] = {
1104 [TPDU_S_INIT] = {
1105 .name = "INIT",
1106 .in_event_mask = S(ISO7816_E_XCEIVE_TPDU_CMD) |
1107 S(ISO7816_E_TX_COMPL),
1108 .out_state_mask = S(TPDU_S_INIT) |
1109 S(TPDU_S_TX_HDR),
1110 .action = tpdu_s_init_action,
1111 },
1112 [TPDU_S_TX_HDR] = {
1113 .name = "TX_HDR",
1114 .in_event_mask = S(ISO7816_E_TX_COMPL),
1115 .out_state_mask = S(TPDU_S_INIT) |
1116 S(TPDU_S_PROCEDURE),
1117 .action = tpdu_s_tx_hdr_action,
1118 },
1119 [TPDU_S_PROCEDURE] = {
1120 .name = "PROCEDURE",
1121 .in_event_mask = S(ISO7816_E_RX_SINGLE),
1122 .out_state_mask = S(TPDU_S_INIT) |
1123 S(TPDU_S_PROCEDURE) |
1124 S(TPDU_S_RX_REMAINING) |
1125 S(TPDU_S_RX_SINGLE) |
1126 S(TPDU_S_TX_REMAINING) |
1127 S(TPDU_S_TX_SINGLE) |
1128 S(TPDU_S_SW2),
1129 .action = tpdu_s_procedure_action,
1130 },
1131 [TPDU_S_TX_REMAINING] = {
1132 .name = "TX_REMAINING",
1133 .in_event_mask = S(ISO7816_E_TX_COMPL),
1134 .out_state_mask = S(TPDU_S_INIT) |
1135 S(TPDU_S_SW1),
1136 .action = tpdu_s_tx_remaining_action,
1137 },
1138 [TPDU_S_TX_SINGLE] = {
1139 .name = "TX_SINGLE",
1140 .in_event_mask = S(ISO7816_E_TX_COMPL),
1141 .out_state_mask = S(TPDU_S_INIT) |
1142 S(TPDU_S_PROCEDURE),
1143 .action = tpdu_s_tx_single_action,
1144 },
1145 [TPDU_S_RX_REMAINING] = {
1146 .name = "RX_REMAINING",
1147 .in_event_mask = S(ISO7816_E_RX_COMPL),
1148 .out_state_mask = S(TPDU_S_INIT) |
1149 S(TPDU_S_SW1),
1150 .action = tpdu_s_rx_remaining_action,
1151 },
1152 [TPDU_S_RX_SINGLE] = {
1153 .name = "RX_SINGLE",
1154 .in_event_mask = S(ISO7816_E_RX_SINGLE),
1155 .out_state_mask = S(TPDU_S_INIT) |
1156 S(TPDU_S_PROCEDURE),
1157 .action = tpdu_s_rx_single_action,
1158 },
1159 [TPDU_S_SW1] = {
1160 .name = "SW1",
1161 .in_event_mask = S(ISO7816_E_RX_SINGLE),
1162 .out_state_mask = S(TPDU_S_INIT) |
1163 S(TPDU_S_SW2),
1164 .action = tpdu_s_sw1_action,
1165 },
1166 [TPDU_S_SW2] = {
1167 .name = "SW2",
1168 .in_event_mask = S(ISO7816_E_RX_SINGLE),
1169 .out_state_mask = S(TPDU_S_INIT) |
1170 S(TPDU_S_DONE),
1171 .action = tpdu_s_sw2_action,
1172 },
1173 [TPDU_S_DONE] = {
1174 .name = "DONE",
1175 .in_event_mask = 0,
1176 .out_state_mask = S(TPDU_S_INIT),
1177 .action = NULL,
1178 },
1179};
1180static struct osmo_fsm tpdu_fsm = {
1181 .name = "TPDU",
1182 .states = tpdu_states,
1183 .num_states = ARRAY_SIZE(tpdu_states),
1184 .allstate_event_mask = S(ISO7816_E_RX_ERR_IND) |
1185 S(ISO7816_E_TX_ERR_IND) |
1186 S(ISO7816_E_TPDU_CLEAR_REQ),
1187 .allstate_action = tpdu_allstate_action,
1188 .log_subsys = DTPDU,
1189 .event_names = iso7816_3_event_names,
1190};
1191
1192struct osmo_fsm_inst *iso7816_fsm_alloc(void *ctx, int log_level, const char *id,
1193 struct card_uart *cuart, iso7816_user_cb user_cb,
1194 void *user_priv)
1195{
1196 struct iso7816_3_priv *ip;
1197 struct osmo_fsm_inst *fi;
1198
1199 fi = osmo_fsm_inst_alloc(&iso7816_3_fsm, ctx, NULL, log_level, id);
1200 ip = talloc_zero(fi, struct iso7816_3_priv);
1201 if (!ip)
1202 goto out_fi;
1203 fi->priv = ip;
1204
1205 ip->uart = cuart;
1206 cuart->priv = fi;
1207 cuart->handle_event = tpdu_uart_notification;
1208
1209 ip->user_cb = user_cb;
1210 ip->user_priv = user_priv;
1211
1212 ip->atr_fi = osmo_fsm_inst_alloc_child(&atr_fsm, fi, ISO7816_E_SW_ERR_IND);
1213 if (!ip->atr_fi)
1214 goto out_fi;
1215 ip->atr_fi->priv = talloc_zero(ip->atr_fi, struct atr_fsm_priv);
1216 if (!ip->atr_fi->priv)
1217 goto out_atr;
1218
1219 ip->tpdu_fi = osmo_fsm_inst_alloc_child(&tpdu_fsm, fi, ISO7816_E_SW_ERR_IND);
1220 if (!ip->tpdu_fi)
1221 goto out_atr;
1222 ip->tpdu_fi->priv = talloc_zero(ip->tpdu_fi, struct tpdu_fsm_priv);
1223 if (!ip->tpdu_fi->priv)
1224 goto out_tpdu;
1225
1226#if 0
1227 ip->pps_fi = osmo_fsm_inst_alloc_child(&pps_fsm, fi, ISO7816_E_SW_ERR_IND);
1228 if (!ip->pps_fi)
1229 goto out_tpdu;
1230 ip->pps_fi->priv = talloc_zero(ip->pps_fi, struct pps_fsm_priv);
1231 if (!ip->pps_fi->priv)
1232 goto out_pps;
1233#endif
1234
1235 /* This ensures the 'onenter' function of the initial state is called */
1236 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
1237
1238 return fi;
1239
1240#if 0
1241out_pps:
1242 osmo_fsm_inst_free(ip->pps_fi);
1243#endif
1244out_tpdu:
1245 osmo_fsm_inst_free(ip->tpdu_fi);
1246out_atr:
1247 osmo_fsm_inst_free(ip->atr_fi);
1248out_fi:
1249 osmo_fsm_inst_free(fi);
1250 cuart->priv = NULL;
1251 return NULL;
1252}
1253
1254void *iso7816_fsm_get_user_priv(struct osmo_fsm_inst *fi)
1255{
1256 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
1257 return ip->user_priv;
1258}
1259
1260
1261static __attribute__((constructor)) void on_dso_load_iso7816(void)
1262{
1263 osmo_fsm_register(&iso7816_3_fsm);
1264 osmo_fsm_register(&atr_fsm);
1265 osmo_fsm_register(&tpdu_fsm);
1266 osmo_fsm_register(&pps_fsm);
1267}