blob: 1835368bb862415274bcc319e6e0ae21bbdd1427 [file] [log] [blame]
Harald Welte06348362019-05-19 00:45:17 +02001/* ISO 7816-3 Finite State Machine (reader side)
2 *
Harald Weltea67be5f2020-09-03 10:04:36 +02003 * (C) 2019-2020 by Harald Welte <laforge@gnumonks.org>
Harald Welte06348362019-05-19 00:45:17 +02004 *
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 */
Harald Welte06348362019-05-19 00:45:17 +020048 ISO7816_S_WAIT_PPS_RSP, /*!< waiting for start of the PPS response */
49 ISO7816_S_IN_PPS_RSP, /*!< while we are inside the PPS request */
50};
51
52/*! Answer-To-Reset (ATR) sub-states of ISO7816_S_IN_ATR
53 * @note defined in ISO/IEC 7816-3:2006(E) section 8
54 */
55enum atr_state {
56 ATR_S_WAIT_TS, /*!< initial byte */
57 ATR_S_WAIT_T0, /*!< format byte */
58 ATR_S_WAIT_TA, /*!< first sub-group interface byte */
59 ATR_S_WAIT_TB, /*!< second sub-group interface byte */
60 ATR_S_WAIT_TC, /*!< third sub-group interface byte */
61 ATR_S_WAIT_TD, /*!< fourth sub-group interface byte */
62 ATR_S_WAIT_HIST, /*!< historical byte */
63 ATR_S_WAIT_TCK, /*!< check byte */
64 ATR_S_DONE
65};
66
67/*! Protocol and Parameters Selection (PPS) sub-states of ISO7816_S_IN_PTS_REQ/ISO7816_S_IN_PTS_RSP
68 * @note defined in ISO/IEC 7816-3:2006(E) section 9
69 */
70enum pps_state {
Eric Wild2f5cdd12019-11-27 18:40:44 +010071 PPS_S_PPS_REQ_INIT, /*!< tx pps request */
72 PPS_S_TX_PPS_REQ,
73 PPS_S_WAIT_PPSX, /*!< initial byte */
Harald Welte06348362019-05-19 00:45:17 +020074 PPS_S_WAIT_PPS0, /*!< format byte */
75 PPS_S_WAIT_PPS1, /*!< first parameter byte */
76 PPS_S_WAIT_PPS2, /*!< second parameter byte */
77 PPS_S_WAIT_PPS3, /*!< third parameter byte */
78 PPS_S_WAIT_PCK, /*!< check byte */
Harald Welte06348362019-05-19 00:45:17 +020079 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
Eric Wild6d3b2fc2020-03-30 03:12:09 +0200131struct atr_fsm_priv {
132 uint8_t hist_len; /*!< store the number of expected historical bytes */
133 uint8_t y; /*!< last mask of the upcoming TA, TB, TC, TD interface bytes */
134 uint8_t i; /*!< interface byte subgroup number */
135 struct msgb *atr; /*!< ATR data */
136 uint8_t computed_checksum;
137 uint16_t protocol_support;
138};
139
140static struct atr_fsm_priv *get_atr_fsm_priv(struct osmo_fsm_inst *fi);
141
Harald Welte06348362019-05-19 00:45:17 +0200142/***********************************************************************
143 * ISO7816-3 Main FSM
144 ***********************************************************************/
145
146static const struct value_string iso7816_3_event_names[] = {
147 { ISO7816_E_RX_SINGLE, "UART_RX_SINGLE" },
148 { ISO7816_E_RX_COMPL, "UART_RX_COMPL" },
149 { ISO7816_E_TX_COMPL, "UART_TX_COMPL" },
150 { ISO7816_E_POWER_UP_IND, "POWER_UP_IND" },
151 { ISO7816_E_RESET_REL_IND, "RESET_REL_IND" },
152 { ISO7816_E_RX_ERR_IND, "RX_ERR_IND" },
153 { ISO7816_E_TX_ERR_IND, "TX_ERR_IND" },
154 { ISO7816_E_ATR_DONE_IND, "ATR_DONE_IND" },
Harald Welte1ac9ef92019-10-09 22:20:16 +0200155 { ISO7816_E_ATR_ERR_IND, "ATR_ERR_IND" },
Harald Welte06348362019-05-19 00:45:17 +0200156 { ISO7816_E_TPDU_DONE_IND, "TPDU_DONE_IND" },
157 { ISO7816_E_XCEIVE_TPDU_CMD, "XCEIVE_TPDU_CMD" },
158 /* allstate events */
159 { ISO7816_E_WTIME_EXP, "WAIT_TIME_EXP" },
160 { ISO7816_E_HW_ERR_IND, "HW_ERR_IND" },
161 { ISO7816_E_SW_ERR_IND, "SW_ERR_IND" },
162 { ISO7816_E_CARD_REMOVAL, "CARD_REMOVAL" },
163 { ISO7816_E_POWER_DN_IND, "POWER_DN_IND" },
164 { ISO7816_E_RESET_ACT_IND, "RESET_ACT_IND" },
165 { ISO7816_E_ABORT_REQ, "ABORT_REQ" },
166 { ISO7816_E_TPDU_CLEAR_REQ, "TPDU_CLEAR_REQ" },
167 { 0, NULL }
168};
169
170struct iso7816_3_priv {
171 uint8_t slot_nr;
172 /* child FSM instances */
173 struct osmo_fsm_inst *atr_fi;
174 struct osmo_fsm_inst *pps_fi;
175 struct osmo_fsm_inst *tpdu_fi;
176 /* other data */
177 bool convention_convert;/*!< If convention conversion is needed */
178 uint16_t guard_time_ms;
179 /* underlying UART */
180 struct card_uart *uart;
181 iso7816_user_cb user_cb;
182 void *user_priv;
183};
184
185/* type-safe method to obtain iso7816_3_priv from fi */
186static struct iso7816_3_priv *get_iso7816_3_priv(struct osmo_fsm_inst *fi)
187{
188 OSMO_ASSERT(fi);
189 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
190 return (struct iso7816_3_priv *) fi->priv;
191}
192
193/* convert from clock cycles of the CLK line to milli-seconds */
194uint32_t fi_cycles2ms(struct osmo_fsm_inst *fi, uint32_t cyclces)
195{
196 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
197 /* FIXME */
198 return 1000;
199}
200
201/* card UART notifies us: dispatch to (main ISO7816-3) FSM */
202static void tpdu_uart_notification(struct card_uart *cuart, enum card_uart_event evt, void *data)
203{
204 struct osmo_fsm_inst *fi = (struct osmo_fsm_inst *) cuart->priv;
205 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
206
207 LOGPFSML(fi, LOGL_DEBUG, "UART Notification '%s'\n",
208 get_value_string(card_uart_event_vals, evt));
209
210 /* FIXME: Set only flags here; Main loop polls flags and dispatches events */
211
212 switch (evt) {
213 case CUART_E_RX_SINGLE:
214 osmo_fsm_inst_dispatch(fi, ISO7816_E_RX_SINGLE, data);
215 break;
216 case CUART_E_RX_COMPLETE:
217 osmo_fsm_inst_dispatch(fi, ISO7816_E_RX_COMPL, data);
218 break;
219 case CUART_E_RX_TIMEOUT:
220 osmo_fsm_inst_dispatch(fi, ISO7816_E_WTIME_EXP, data);
221 break;
222 case CUART_E_TX_COMPLETE:
223 osmo_fsm_inst_dispatch(fi, ISO7816_E_TX_COMPL, data);
224 break;
225 }
226}
227
228static void iso7816_3_reset_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
229{
230 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
231 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
232
Eric Wild2f5cdd12019-11-27 18:40:44 +0100233 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 0);
234
Harald Welte06348362019-05-19 00:45:17 +0200235 /* go back to initial state in child FSMs */
236 osmo_fsm_inst_state_chg(ip->atr_fi, ATR_S_WAIT_TS, 0, 0);
Eric Wild2f5cdd12019-11-27 18:40:44 +0100237 osmo_fsm_inst_state_chg(ip->pps_fi, PPS_S_PPS_REQ_INIT, 0, 0);
Harald Welte06348362019-05-19 00:45:17 +0200238 osmo_fsm_inst_state_chg(ip->tpdu_fi, TPDU_S_INIT, 0, 0);
239}
240
241static void iso7816_3_reset_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
242{
243 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
244 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
Eric Wild9e622dc2019-11-27 14:43:16 +0100245 struct msgb *msg;
Harald Welte06348362019-05-19 00:45:17 +0200246
247 switch (event) {
248 case ISO7816_E_RESET_REL_IND:
249 /* TOOD: this should happen before reset is released */
250 card_uart_ctrl(ip->uart, CUART_CTL_RX, true);
Eric Wild2f5cdd12019-11-27 18:40:44 +0100251
252 /* let's be reasonable here: the 40k cycle delay to ATR start is
253 * ~1.4ms @ 2.5Mhz/6720 baud, 1ETU = 372 cycles -> 40k/372=107/12ETU ~ 9 byte
254 * default timeout for rx is 9600 ETU, ATR might be missing the TCK
255 * so it might time out, so just add this delay */
256 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 32+9);
257 osmo_fsm_inst_state_chg(fi, ISO7816_S_WAIT_ATR, 0, 0);
Harald Welte06348362019-05-19 00:45:17 +0200258 break;
Eric Wild759a6462019-11-11 14:22:52 +0100259 case ISO7816_E_POWER_UP_IND:
260 break;
Eric Wild9e622dc2019-11-27 14:43:16 +0100261 case ISO7816_E_PPS_FAILED_IND:
262 msg = data;
263 /* notify user about PPS result */
264 ip->user_cb(fi, event, 0, msg);
265 break;
266 case ISO7816_E_TPDU_FAILED_IND:
267 msg = data;
268 /* hand finished TPDU to user */
269 ip->user_cb(fi, event, 0, msg);
270 break;
Harald Welte06348362019-05-19 00:45:17 +0200271 default:
272 OSMO_ASSERT(0);
273 }
274}
275
276static void iso7816_3_wait_atr_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
277{
278 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
279 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
280
281 switch (event) {
282 case ISO7816_E_RX_SINGLE:
283 osmo_fsm_inst_state_chg(fi, ISO7816_S_IN_ATR, 0, 0);
284 osmo_fsm_inst_dispatch(ip->atr_fi, event, data);
285 break;
Harald Welte1ac9ef92019-10-09 22:20:16 +0200286 case ISO7816_E_WTIME_EXP:
287 ip->user_cb(fi, event, 0, NULL);
288 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
289 break;
Harald Welte06348362019-05-19 00:45:17 +0200290 default:
291 OSMO_ASSERT(0);
292 }
293}
294
295static void iso7816_3_in_atr_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
296{
297 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
298 struct msgb *atr;
299 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
300
301 switch (event) {
302 case ISO7816_E_RX_SINGLE:
303 case ISO7816_E_RX_ERR_IND:
Harald Welte1ac9ef92019-10-09 22:20:16 +0200304 case ISO7816_E_WTIME_EXP:
Harald Welte06348362019-05-19 00:45:17 +0200305 /* simply pass this through to the child FSM for the ATR */
306 osmo_fsm_inst_dispatch(ip->atr_fi, event, data);
307 break;
308 case ISO7816_E_ATR_DONE_IND:
309 atr = data;
310 /* FIXME: verify ATR result: success / failure */
311 osmo_fsm_inst_state_chg(fi, ISO7816_S_WAIT_TPDU, 0, 0);
312 /* notify user about ATR */
313 ip->user_cb(fi, event, 0, atr);
314 break;
Harald Welte1ac9ef92019-10-09 22:20:16 +0200315 case ISO7816_E_ATR_ERR_IND:
Eric Wild91552312019-11-18 13:57:11 +0100316 atr = data;
Harald Welte1ac9ef92019-10-09 22:20:16 +0200317 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
318 ip->user_cb(fi, event, 0, atr);
319 break;
Harald Welte06348362019-05-19 00:45:17 +0200320 default:
321 OSMO_ASSERT(0);
322 }
323}
324
325static void iso7816_3_wait_tpdu_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
326{
327 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
328 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
Eric Wild2f5cdd12019-11-27 18:40:44 +0100329 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 0);
Eric Wildfd0bace2019-11-27 18:33:09 +0100330 card_uart_ctrl(ip->uart, CUART_CTL_NO_RXTX, true);
Harald Welte06348362019-05-19 00:45:17 +0200331 /* reset the TPDU state machine */
332 osmo_fsm_inst_dispatch(ip->tpdu_fi, ISO7816_E_TPDU_CLEAR_REQ, NULL);
333}
334
335static void iso7816_3_wait_tpdu_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
336{
337 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
338 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
339
340 switch (event) {
341 case ISO7816_E_XCEIVE_TPDU_CMD:
342 /* "data" contains a msgb-wrapped TPDU */
343 osmo_fsm_inst_state_chg(fi, ISO7816_S_IN_TPDU, 0, 0);
344 /* pass on to sub-fsm */
345 osmo_fsm_inst_dispatch(ip->tpdu_fi, event, data);
346 break;
Eric Wildad1edce2019-11-27 16:51:08 +0100347 case ISO7816_E_XCEIVE_PPS_CMD:
348 osmo_fsm_inst_state_chg(fi, ISO7816_S_WAIT_PPS_RSP, 0, 0);
Eric Wild2f5cdd12019-11-27 18:40:44 +0100349 osmo_fsm_inst_state_chg(ip->pps_fi, PPS_S_PPS_REQ_INIT, 0, 0);
Eric Wildad1edce2019-11-27 16:51:08 +0100350 osmo_fsm_inst_dispatch(ip->pps_fi, event, data);
351 break;
Harald Welte06348362019-05-19 00:45:17 +0200352 default:
353 OSMO_ASSERT(0);
354 }
355}
356
357static void iso7816_3_in_tpdu_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
358{
359 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
360 struct msgb *apdu;
361 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
362
363 switch (event) {
364 case ISO7816_E_RX_SINGLE:
365 case ISO7816_E_RX_COMPL:
366 case ISO7816_E_RX_ERR_IND:
367 case ISO7816_E_TX_COMPL:
368 case ISO7816_E_TX_ERR_IND:
369 /* simply pass this through to the child FSM for the ATR */
370 osmo_fsm_inst_dispatch(ip->tpdu_fi, event, data);
371 break;
372 case ISO7816_E_TPDU_DONE_IND:
373 apdu = data;
374 osmo_fsm_inst_state_chg(fi, ISO7816_S_WAIT_TPDU, 0, 0);
375 /* hand finished TPDU to user */
376 ip->user_cb(fi, event, 0, apdu);
377 break;
Harald Welte1ac9ef92019-10-09 22:20:16 +0200378 case ISO7816_E_WTIME_EXP:
379 /* FIXME: power off? */
380 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
381 break;
Harald Welte06348362019-05-19 00:45:17 +0200382 default:
383 OSMO_ASSERT(0);
384 }
385}
386
387static void iso7816_3_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
388{
389 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
Eric Wild6d3b2fc2020-03-30 03:12:09 +0200390 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
391 struct atr_fsm_priv *atp = get_atr_fsm_priv(ip->atr_fi);
Harald Welte06348362019-05-19 00:45:17 +0200392
393 switch (event) {
Harald Welte06348362019-05-19 00:45:17 +0200394 case ISO7816_E_HW_ERR_IND:
395 case ISO7816_E_CARD_REMOVAL:
396 /* FIXME: power off? */
Eric Wild6d3b2fc2020-03-30 03:12:09 +0200397 if(fi->state == ISO7816_S_WAIT_ATR || fi->state == ISO7816_S_IN_ATR)
398 ip->user_cb(fi, ISO7816_E_ATR_ERR_IND, 0, atp->atr);
Harald Welte06348362019-05-19 00:45:17 +0200399 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
400 break;
401 case ISO7816_E_POWER_DN_IND:
402 case ISO7816_E_RESET_ACT_IND:
403 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
404 break;
405 case ISO7816_E_ABORT_REQ:
406 /* FIXME */
407 break;
408 default:
409 OSMO_ASSERT(0);
410 break;
411 }
412}
413
Eric Wildad1edce2019-11-27 16:51:08 +0100414
415static void iso7816_3_s_wait_pps_rsp_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
416{
Eric Wild2f5cdd12019-11-27 18:40:44 +0100417 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
Eric Wildad1edce2019-11-27 16:51:08 +0100418 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
419 switch (event) {
Harald Welte68bc7f42020-09-02 18:14:30 +0200420 case ISO7816_E_RX_SINGLE:
421 return;
Eric Wildad1edce2019-11-27 16:51:08 +0100422 case ISO7816_E_TX_COMPL:
423 /* Rx of single byte is already enabled by previous card_uart_tx() call */
424 osmo_fsm_inst_state_chg(fi, ISO7816_S_IN_PPS_RSP, 0, 0);
Eric Wild2f5cdd12019-11-27 18:40:44 +0100425 osmo_fsm_inst_dispatch(ip->pps_fi, event, data);
Eric Wildad1edce2019-11-27 16:51:08 +0100426 break;
427 default:
428 OSMO_ASSERT(0);
429 }
430}
431
432static void iso7816_3_s_ins_pps_rsp_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
433{
434 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
435 struct msgb *ppsrsp;
436 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
437
438 switch (event) {
439 case ISO7816_E_RX_SINGLE:
440 case ISO7816_E_WTIME_EXP:
441 /* simply pass this through to the child FSM for the ATR */
442 osmo_fsm_inst_dispatch(ip->pps_fi, event, data);
443 break;
444 case ISO7816_E_PPS_DONE_IND:
445 case ISO7816_E_PPS_FAILED_IND:
446 ppsrsp = data;
447 osmo_fsm_inst_state_chg(fi, ISO7816_S_WAIT_TPDU, 0, 0);
448 /* notify user about PPS result */
449 ip->user_cb(fi, event, 0, ppsrsp);
450 break;
451 case ISO7816_E_RX_ERR_IND:
452 ppsrsp = data;
453 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
454 ip->user_cb(fi, event, 0, ppsrsp);
455 break;
456 default:
457 OSMO_ASSERT(0);
458 }
459}
460
Harald Welte06348362019-05-19 00:45:17 +0200461static const struct osmo_fsm_state iso7816_3_states[] = {
462 [ISO7816_S_RESET] = {
463 .name = "RESET",
Eric Wild9e622dc2019-11-27 14:43:16 +0100464 .in_event_mask = S(ISO7816_E_RESET_REL_IND) |
Eric Wild2f5cdd12019-11-27 18:40:44 +0100465 S(ISO7816_E_POWER_UP_IND) |
Eric Wild9e622dc2019-11-27 14:43:16 +0100466 S(ISO7816_E_PPS_FAILED_IND)|
467 S(ISO7816_E_TPDU_FAILED_IND),
Harald Welte06348362019-05-19 00:45:17 +0200468 .out_state_mask = S(ISO7816_S_WAIT_ATR) |
469 S(ISO7816_S_RESET),
470 .action = iso7816_3_reset_action,
471 .onenter = iso7816_3_reset_onenter,
472 },
473 [ISO7816_S_WAIT_ATR] = {
474 .name = "WAIT_ATR",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200475 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
476 S(ISO7816_E_WTIME_EXP),
Harald Welte06348362019-05-19 00:45:17 +0200477 .out_state_mask = S(ISO7816_S_RESET) |
478 S(ISO7816_S_IN_ATR),
479 .action = iso7816_3_wait_atr_action,
480 },
481 [ISO7816_S_IN_ATR] = {
482 .name = "IN_ATR",
483 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
484 S(ISO7816_E_RX_ERR_IND) |
Harald Welte1ac9ef92019-10-09 22:20:16 +0200485 S(ISO7816_E_ATR_DONE_IND) |
486 S(ISO7816_E_ATR_ERR_IND) |
487 S(ISO7816_E_WTIME_EXP),
Harald Welte06348362019-05-19 00:45:17 +0200488 .out_state_mask = S(ISO7816_S_RESET) |
489 S(ISO7816_S_IN_ATR) |
490 S(ISO7816_S_WAIT_TPDU),
491 .action = iso7816_3_in_atr_action,
492 },
493 [ISO7816_S_WAIT_TPDU] = {
494 .name = "WAIT_TPDU",
Eric Wildad1edce2019-11-27 16:51:08 +0100495 .in_event_mask = S(ISO7816_E_XCEIVE_TPDU_CMD) |
496 S(ISO7816_E_XCEIVE_PPS_CMD),
Harald Welte06348362019-05-19 00:45:17 +0200497 .out_state_mask = S(ISO7816_S_RESET) |
498 S(ISO7816_S_WAIT_TPDU) |
499 S(ISO7816_S_IN_TPDU) |
Eric Wildad1edce2019-11-27 16:51:08 +0100500 S(ISO7816_S_WAIT_PPS_RSP),
Harald Welte06348362019-05-19 00:45:17 +0200501 .action = iso7816_3_wait_tpdu_action,
502 .onenter = iso7816_3_wait_tpdu_onenter,
503 },
504 [ISO7816_S_IN_TPDU] = {
505 .name = "IN_TPDU",
506 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
507 S(ISO7816_E_RX_COMPL) |
508 S(ISO7816_E_TX_COMPL) |
509 S(ISO7816_E_RX_ERR_IND) |
510 S(ISO7816_E_TX_ERR_IND) |
Harald Welte1ac9ef92019-10-09 22:20:16 +0200511 S(ISO7816_E_TPDU_DONE_IND) |
512 S(ISO7816_E_WTIME_EXP),
Harald Welte06348362019-05-19 00:45:17 +0200513 .out_state_mask = S(ISO7816_S_RESET) |
514 S(ISO7816_S_WAIT_TPDU) |
515 S(ISO7816_S_IN_TPDU),
516 .action = iso7816_3_in_tpdu_action,
517 },
Harald Welte06348362019-05-19 00:45:17 +0200518 [ISO7816_S_WAIT_PPS_RSP] = {
519 .name = "WAIT_PPS_RESP",
Eric Wildad1edce2019-11-27 16:51:08 +0100520 .in_event_mask = S(ISO7816_E_TX_COMPL) |
521 S(ISO7816_E_TX_ERR_IND) |
Harald Welte68bc7f42020-09-02 18:14:30 +0200522 S(ISO7816_E_WTIME_EXP) |
523 S(ISO7816_E_RX_SINGLE),
Harald Welte06348362019-05-19 00:45:17 +0200524 .out_state_mask = S(ISO7816_S_RESET) |
525 S(ISO7816_S_WAIT_TPDU) |
526 S(ISO7816_S_WAIT_PPS_RSP) |
527 S(ISO7816_S_IN_PPS_RSP),
Eric Wildad1edce2019-11-27 16:51:08 +0100528 .action = iso7816_3_s_wait_pps_rsp_action,
Harald Welte06348362019-05-19 00:45:17 +0200529 },
530 [ISO7816_S_IN_PPS_RSP] = {
531 .name = "IN_PPS_RESP",
Eric Wildad1edce2019-11-27 16:51:08 +0100532 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
533 S(ISO7816_E_RX_COMPL) |
534 S(ISO7816_E_RX_ERR_IND) |
535 S(ISO7816_E_PPS_DONE_IND) |
536 S(ISO7816_E_PPS_FAILED_IND) |
537 S(ISO7816_E_WTIME_EXP),
Harald Welte06348362019-05-19 00:45:17 +0200538 .out_state_mask = S(ISO7816_S_RESET) |
539 S(ISO7816_S_WAIT_TPDU) |
540 S(ISO7816_S_IN_PPS_RSP),
Eric Wildad1edce2019-11-27 16:51:08 +0100541 .action = iso7816_3_s_ins_pps_rsp_action,
Harald Welte06348362019-05-19 00:45:17 +0200542 },
543};
544static struct osmo_fsm iso7816_3_fsm = {
545 .name = "ISO7816-3",
546 .states = iso7816_3_states,
547 .num_states = ARRAY_SIZE(iso7816_3_states),
548 .log_subsys = DISO7816,
549 .event_names = iso7816_3_event_names,
550 .allstate_action = iso7816_3_allstate_action,
Harald Welte1ac9ef92019-10-09 22:20:16 +0200551 .allstate_event_mask = S(ISO7816_E_CARD_REMOVAL) |
Harald Welte06348362019-05-19 00:45:17 +0200552 S(ISO7816_E_POWER_DN_IND) |
553 S(ISO7816_E_RESET_ACT_IND) |
554 S(ISO7816_E_HW_ERR_IND) |
555 S(ISO7816_E_ABORT_REQ),
556};
557
558/***********************************************************************
559 * ATR FSM
560 ***********************************************************************/
561
Eric Wild6d3b2fc2020-03-30 03:12:09 +0200562/* type-safe method to obtain atr_fsm_priv from fi */
563static struct atr_fsm_priv *get_atr_fsm_priv(struct osmo_fsm_inst *fi)
564{
565 OSMO_ASSERT(fi);
566 OSMO_ASSERT(fi->fsm == &atr_fsm);
567 return (struct atr_fsm_priv *) fi->priv;
568}
Harald Welte06348362019-05-19 00:45:17 +0200569
570/* obtain the [software] guard time in milli-seconds from the atr fsm_inst */
571static uint32_t atr_fi_gt_ms(struct osmo_fsm_inst *fi)
572{
573 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
574 struct iso7816_3_priv *ip;
575
576 OSMO_ASSERT(fi->fsm == &atr_fsm);
577 OSMO_ASSERT(parent_fi);
578 ip = get_iso7816_3_priv(parent_fi);
579
580 return ip->guard_time_ms;
581}
582
583/* obtain the 'byte' parmeter of an ISO7816_E_RX event */
584static uint8_t get_rx_byte_evt(struct osmo_fsm_inst *fi, void *data)
585{
586 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
587 uint8_t byte = *(uint8_t *)data;
588
589 /* apply inverse convention */
590 if (ip->convention_convert)
591 byte = convention_convert_lut[byte];
592
593 return byte;
594}
595
596/* append a single byte to the ATR */
597static int atr_append_byte(struct osmo_fsm_inst *fi, uint8_t byte)
598{
Eric Wild6d3b2fc2020-03-30 03:12:09 +0200599 struct atr_fsm_priv *atp = get_atr_fsm_priv(fi);
Harald Welte06348362019-05-19 00:45:17 +0200600
601 if (!msgb_tailroom(atp->atr)) {
602 LOGPFSML(fi, LOGL_ERROR, "ATR overflow !?!");
603 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_SW_ERR_IND, NULL);
604 return -1;
605 }
606 msgb_put_u8(atp->atr, byte);
607 return 0;
608}
609
610static void atr_wait_ts_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
611{
Eric Wild6d3b2fc2020-03-30 03:12:09 +0200612 struct atr_fsm_priv *atp = get_atr_fsm_priv(fi);
Harald Welte06348362019-05-19 00:45:17 +0200613
614 /* reset state to its initial value */
615 atp->hist_len = 0;
616 atp->y = 0;
617 atp->i = 0;
618 if (!atp->atr)
619 atp->atr = msgb_alloc_c(fi, 33, "ATR"); /* TS + 32 chars */
620 else
621 msgb_reset(atp->atr);
622 atp->computed_checksum = 0;
623 atp->protocol_support = 0;
624}
625
626static void atr_wait_ts_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
627{
Eric Wild6d3b2fc2020-03-30 03:12:09 +0200628 struct atr_fsm_priv *atp = get_atr_fsm_priv(fi);
Harald Welte06348362019-05-19 00:45:17 +0200629 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
630 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
631 uint8_t byte;
632
633 switch (event) {
634 case ISO7816_E_RX_SINGLE:
635 OSMO_ASSERT(msgb_length(atp->atr) == 0);
636restart:
637 byte = get_rx_byte_evt(parent_fi, data);
638 LOGPFSML(fi, LOGL_DEBUG, "RX byte '%02x'\n", byte);
639 switch (byte) {
640 case 0x23:
641 /* direct convention used, but decoded using inverse
642 * convention (a parity error should also have occurred) */
643 /* fall-through */
644 case 0x30:
645 /* inverse convention used, but decoded using direct
646 * convention (a parity error should also have occurred) */
647 ip->convention_convert = !ip->convention_convert;
648 goto restart;
649 break;
650 case 0x3b: /* direct convention used and correctly decoded */
651 /* fall-through */
652 case 0x3f: /* inverse convention used and correctly decoded */
653 atr_append_byte(fi, byte);
654 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_T0, atr_fi_gt_ms(fi), T_GUARD);
655 break;
656 default:
657 LOGPFSML(fi, LOGL_ERROR, "Invalid TS received: 0x%02X\n", byte);
658 /* FIXME: somehow indiicate to user */
659 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_SW_ERR_IND, NULL);
660 break;
661 }
662 atp->i = 0; /* first interface byte sub-group is coming (T0 is kind of TD0) */
663 break;
Harald Welte1ac9ef92019-10-09 22:20:16 +0200664 case ISO7816_E_WTIME_EXP:
665 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_ATR_ERR_IND, NULL);
666 break;
Harald Welte06348362019-05-19 00:45:17 +0200667 default:
668 OSMO_ASSERT(0);
669 }
670}
671
672static void atr_wait_tX_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
673{
Eric Wild6d3b2fc2020-03-30 03:12:09 +0200674 struct atr_fsm_priv *atp = get_atr_fsm_priv(fi);
Harald Welte06348362019-05-19 00:45:17 +0200675 uint32_t guard_time_ms = atr_fi_gt_ms(fi);
676 uint8_t byte;
677
678 switch (event) {
679 case ISO7816_E_RX_SINGLE:
680 byte = get_rx_byte_evt(fi->proc.parent, data);
681 LOGPFSML(fi, LOGL_DEBUG, "RX byte '%02x'\n", byte);
682 atr_append_byte(fi, byte);
683 switch (fi->state) {
684 case ATR_S_WAIT_T0: /* see ISO/IEC 7816-3:2006 section 8.2.2 */
685 case ATR_S_WAIT_TD: /* see ISO/IEC 7816-3:2006 section 8.2.3 */
686 if (fi->state == ATR_S_WAIT_T0) {
687 /* save number of hist. bytes */
688 atp->hist_len = (byte & 0x0f);
689 } else {
690 /* remember supported protocol to know if TCK will be present */
691 atp->protocol_support |= (1<<(byte & 0x0f));
692 }
693 atp->y = (byte & 0xf0); /* remember incoming interface bytes */
694 atp->i++;
695 if (atp->y & 0x10) {
696 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_TA, guard_time_ms, T_GUARD);
697 break;
698 }
699 /* fall-through */
700 case ATR_S_WAIT_TA: /* see ISO/IEC 7816-3:2006 section 8.2.3 */
701 if (atp->y & 0x20) {
702 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_TB, guard_time_ms, T_GUARD);
703 break;
704 }
705 /* fall-through */
706 case ATR_S_WAIT_TB: /* see ISO/IEC 7816-3:2006 section 8.2.3 */
707 if (atp->y & 0x40) {
708 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_TC, guard_time_ms, T_GUARD);
709 break;
710 }
711 /* fall-through */
712 case ATR_S_WAIT_TC: /* see ISO/IEC 7816-3:2006 section 8.2.3 */
713 if (atp->y & 0x80) {
714 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_TD, guard_time_ms, T_GUARD);
715 break;
716 } else if (atp->hist_len) {
717 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_HIST, guard_time_ms, T_GUARD);
718 break;
719 }
720 /* fall-through */
721 case ATR_S_WAIT_HIST: /* see ISO/IEC 7816-3:2006 section 8.2.4 */
722 if (atp->hist_len)
723 atp->hist_len--;
724 if (atp->hist_len == 0) {
725 if (atp->protocol_support > 1) {
726 /* wait for check byte */
727 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_TCK,
728 guard_time_ms, T_GUARD);
729 break;
Eric Wild70d212d2019-11-27 15:05:09 +0100730 } else {
731 /* no TCK present, ATR complete; notify parent */
732 osmo_fsm_inst_state_chg(fi, ATR_S_DONE, 0, 0);
733 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_ATR_DONE_IND, atp->atr);
Harald Welte06348362019-05-19 00:45:17 +0200734 }
735 } else {
736 break;
737 }
738 /* fall-through */
739 case ATR_S_WAIT_TCK: /* see ISO/IEC 7816-3:2006 section 8.2.5 */
740 /* verify checksum if present */
741 if (fi->state == ATR_S_WAIT_TCK) {
742 uint8_t ui;
743 uint8_t *atr = msgb_data(atp->atr);
744 LOGPFSML(fi, LOGL_INFO, "Complete ATR: %s\n", msgb_hexdump(atp->atr));
745 for (ui = 1; ui < msgb_length(atp->atr)-1; ui++) {
746 atp->computed_checksum ^= atr[ui];
747 }
748 if (atp->computed_checksum != byte) {
749 /* checkum error. report to user? */
750 LOGPFSML(fi, LOGL_ERROR,
751 "computed checksum %02x doesn't match TCK=%02x\n",
752 atp->computed_checksum, byte);
753 }
754 /* ATR complete; notify parent */
755 osmo_fsm_inst_state_chg(fi, ATR_S_DONE, 0, 0);
756 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_ATR_DONE_IND, atp->atr);
757 }
758 break;
759 default:
760 OSMO_ASSERT(0);
761 }
762 break;
Harald Welte1ac9ef92019-10-09 22:20:16 +0200763 case ISO7816_E_WTIME_EXP:
764 switch (fi->state) {
765 case ATR_S_WAIT_HIST:
766 case ATR_S_WAIT_TCK:
767 /* Some cards have an ATR with long indication of historical bytes */
768 /* FIXME: should we check the checksum? */
769 osmo_fsm_inst_state_chg(fi, ATR_S_DONE, 0, 0);
770 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_ATR_DONE_IND, atp->atr);
771 break;
772 default:
773 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_ATR_ERR_IND, NULL);
774 break;
775 }
776 break;
Harald Welte06348362019-05-19 00:45:17 +0200777 default:
778 OSMO_ASSERT(0);
779 }
780}
781
Eric Wild2f5cdd12019-11-27 18:40:44 +0100782static void atr_done_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
783{
784 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
785 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
786
787 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 0);
788}
789
Harald Welte06348362019-05-19 00:45:17 +0200790static const struct osmo_fsm_state atr_states[] = {
791 [ATR_S_WAIT_TS] = {
792 .name = "WAIT_TS",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200793 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
794 S(ISO7816_E_WTIME_EXP),
Harald Welte06348362019-05-19 00:45:17 +0200795 .out_state_mask = S(ATR_S_WAIT_TS) |
796 S(ATR_S_WAIT_T0),
797 .action = atr_wait_ts_action,
798 .onenter = atr_wait_ts_onenter,
799 },
800 [ATR_S_WAIT_T0] = {
801 .name = "WAIT_T0",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200802 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
803 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200804 .out_state_mask = S(ATR_S_WAIT_TS) |
805 S(ATR_S_WAIT_TA) |
Harald Welte06348362019-05-19 00:45:17 +0200806 S(ATR_S_WAIT_TB) |
807 S(ATR_S_WAIT_TC) |
808 S(ATR_S_WAIT_TD) |
809 S(ATR_S_WAIT_HIST) |
810 S(ATR_S_WAIT_TCK) |
811 S(ATR_S_WAIT_T0),
812 .action = atr_wait_tX_action,
813 },
814 [ATR_S_WAIT_TA] = {
815 .name = "WAIT_TA",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200816 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
817 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200818 .out_state_mask = S(ATR_S_WAIT_TS) |
819 S(ATR_S_WAIT_TB) |
Harald Welte06348362019-05-19 00:45:17 +0200820 S(ATR_S_WAIT_TC) |
821 S(ATR_S_WAIT_TD) |
822 S(ATR_S_WAIT_HIST) |
823 S(ATR_S_WAIT_TCK) |
824 S(ATR_S_WAIT_T0),
825 .action = atr_wait_tX_action,
826 },
827 [ATR_S_WAIT_TB] = {
828 .name = "WAIT_TB",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200829 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
830 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200831 .out_state_mask = S(ATR_S_WAIT_TS) |
832 S(ATR_S_WAIT_TC) |
Harald Welte06348362019-05-19 00:45:17 +0200833 S(ATR_S_WAIT_TD) |
834 S(ATR_S_WAIT_HIST) |
835 S(ATR_S_WAIT_TCK) |
836 S(ATR_S_WAIT_T0),
837 .action = atr_wait_tX_action,
838 },
839 [ATR_S_WAIT_TC] = {
840 .name = "WAIT_TC",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200841 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
842 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200843 .out_state_mask = S(ATR_S_WAIT_TS) |
844 S(ATR_S_WAIT_TD) |
Harald Welte06348362019-05-19 00:45:17 +0200845 S(ATR_S_WAIT_HIST) |
846 S(ATR_S_WAIT_TCK) |
847 S(ATR_S_WAIT_T0),
848 .action = atr_wait_tX_action,
849 },
850 [ATR_S_WAIT_TD] = {
851 .name = "WAIT_TD",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200852 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
853 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200854 .out_state_mask = S(ATR_S_WAIT_TS) |
855 S(ATR_S_WAIT_TA) |
Harald Welte06348362019-05-19 00:45:17 +0200856 S(ATR_S_WAIT_TB) |
857 S(ATR_S_WAIT_TC) |
858 S(ATR_S_WAIT_TD) |
859 S(ATR_S_WAIT_HIST) |
860 S(ATR_S_WAIT_TCK) |
861 S(ATR_S_WAIT_T0),
862 .action = atr_wait_tX_action,
863 },
864 [ATR_S_WAIT_HIST] = {
865 .name = "WAIT_HIST",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200866 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
867 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200868 .out_state_mask = S(ATR_S_WAIT_TS) |
869 S(ATR_S_WAIT_TCK) |
Harald Welte1ac9ef92019-10-09 22:20:16 +0200870 S(ATR_S_WAIT_T0) |
871 S(ATR_S_DONE),
Harald Welte06348362019-05-19 00:45:17 +0200872 .action = atr_wait_tX_action,
873 },
874 [ATR_S_WAIT_TCK] = {
875 .name = "WAIT_TCK",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200876 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
877 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200878 .out_state_mask = S(ATR_S_WAIT_TS) |
879 S(ATR_S_DONE),
Harald Welte06348362019-05-19 00:45:17 +0200880 .action = atr_wait_tX_action,
881 },
882 [ATR_S_DONE] = {
883 .name = "DONE",
884 .in_event_mask = 0,
Harald Welte704d99a2019-10-09 21:39:27 +0200885 .out_state_mask = S(ATR_S_WAIT_TS),
Eric Wild2f5cdd12019-11-27 18:40:44 +0100886 .onenter = atr_done_onenter
Harald Welte06348362019-05-19 00:45:17 +0200887 },
888
889};
890static struct osmo_fsm atr_fsm = {
891 .name = "ATR",
892 .states = atr_states,
893 .num_states = ARRAY_SIZE(atr_states),
894 .log_subsys = DATR,
895 .event_names = iso7816_3_event_names,
896};
897
898/***********************************************************************
899 * PPS FSM
900 ***********************************************************************/
Eric Wildad1edce2019-11-27 16:51:08 +0100901struct pps_fsm_priv {
902 struct msgb* tx_cmd;
903 struct msgb* rx_cmd;
904 uint8_t pps0_recv;
905};
906
Eric Wild2f5cdd12019-11-27 18:40:44 +0100907static void pps_s_pps_req_init_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
Eric Wildad1edce2019-11-27 16:51:08 +0100908{
909 struct pps_fsm_priv *atp = fi->priv;
910
911 if (!atp->rx_cmd)
Eric Wild9e622dc2019-11-27 14:43:16 +0100912 atp->rx_cmd = msgb_alloc_c(fi, 6, "PPSRSP"); /* at most 6 */
Eric Wildad1edce2019-11-27 16:51:08 +0100913 else
914 msgb_reset(atp->rx_cmd);
Eric Wild9e622dc2019-11-27 14:43:16 +0100915
916 /* notify in case card got pulled out */
Eric Wild759a6462019-11-11 14:22:52 +0100917 if (atp->tx_cmd && old_state != PPS_S_DONE){
Eric Wild9e622dc2019-11-27 14:43:16 +0100918 osmo_fsm_inst_dispatch(fi->proc.parent,
919 ISO7816_E_PPS_FAILED_IND, atp->tx_cmd);
920 atp->tx_cmd = 0;
921 }
Eric Wildad1edce2019-11-27 16:51:08 +0100922}
923
Eric Wild2f5cdd12019-11-27 18:40:44 +0100924static void pps_s_pps_req_init_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
Eric Wildad1edce2019-11-27 16:51:08 +0100925{
926 struct pps_fsm_priv *atp = fi->priv;
Eric Wildad1edce2019-11-27 16:51:08 +0100927 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
928 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
929
Eric Wild9e622dc2019-11-27 14:43:16 +0100930 /* keep the buffer to compare it with the received response */
931 atp->tx_cmd = data;
932
Eric Wildad1edce2019-11-27 16:51:08 +0100933 switch (event) {
934 case ISO7816_E_XCEIVE_PPS_CMD:
Eric Wild2f5cdd12019-11-27 18:40:44 +0100935 osmo_fsm_inst_state_chg(fi, PPS_S_TX_PPS_REQ, 0, 0);
936 card_uart_set_rx_threshold(ip->uart, 1);
Eric Wildad1edce2019-11-27 16:51:08 +0100937 card_uart_tx(ip->uart, msgb_data(data), msgb_length(data), true);
938 break;
939 default:
940 OSMO_ASSERT(0);
941 }
942}
943
Eric Wild2f5cdd12019-11-27 18:40:44 +0100944static void pps_s_tx_pps_req_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
945{
946 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
947 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
948
949 switch (event) {
950 case ISO7816_E_TX_COMPL:
951 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 6);
952 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPSX, 0, 0);
953 break;
954 default:
955 OSMO_ASSERT(0);
956 }
957}
958
959
960
961
Eric Wildad1edce2019-11-27 16:51:08 +0100962static void pps_wait_pX_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
963{
964 struct pps_fsm_priv *atp = fi->priv;
Eric Wild2f5cdd12019-11-27 18:40:44 +0100965 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
966 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
Eric Wildad1edce2019-11-27 16:51:08 +0100967 uint8_t byte;
968
969 switch (event) {
970 case ISO7816_E_RX_SINGLE:
971 byte = get_rx_byte_evt(fi->proc.parent, data);
972 LOGPFSML(fi, LOGL_DEBUG, "RX byte '%02x'\n", byte);
973 msgb_put_u8(atp->rx_cmd, byte);
974 switch (fi->state) {
Eric Wild2f5cdd12019-11-27 18:40:44 +0100975 case PPS_S_WAIT_PPSX:
Eric Wildad1edce2019-11-27 16:51:08 +0100976 if (byte == 0xff)
977 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPS0, 0, 0);
978 break;
979 case PPS_S_WAIT_PPS0:
980 atp->pps0_recv = byte;
981 if(atp->pps0_recv & (1 << 4)) {
982 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPS1, 0, 0);
983 break;
984 } else if (atp->pps0_recv & (1 << 5)) {
985 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPS2, 0, 0);
986 break;
987 } else if (atp->pps0_recv & (1 << 6)) {
988 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPS3, 0, 0);
989 break;
990 }
991 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PCK, 0, 0);
992 break;
993 case PPS_S_WAIT_PPS1:
994 if (atp->pps0_recv & (1 << 5)) {
995 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPS2, 0, 0);
996 break;
997 } else if (atp->pps0_recv & (1 << 6)) {
998 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPS3, 0, 0);
999 break;
1000 }
1001 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PCK, 0, 0);
1002 break;
1003 case PPS_S_WAIT_PPS2:
1004 if (atp->pps0_recv & (1 << 6)) {
1005 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPS3, 0, 0);
1006 break;
1007 }
1008 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PCK, 0, 0);
1009 break;
1010 case PPS_S_WAIT_PPS3:
1011 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PCK, 0, 0);
1012 break;
1013 case PPS_S_WAIT_PCK:
1014 /* verify checksum if present */
1015 if (fi->state == PPS_S_WAIT_PCK) {
1016 uint8_t *pps_received = msgb_data(atp->rx_cmd);
1017 uint8_t *pps_sent = msgb_data(atp->tx_cmd);
1018
Eric Wild2f5cdd12019-11-27 18:40:44 +01001019 osmo_fsm_inst_state_chg(fi, PPS_S_DONE, 0, 0);
Eric Wildad1edce2019-11-27 16:51:08 +01001020
1021 /* pps was successful if response equals request
1022 * rx buffer stays with the fsm, tx buffer gets handed back and freed
1023 * by the cb */
1024 if (msgb_length(atp->rx_cmd) == msgb_length(atp->tx_cmd) &&
1025 !memcmp(pps_received, pps_sent, msgb_length(atp->rx_cmd))) {
1026 osmo_fsm_inst_dispatch(fi->proc.parent,
1027 ISO7816_E_PPS_DONE_IND, atp->tx_cmd);
1028 } else {
1029 osmo_fsm_inst_dispatch(fi->proc.parent,
1030 ISO7816_E_PPS_FAILED_IND, atp->tx_cmd);
1031 }
Eric Wild9e622dc2019-11-27 14:43:16 +01001032 /* ownership transfer */
1033 atp->tx_cmd = 0;
Eric Wildad1edce2019-11-27 16:51:08 +01001034 }
1035 break;
1036 default:
1037 OSMO_ASSERT(0);
1038 }
1039 break;
1040 case ISO7816_E_WTIME_EXP:
Eric Wild2f5cdd12019-11-27 18:40:44 +01001041 osmo_fsm_inst_state_chg(fi, PPS_S_DONE, 0, 0);
Eric Wildad1edce2019-11-27 16:51:08 +01001042 /* FIXME: timeout handling if no pps supported ? */
1043 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_RX_ERR_IND, NULL);
1044 break;
1045 default:
1046 OSMO_ASSERT(0);
1047 }
1048}
1049
Harald Welte06348362019-05-19 00:45:17 +02001050
Eric Wild2f5cdd12019-11-27 18:40:44 +01001051static void pps_s_done_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
1052{
1053 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1054 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1055
1056 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 0);
1057}
1058
1059
Harald Welte06348362019-05-19 00:45:17 +02001060static const struct osmo_fsm_state pps_states[] = {
Eric Wild2f5cdd12019-11-27 18:40:44 +01001061 [PPS_S_PPS_REQ_INIT] = {
1062 .name = "INIT",
Eric Wildad1edce2019-11-27 16:51:08 +01001063 .in_event_mask = S(ISO7816_E_XCEIVE_PPS_CMD) |
1064 S(ISO7816_E_WTIME_EXP),
Eric Wild2f5cdd12019-11-27 18:40:44 +01001065 .out_state_mask = S(PPS_S_PPS_REQ_INIT) |
1066 S(PPS_S_TX_PPS_REQ),
1067 .action = pps_s_pps_req_init_action,
1068 .onenter = pps_s_pps_req_init_onenter,
Eric Wildad1edce2019-11-27 16:51:08 +01001069 },
Eric Wild2f5cdd12019-11-27 18:40:44 +01001070 [PPS_S_TX_PPS_REQ] = {
1071 .name = "TX_PPS_REQ",
1072 .in_event_mask = S(ISO7816_E_TX_COMPL),
1073 .out_state_mask = S(PPS_S_WAIT_PPSX),
1074 .action = pps_s_tx_pps_req_action,
1075 },
1076 [PPS_S_WAIT_PPSX] = {
Harald Welte06348362019-05-19 00:45:17 +02001077 .name = "WAIT_PPSS",
Eric Wildad1edce2019-11-27 16:51:08 +01001078 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
1079 S(ISO7816_E_WTIME_EXP),
1080 .out_state_mask = S(PPS_S_WAIT_PPS0) |
Eric Wild2f5cdd12019-11-27 18:40:44 +01001081 S(PPS_S_WAIT_PPSX),
Eric Wildad1edce2019-11-27 16:51:08 +01001082 .action = pps_wait_pX_action,
Harald Welte06348362019-05-19 00:45:17 +02001083 },
1084 [PPS_S_WAIT_PPS0] = {
1085 .name = "WAIT_PPS0",
Eric Wildad1edce2019-11-27 16:51:08 +01001086 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
1087 S(ISO7816_E_WTIME_EXP),
1088 .out_state_mask = S(PPS_S_WAIT_PPS1) |
1089 S(PPS_S_WAIT_PPS2) |
1090 S(PPS_S_WAIT_PPS3) |
1091 S(PPS_S_WAIT_PCK),
1092 .action = pps_wait_pX_action,
Harald Welte06348362019-05-19 00:45:17 +02001093 },
1094 [PPS_S_WAIT_PPS1] = {
1095 .name = "WAIT_PPS1",
Eric Wildad1edce2019-11-27 16:51:08 +01001096 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
1097 S(ISO7816_E_WTIME_EXP),
1098 .out_state_mask = S(PPS_S_WAIT_PPS2) |
1099 S(PPS_S_WAIT_PPS3) |
1100 S(PPS_S_WAIT_PCK),
1101 .action = pps_wait_pX_action,
Harald Welte06348362019-05-19 00:45:17 +02001102 },
1103 [PPS_S_WAIT_PPS2] = {
1104 .name = "WAIT_PPS2",
Eric Wildad1edce2019-11-27 16:51:08 +01001105 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
1106 S(ISO7816_E_WTIME_EXP),
1107 .out_state_mask = S(PPS_S_WAIT_PPS3) |
1108 S(PPS_S_WAIT_PCK),
1109 .action = pps_wait_pX_action,
Harald Welte06348362019-05-19 00:45:17 +02001110 },
1111 [PPS_S_WAIT_PPS3] = {
1112 .name = "WAIT_PPS3",
Eric Wildad1edce2019-11-27 16:51:08 +01001113 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
1114 S(ISO7816_E_WTIME_EXP),
1115 .out_state_mask = S(PPS_S_WAIT_PCK),
1116 .action = pps_wait_pX_action,
Harald Welte06348362019-05-19 00:45:17 +02001117 },
1118 [PPS_S_WAIT_PCK] = {
1119 .name = "WAIT_PCK",
Eric Wildad1edce2019-11-27 16:51:08 +01001120 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
1121 S(ISO7816_E_WTIME_EXP),
Eric Wild2f5cdd12019-11-27 18:40:44 +01001122 .out_state_mask = S(PPS_S_DONE),
Eric Wildad1edce2019-11-27 16:51:08 +01001123 .action = pps_wait_pX_action,
Harald Welte06348362019-05-19 00:45:17 +02001124 },
Eric Wild2f5cdd12019-11-27 18:40:44 +01001125 [PPS_S_DONE] = {
1126 .name = "DONE",
Eric Wildad1edce2019-11-27 16:51:08 +01001127 .in_event_mask = 0,
Eric Wild2f5cdd12019-11-27 18:40:44 +01001128 .out_state_mask = S(PPS_S_PPS_REQ_INIT),
1129 .action = NULL,
1130 .onenter = pps_s_done_onenter,
Harald Welte06348362019-05-19 00:45:17 +02001131 },
1132};
1133
1134static struct osmo_fsm pps_fsm = {
1135 .name = "PPS",
1136 .states = pps_states,
1137 .num_states = ARRAY_SIZE(pps_states),
1138 .log_subsys = DPPS,
1139 .event_names = iso7816_3_event_names,
1140};
1141
1142/***********************************************************************
1143 * TPDU FSM
1144 ***********************************************************************/
1145
Harald Welte65087832019-10-01 09:16:49 +02001146/* In this FSM weu use the msgb for the TPDU as follows:
1147 * - 5-byte TPDU header is at msg->data
1148 * - COMMAND TPDU:
1149 * - command bytes are provided after the header at msg->l2h
1150 * - in case of incremental transmission, l3h points to next to-be-transmitted byte
1151 * - RESPONSE TPDU:
1152 * - any response bytes are stored after the header at msg->l2h
1153 */
1154
1155static inline struct osim_apdu_cmd_hdr *msgb_tpdu_hdr(struct msgb *msg) {
1156 return (struct osim_apdu_cmd_hdr *) msgb_data(msg);
1157}
1158
Harald Welte06348362019-05-19 00:45:17 +02001159struct tpdu_fsm_priv {
1160 struct msgb *tpdu;
Harald Welte65087832019-10-01 09:16:49 +02001161 bool is_command; /* is this a command TPDU (true) or a response (false) */
Harald Welte06348362019-05-19 00:45:17 +02001162};
1163
1164/* type-safe method to obtain iso7816_3_priv from fi */
1165static struct tpdu_fsm_priv *get_tpdu_fsm_priv(struct osmo_fsm_inst *fi)
1166{
1167 OSMO_ASSERT(fi);
1168 OSMO_ASSERT(fi->fsm == &tpdu_fsm);
1169 return (struct tpdu_fsm_priv *) fi->priv;
1170}
1171
Eric Wild9e622dc2019-11-27 14:43:16 +01001172static void tpdu_s_init_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
1173{
1174 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
1175
1176 /* notify in case card got pulled out */
Eric Wild759a6462019-11-11 14:22:52 +01001177 if (tfp->tpdu && old_state != TPDU_S_DONE){
Eric Wild9e622dc2019-11-27 14:43:16 +01001178 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_TPDU_FAILED_IND, tfp->tpdu);
1179 tfp->tpdu = 0;
1180 }
1181}
Harald Welte06348362019-05-19 00:45:17 +02001182
1183static void tpdu_s_init_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1184{
1185 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
1186 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1187 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1188 struct osim_apdu_cmd_hdr *tpduh;
1189
1190 switch (event) {
1191 case ISO7816_E_XCEIVE_TPDU_CMD:
1192 /* start transmission of a TPDU by sending the 5-byte header */
1193 tfp->tpdu = (struct msgb *)data;
1194 OSMO_ASSERT(msgb_length(tfp->tpdu) >= sizeof(*tpduh));
Harald Welte43281fe2020-07-30 20:29:02 +02001195 /* l2h = after the 5byte header */
Harald Welte06348362019-05-19 00:45:17 +02001196 tfp->tpdu->l2h = msgb_data(tfp->tpdu) + sizeof(*tpduh);
Harald Welte43281fe2020-07-30 20:29:02 +02001197 /* l4h = where we start to receive from the card */
1198 tfp->tpdu->l4h = msgb_l2(tfp->tpdu) + msgb_l2len(tfp->tpdu);
Harald Welte65087832019-10-01 09:16:49 +02001199 if (msgb_l2len(tfp->tpdu)) {
1200 tfp->is_command = true;
Harald Welte43281fe2020-07-30 20:29:02 +02001201 /* l3h = used as 'next byte to write' pointer */
Harald Welte65087832019-10-01 09:16:49 +02001202 tfp->tpdu->l3h = tfp->tpdu->l2h; /* next tx byte == first byte of body */
1203 } else
1204 tfp->is_command = false;
1205 tpduh = msgb_tpdu_hdr(tfp->tpdu);
1206 LOGPFSML(fi, LOGL_DEBUG, "Transmitting %s TPDU header %s via UART\n",
1207 tfp->is_command ? "COMMAND" : "RESPONSE",
Harald Welte06348362019-05-19 00:45:17 +02001208 osmo_hexdump_nospc((uint8_t *) tpduh, sizeof(*tpduh)));
1209 osmo_fsm_inst_state_chg(fi, TPDU_S_TX_HDR, 0, 0);
Harald Welte6603d952019-10-09 20:50:13 +02001210 card_uart_tx(ip->uart, (uint8_t *) tpduh, sizeof(*tpduh), true);
Harald Welte06348362019-05-19 00:45:17 +02001211 break;
1212 default:
1213 OSMO_ASSERT(0);
1214 }
1215}
1216
Eric Wilde84a5712019-11-28 17:30:30 +01001217
Harald Welte06348362019-05-19 00:45:17 +02001218static void tpdu_s_tx_hdr_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1219{
Eric Wild2f5cdd12019-11-27 18:40:44 +01001220 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1221 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
Harald Welte06348362019-05-19 00:45:17 +02001222 OSMO_ASSERT(fi->fsm == &tpdu_fsm);
1223 switch (event) {
Harald Welte68bc7f42020-09-02 18:14:30 +02001224 case ISO7816_E_RX_SINGLE:
1225 return;
Harald Welte06348362019-05-19 00:45:17 +02001226 case ISO7816_E_TX_COMPL:
Eric Wild2f5cdd12019-11-27 18:40:44 +01001227
1228 card_uart_set_rx_threshold(ip->uart, 1);
1229 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 1);
Harald Welte06348362019-05-19 00:45:17 +02001230 /* Rx of single byte is already enabled by previous card_uart_tx() call */
1231 osmo_fsm_inst_state_chg(fi, TPDU_S_PROCEDURE, 0, 0);
1232 break;
1233 default:
1234 OSMO_ASSERT(0);
1235 }
1236}
1237
1238
Eric Wilde84a5712019-11-28 17:30:30 +01001239#if 0
1240#include <hal_gpio.h>
1241#endif
Harald Welte06348362019-05-19 00:45:17 +02001242static void tpdu_s_procedure_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1243{
1244 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
Harald Welte65087832019-10-01 09:16:49 +02001245 struct osim_apdu_cmd_hdr *tpduh = msgb_tpdu_hdr(tfp->tpdu);
Harald Welte06348362019-05-19 00:45:17 +02001246 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1247 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1248 uint8_t byte;
1249
1250 switch (event) {
1251 case ISO7816_E_RX_SINGLE:
1252 byte = get_rx_byte_evt(fi->proc.parent, data);
1253 LOGPFSML(fi, LOGL_DEBUG, "Received 0x%02x from UART\n", byte);
1254 if (byte == 0x60) {
1255 /* NULL: wait for another procedure byte */
Eric Wild2f5cdd12019-11-27 18:40:44 +01001256 card_uart_set_rx_threshold(ip->uart, 1);
1257 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 1);
Harald Welte06348362019-05-19 00:45:17 +02001258 osmo_fsm_inst_state_chg(fi, TPDU_S_PROCEDURE, 0, 0);
1259 } else if ((byte >= 0x60 && byte <= 0x6f) || (byte >= 0x90 && byte <= 0x9f)) {
1260 //msgb_apdu_sw(tfp->apdu) = byte << 8;
Harald Welte08c8e1c2020-09-02 20:02:45 +02001261 msgb_put_u8(tfp->tpdu, byte);
Harald Welte06348362019-05-19 00:45:17 +02001262 /* receive second SW byte (SW2) */
Eric Wild2f5cdd12019-11-27 18:40:44 +01001263 card_uart_set_rx_threshold(ip->uart, 1);
1264 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 1);
Harald Welte06348362019-05-19 00:45:17 +02001265 osmo_fsm_inst_state_chg(fi, TPDU_S_SW2, 0, 0);
1266 break;
1267 } else if (byte == tpduh->ins) {
Harald Welte65087832019-10-01 09:16:49 +02001268 if (tfp->is_command) {
Harald Welte06348362019-05-19 00:45:17 +02001269 /* transmit all remaining bytes */
Eric Wild9a2279c2019-11-27 18:30:18 +01001270#if 0
1271// rx -> tx delay
1272 gpio_set_pin_level(PIN_PB12, true);
1273 delay_us(1);
1274 gpio_set_pin_level(PIN_PB12, false);
1275#endif
Harald Welte6603d952019-10-09 20:50:13 +02001276 card_uart_tx(ip->uart, msgb_l2(tfp->tpdu), msgb_l2len(tfp->tpdu), true);
Harald Welte06348362019-05-19 00:45:17 +02001277 osmo_fsm_inst_state_chg(fi, TPDU_S_TX_REMAINING, 0, 0);
1278 } else {
Eric Wild172b4432020-09-10 19:33:51 +02001279 /* 7816-3 10.3.2 special case outgoing transfer 0 means 256 */
1280 int len_expected = tpduh->p3 == 0 ? 256 : tpduh->p3;
1281
1282 card_uart_set_rx_threshold(ip->uart, len_expected);
1283 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, len_expected);
Harald Welte498e9e72020-09-02 18:10:13 +02001284 /* if the expected length is only one byte, cuart will issue
1285 * TPDU_S_RX_SINGLE instead of TPDU_S_RX_REMAINING (OS#4741) */
Eric Wild172b4432020-09-10 19:33:51 +02001286 if (len_expected == 1)
Harald Welte498e9e72020-09-02 18:10:13 +02001287 osmo_fsm_inst_state_chg(fi, TPDU_S_RX_SINGLE, 0, 0);
1288 else
1289 osmo_fsm_inst_state_chg(fi, TPDU_S_RX_REMAINING, 0, 0);
Harald Welte06348362019-05-19 00:45:17 +02001290 }
1291 } else if (byte == (tpduh->ins ^ 0xFF)) {
Harald Welte65087832019-10-01 09:16:49 +02001292 /* transmit/recieve single byte then wait for proc */
1293 if (tfp->is_command) {
1294 /* transmit *next*, not first byte */
1295 OSMO_ASSERT(msgb_l3len(tfp->tpdu) >= 0);
Harald Welte6603d952019-10-09 20:50:13 +02001296 card_uart_tx(ip->uart, msgb_l3(tfp->tpdu), 1, false);
Harald Welte65087832019-10-01 09:16:49 +02001297 osmo_fsm_inst_state_chg(fi, TPDU_S_TX_SINGLE, 0, 0);
1298 } else {
Eric Wild2f5cdd12019-11-27 18:40:44 +01001299 card_uart_set_rx_threshold(ip->uart, 1);
1300 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 1);
Harald Welte65087832019-10-01 09:16:49 +02001301 osmo_fsm_inst_state_chg(fi, TPDU_S_RX_SINGLE, 0, 0);
1302 }
Harald Welte06348362019-05-19 00:45:17 +02001303 } else
1304 OSMO_ASSERT(0);
1305 break;
1306 default:
1307 OSMO_ASSERT(0);
1308 }
1309}
1310
1311/* UART is transmitting remaining data; we wait for ISO7816_E_TX_COMPL */
1312static void tpdu_s_tx_remaining_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1313{
1314 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1315 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1316
1317 switch (event) {
Harald Welte68bc7f42020-09-02 18:14:30 +02001318 case ISO7816_E_RX_SINGLE:
1319 return;
Harald Welte06348362019-05-19 00:45:17 +02001320 case ISO7816_E_TX_COMPL:
1321 card_uart_set_rx_threshold(ip->uart, 1);
Eric Wild2f5cdd12019-11-27 18:40:44 +01001322 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 1);
Harald Welte06348362019-05-19 00:45:17 +02001323 osmo_fsm_inst_state_chg(fi, TPDU_S_SW1, 0, 0);
1324 break;
1325 default:
1326 OSMO_ASSERT(0);
1327 }
1328}
1329
1330/* UART is transmitting single byte of data; we wait for ISO7816_E_TX_COMPL */
1331static void tpdu_s_tx_single_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1332{
Harald Welte65087832019-10-01 09:16:49 +02001333 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
Eric Wild2f5cdd12019-11-27 18:40:44 +01001334 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1335 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
Harald Welte65087832019-10-01 09:16:49 +02001336
Harald Welte06348362019-05-19 00:45:17 +02001337 switch (event) {
Harald Welte68bc7f42020-09-02 18:14:30 +02001338 case ISO7816_E_RX_SINGLE:
1339 return;
Harald Welte06348362019-05-19 00:45:17 +02001340 case ISO7816_E_TX_COMPL:
Harald Welte65087832019-10-01 09:16:49 +02001341 tfp->tpdu->l3h += 1;
Eric Wild2f5cdd12019-11-27 18:40:44 +01001342 card_uart_set_rx_threshold(ip->uart, 1);
1343 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 1);
Harald Welte65087832019-10-01 09:16:49 +02001344 if (msgb_l3len(tfp->tpdu))
1345 osmo_fsm_inst_state_chg(fi, TPDU_S_PROCEDURE, 0, 0);
1346 else
1347 osmo_fsm_inst_state_chg(fi, TPDU_S_SW1, 0, 0);
Harald Welte06348362019-05-19 00:45:17 +02001348 break;
1349 default:
1350 OSMO_ASSERT(0);
1351 }
1352}
1353
1354/* UART is receiving remaining data; we wait for ISO7816_E_RX_COMPL */
1355static void tpdu_s_rx_remaining_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1356{
1357 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
Harald Welte65087832019-10-01 09:16:49 +02001358 struct osim_apdu_cmd_hdr *tpduh = msgb_tpdu_hdr(tfp->tpdu);
Harald Welte06348362019-05-19 00:45:17 +02001359 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1360 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1361 int rc;
1362
Eric Wild172b4432020-09-10 19:33:51 +02001363 /* 7816-3 10.3.2 special case outgoing transfer 0 means 256 */
1364 int len_expected = tpduh->p3 == 0 ? 256 : tpduh->p3;
1365
Harald Welte06348362019-05-19 00:45:17 +02001366 switch (event) {
1367 case ISO7816_E_RX_COMPL:
1368 /* retrieve pending byte(s) */
Eric Wild172b4432020-09-10 19:33:51 +02001369 rc = card_uart_rx(ip->uart, msgb_l2(tfp->tpdu), len_expected);
Harald Welte65087832019-10-01 09:16:49 +02001370 OSMO_ASSERT(rc > 0);
1371 msgb_put(tfp->tpdu, rc);
Eric Wild172b4432020-09-10 19:33:51 +02001372 if (msgb_l2len(tfp->tpdu) != len_expected) {
1373 LOGPFSML(fi, LOGL_ERROR, "expected %u bytes; read %d\n", len_expected,
Harald Welte65087832019-10-01 09:16:49 +02001374 msgb_l2len(tfp->tpdu));
1375 }
Harald Welte06348362019-05-19 00:45:17 +02001376 card_uart_set_rx_threshold(ip->uart, 1);
Eric Wild2f5cdd12019-11-27 18:40:44 +01001377 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 1);
Harald Welte06348362019-05-19 00:45:17 +02001378 osmo_fsm_inst_state_chg(fi, TPDU_S_SW1, 0, 0);
1379 break;
1380 default:
1381 OSMO_ASSERT(0);
1382 }
1383}
1384
1385/* UART is receiving single byte of data; we wait for ISO7816_E_RX_SINGLE */
1386static void tpdu_s_rx_single_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1387{
1388 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
Harald Welte65087832019-10-01 09:16:49 +02001389 struct osim_apdu_cmd_hdr *tpduh = msgb_tpdu_hdr(tfp->tpdu);
Eric Wild2f5cdd12019-11-27 18:40:44 +01001390 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1391 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
Harald Welte06348362019-05-19 00:45:17 +02001392 uint8_t byte;
1393
1394 switch (event) {
1395 case ISO7816_E_RX_SINGLE:
1396 byte = get_rx_byte_evt(fi->proc.parent, data);
1397 LOGPFSML(fi, LOGL_DEBUG, "Received 0x%02x from UART\n", byte);
Harald Welte65087832019-10-01 09:16:49 +02001398 msgb_put_u8(tfp->tpdu, byte);
Eric Wild2f5cdd12019-11-27 18:40:44 +01001399
1400 card_uart_set_rx_threshold(ip->uart, 1);
1401 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 1);
1402
Harald Welte65087832019-10-01 09:16:49 +02001403 /* determine if number of expected bytes received */
1404 if (msgb_l2len(tfp->tpdu) == tpduh->p3)
Harald Welte06348362019-05-19 00:45:17 +02001405 osmo_fsm_inst_state_chg(fi, TPDU_S_SW1, 0, 0);
Harald Welte65087832019-10-01 09:16:49 +02001406 else
Harald Welte06348362019-05-19 00:45:17 +02001407 osmo_fsm_inst_state_chg(fi, TPDU_S_PROCEDURE, 0, 0);
1408 break;
1409 default:
1410 OSMO_ASSERT(0);
1411 }
1412}
1413
1414static void tpdu_s_sw1_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1415{
1416 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
1417 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1418 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1419 uint8_t byte;
1420
1421 switch (event) {
1422 case ISO7816_E_RX_SINGLE:
1423 byte = get_rx_byte_evt(fi->proc.parent, data);
1424 LOGPFSML(fi, LOGL_DEBUG, "Received 0x%02x from UART\n", byte);
1425 /* record byte */
1426 //msgb_apdu_sw(tfp->apdu) = byte << 8;
1427 msgb_put_u8(tfp->tpdu, byte);
1428 card_uart_set_rx_threshold(ip->uart, 1);
Eric Wild2f5cdd12019-11-27 18:40:44 +01001429 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 1);
Harald Welte06348362019-05-19 00:45:17 +02001430 osmo_fsm_inst_state_chg(fi, TPDU_S_SW2, 0, 0);
1431 break;
1432 default:
1433 OSMO_ASSERT(0);
1434 }
1435}
1436
1437static void tpdu_s_sw2_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1438{
1439 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
1440 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1441 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1442 uint8_t byte;
1443
1444 switch (event) {
1445 case ISO7816_E_RX_SINGLE:
1446 byte = get_rx_byte_evt(fi->proc.parent, data);
1447 LOGPFSML(fi, LOGL_DEBUG, "Received 0x%02x from UART\n", byte);
1448 /* record SW2 byte */
1449 //msgb_apdu_sw(tfp->apdu) &= 0xFF00;
1450 //msgb_apdu_sw(tfp->apdu) |= byte;
1451 msgb_put_u8(tfp->tpdu, byte);
1452 osmo_fsm_inst_state_chg(fi, TPDU_S_DONE, 0, 0);
1453 /* Notify parent FSM */
1454 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_TPDU_DONE_IND, tfp->tpdu);
Eric Wild9e622dc2019-11-27 14:43:16 +01001455
1456 /* ownership transfer */
1457 tfp->tpdu = 0;
Harald Welte06348362019-05-19 00:45:17 +02001458 break;
1459 default:
1460 OSMO_ASSERT(0);
1461 }
1462}
1463
1464static void tpdu_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1465{
1466 OSMO_ASSERT(fi->fsm == &tpdu_fsm);
1467
1468 switch (event) {
1469 case ISO7816_E_RX_ERR_IND:
1470 case ISO7816_E_TX_ERR_IND:
1471 /* FIXME: handle this in some different way */
1472 osmo_fsm_inst_state_chg(fi, TPDU_S_DONE, 0, 0);
Eric Wild2f5cdd12019-11-27 18:40:44 +01001473 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_TPDU_FAILED_IND, NULL);
Harald Welte06348362019-05-19 00:45:17 +02001474 break;
1475 case ISO7816_E_TPDU_CLEAR_REQ:
1476 osmo_fsm_inst_state_chg(fi, TPDU_S_INIT, 0, 0);
1477 break;
1478 }
1479}
1480
Eric Wild2f5cdd12019-11-27 18:40:44 +01001481
1482static void tpdu_s_done_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
1483{
1484 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1485 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1486
1487 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 0);
1488}
1489
Harald Welte06348362019-05-19 00:45:17 +02001490static const struct osmo_fsm_state tpdu_states[] = {
1491 [TPDU_S_INIT] = {
1492 .name = "INIT",
1493 .in_event_mask = S(ISO7816_E_XCEIVE_TPDU_CMD) |
1494 S(ISO7816_E_TX_COMPL),
1495 .out_state_mask = S(TPDU_S_INIT) |
1496 S(TPDU_S_TX_HDR),
1497 .action = tpdu_s_init_action,
Eric Wild9e622dc2019-11-27 14:43:16 +01001498 .onenter = tpdu_s_init_onenter,
Harald Welte06348362019-05-19 00:45:17 +02001499 },
1500 [TPDU_S_TX_HDR] = {
1501 .name = "TX_HDR",
Harald Welte68bc7f42020-09-02 18:14:30 +02001502 .in_event_mask = S(ISO7816_E_TX_COMPL) |
1503 S(ISO7816_E_RX_SINGLE),
Harald Welte06348362019-05-19 00:45:17 +02001504 .out_state_mask = S(TPDU_S_INIT) |
1505 S(TPDU_S_PROCEDURE),
1506 .action = tpdu_s_tx_hdr_action,
1507 },
1508 [TPDU_S_PROCEDURE] = {
1509 .name = "PROCEDURE",
1510 .in_event_mask = S(ISO7816_E_RX_SINGLE),
1511 .out_state_mask = S(TPDU_S_INIT) |
1512 S(TPDU_S_PROCEDURE) |
1513 S(TPDU_S_RX_REMAINING) |
1514 S(TPDU_S_RX_SINGLE) |
1515 S(TPDU_S_TX_REMAINING) |
1516 S(TPDU_S_TX_SINGLE) |
1517 S(TPDU_S_SW2),
1518 .action = tpdu_s_procedure_action,
1519 },
1520 [TPDU_S_TX_REMAINING] = {
1521 .name = "TX_REMAINING",
Harald Welte68bc7f42020-09-02 18:14:30 +02001522 .in_event_mask = S(ISO7816_E_TX_COMPL) |
1523 S(ISO7816_E_RX_SINGLE),
Harald Welte06348362019-05-19 00:45:17 +02001524 .out_state_mask = S(TPDU_S_INIT) |
1525 S(TPDU_S_SW1),
1526 .action = tpdu_s_tx_remaining_action,
1527 },
1528 [TPDU_S_TX_SINGLE] = {
1529 .name = "TX_SINGLE",
Harald Welte68bc7f42020-09-02 18:14:30 +02001530 .in_event_mask = S(ISO7816_E_TX_COMPL) |
1531 S(ISO7816_E_RX_SINGLE),
Harald Welte06348362019-05-19 00:45:17 +02001532 .out_state_mask = S(TPDU_S_INIT) |
1533 S(TPDU_S_PROCEDURE),
1534 .action = tpdu_s_tx_single_action,
1535 },
1536 [TPDU_S_RX_REMAINING] = {
1537 .name = "RX_REMAINING",
1538 .in_event_mask = S(ISO7816_E_RX_COMPL),
1539 .out_state_mask = S(TPDU_S_INIT) |
1540 S(TPDU_S_SW1),
1541 .action = tpdu_s_rx_remaining_action,
1542 },
1543 [TPDU_S_RX_SINGLE] = {
1544 .name = "RX_SINGLE",
1545 .in_event_mask = S(ISO7816_E_RX_SINGLE),
1546 .out_state_mask = S(TPDU_S_INIT) |
Harald Welte498e9e72020-09-02 18:10:13 +02001547 S(TPDU_S_PROCEDURE) |
1548 S(TPDU_S_SW1),
Harald Welte06348362019-05-19 00:45:17 +02001549 .action = tpdu_s_rx_single_action,
1550 },
1551 [TPDU_S_SW1] = {
1552 .name = "SW1",
1553 .in_event_mask = S(ISO7816_E_RX_SINGLE),
1554 .out_state_mask = S(TPDU_S_INIT) |
1555 S(TPDU_S_SW2),
1556 .action = tpdu_s_sw1_action,
1557 },
1558 [TPDU_S_SW2] = {
1559 .name = "SW2",
1560 .in_event_mask = S(ISO7816_E_RX_SINGLE),
1561 .out_state_mask = S(TPDU_S_INIT) |
1562 S(TPDU_S_DONE),
1563 .action = tpdu_s_sw2_action,
1564 },
1565 [TPDU_S_DONE] = {
1566 .name = "DONE",
1567 .in_event_mask = 0,
1568 .out_state_mask = S(TPDU_S_INIT),
1569 .action = NULL,
Eric Wild2f5cdd12019-11-27 18:40:44 +01001570 .onenter = tpdu_s_done_onenter,
Harald Welte06348362019-05-19 00:45:17 +02001571 },
1572};
1573static struct osmo_fsm tpdu_fsm = {
1574 .name = "TPDU",
1575 .states = tpdu_states,
1576 .num_states = ARRAY_SIZE(tpdu_states),
1577 .allstate_event_mask = S(ISO7816_E_RX_ERR_IND) |
1578 S(ISO7816_E_TX_ERR_IND) |
1579 S(ISO7816_E_TPDU_CLEAR_REQ),
1580 .allstate_action = tpdu_allstate_action,
1581 .log_subsys = DTPDU,
1582 .event_names = iso7816_3_event_names,
1583};
1584
1585struct osmo_fsm_inst *iso7816_fsm_alloc(void *ctx, int log_level, const char *id,
1586 struct card_uart *cuart, iso7816_user_cb user_cb,
1587 void *user_priv)
1588{
1589 struct iso7816_3_priv *ip;
1590 struct osmo_fsm_inst *fi;
1591
1592 fi = osmo_fsm_inst_alloc(&iso7816_3_fsm, ctx, NULL, log_level, id);
1593 ip = talloc_zero(fi, struct iso7816_3_priv);
1594 if (!ip)
1595 goto out_fi;
1596 fi->priv = ip;
1597
1598 ip->uart = cuart;
1599 cuart->priv = fi;
1600 cuart->handle_event = tpdu_uart_notification;
1601
1602 ip->user_cb = user_cb;
1603 ip->user_priv = user_priv;
1604
1605 ip->atr_fi = osmo_fsm_inst_alloc_child(&atr_fsm, fi, ISO7816_E_SW_ERR_IND);
1606 if (!ip->atr_fi)
1607 goto out_fi;
1608 ip->atr_fi->priv = talloc_zero(ip->atr_fi, struct atr_fsm_priv);
1609 if (!ip->atr_fi->priv)
1610 goto out_atr;
1611
1612 ip->tpdu_fi = osmo_fsm_inst_alloc_child(&tpdu_fsm, fi, ISO7816_E_SW_ERR_IND);
1613 if (!ip->tpdu_fi)
1614 goto out_atr;
1615 ip->tpdu_fi->priv = talloc_zero(ip->tpdu_fi, struct tpdu_fsm_priv);
1616 if (!ip->tpdu_fi->priv)
1617 goto out_tpdu;
1618
Eric Wildad1edce2019-11-27 16:51:08 +01001619#if 1
Harald Welte06348362019-05-19 00:45:17 +02001620 ip->pps_fi = osmo_fsm_inst_alloc_child(&pps_fsm, fi, ISO7816_E_SW_ERR_IND);
1621 if (!ip->pps_fi)
1622 goto out_tpdu;
1623 ip->pps_fi->priv = talloc_zero(ip->pps_fi, struct pps_fsm_priv);
1624 if (!ip->pps_fi->priv)
1625 goto out_pps;
1626#endif
1627
1628 /* This ensures the 'onenter' function of the initial state is called */
1629 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
1630
1631 return fi;
1632
Eric Wildad1edce2019-11-27 16:51:08 +01001633#if 1
Harald Welte06348362019-05-19 00:45:17 +02001634out_pps:
1635 osmo_fsm_inst_free(ip->pps_fi);
1636#endif
1637out_tpdu:
1638 osmo_fsm_inst_free(ip->tpdu_fi);
1639out_atr:
1640 osmo_fsm_inst_free(ip->atr_fi);
1641out_fi:
1642 osmo_fsm_inst_free(fi);
1643 cuart->priv = NULL;
1644 return NULL;
1645}
1646
1647void *iso7816_fsm_get_user_priv(struct osmo_fsm_inst *fi)
1648{
1649 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
1650 return ip->user_priv;
1651}
1652
1653
1654static __attribute__((constructor)) void on_dso_load_iso7816(void)
1655{
Harald Welte89b1e062019-12-01 13:30:14 +01001656 OSMO_ASSERT(osmo_fsm_register(&iso7816_3_fsm) == 0);
1657 OSMO_ASSERT(osmo_fsm_register(&atr_fsm) == 0);
1658 OSMO_ASSERT(osmo_fsm_register(&tpdu_fsm) == 0);
1659 OSMO_ASSERT(osmo_fsm_register(&pps_fsm) == 0);
Harald Welte06348362019-05-19 00:45:17 +02001660}