blob: 307dac3402ac6b9629662ff4a257fdb43ef17a40 [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 */
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) {
420 case ISO7816_E_TX_COMPL:
421 /* Rx of single byte is already enabled by previous card_uart_tx() call */
422 osmo_fsm_inst_state_chg(fi, ISO7816_S_IN_PPS_RSP, 0, 0);
Eric Wild2f5cdd12019-11-27 18:40:44 +0100423 osmo_fsm_inst_dispatch(ip->pps_fi, event, data);
Eric Wildad1edce2019-11-27 16:51:08 +0100424 break;
425 default:
426 OSMO_ASSERT(0);
427 }
428}
429
430static void iso7816_3_s_ins_pps_rsp_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
431{
432 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
433 struct msgb *ppsrsp;
434 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
435
436 switch (event) {
437 case ISO7816_E_RX_SINGLE:
438 case ISO7816_E_WTIME_EXP:
439 /* simply pass this through to the child FSM for the ATR */
440 osmo_fsm_inst_dispatch(ip->pps_fi, event, data);
441 break;
442 case ISO7816_E_PPS_DONE_IND:
443 case ISO7816_E_PPS_FAILED_IND:
444 ppsrsp = data;
445 osmo_fsm_inst_state_chg(fi, ISO7816_S_WAIT_TPDU, 0, 0);
446 /* notify user about PPS result */
447 ip->user_cb(fi, event, 0, ppsrsp);
448 break;
449 case ISO7816_E_RX_ERR_IND:
450 ppsrsp = data;
451 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
452 ip->user_cb(fi, event, 0, ppsrsp);
453 break;
454 default:
455 OSMO_ASSERT(0);
456 }
457}
458
Harald Welte06348362019-05-19 00:45:17 +0200459static const struct osmo_fsm_state iso7816_3_states[] = {
460 [ISO7816_S_RESET] = {
461 .name = "RESET",
Eric Wild9e622dc2019-11-27 14:43:16 +0100462 .in_event_mask = S(ISO7816_E_RESET_REL_IND) |
Eric Wild2f5cdd12019-11-27 18:40:44 +0100463 S(ISO7816_E_POWER_UP_IND) |
Eric Wild9e622dc2019-11-27 14:43:16 +0100464 S(ISO7816_E_PPS_FAILED_IND)|
465 S(ISO7816_E_TPDU_FAILED_IND),
Harald Welte06348362019-05-19 00:45:17 +0200466 .out_state_mask = S(ISO7816_S_WAIT_ATR) |
467 S(ISO7816_S_RESET),
468 .action = iso7816_3_reset_action,
469 .onenter = iso7816_3_reset_onenter,
470 },
471 [ISO7816_S_WAIT_ATR] = {
472 .name = "WAIT_ATR",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200473 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
474 S(ISO7816_E_WTIME_EXP),
Harald Welte06348362019-05-19 00:45:17 +0200475 .out_state_mask = S(ISO7816_S_RESET) |
476 S(ISO7816_S_IN_ATR),
477 .action = iso7816_3_wait_atr_action,
478 },
479 [ISO7816_S_IN_ATR] = {
480 .name = "IN_ATR",
481 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
482 S(ISO7816_E_RX_ERR_IND) |
Harald Welte1ac9ef92019-10-09 22:20:16 +0200483 S(ISO7816_E_ATR_DONE_IND) |
484 S(ISO7816_E_ATR_ERR_IND) |
485 S(ISO7816_E_WTIME_EXP),
Harald Welte06348362019-05-19 00:45:17 +0200486 .out_state_mask = S(ISO7816_S_RESET) |
487 S(ISO7816_S_IN_ATR) |
488 S(ISO7816_S_WAIT_TPDU),
489 .action = iso7816_3_in_atr_action,
490 },
491 [ISO7816_S_WAIT_TPDU] = {
492 .name = "WAIT_TPDU",
Eric Wildad1edce2019-11-27 16:51:08 +0100493 .in_event_mask = S(ISO7816_E_XCEIVE_TPDU_CMD) |
494 S(ISO7816_E_XCEIVE_PPS_CMD),
Harald Welte06348362019-05-19 00:45:17 +0200495 .out_state_mask = S(ISO7816_S_RESET) |
496 S(ISO7816_S_WAIT_TPDU) |
497 S(ISO7816_S_IN_TPDU) |
Eric Wildad1edce2019-11-27 16:51:08 +0100498 S(ISO7816_S_WAIT_PPS_RSP),
Harald Welte06348362019-05-19 00:45:17 +0200499 .action = iso7816_3_wait_tpdu_action,
500 .onenter = iso7816_3_wait_tpdu_onenter,
501 },
502 [ISO7816_S_IN_TPDU] = {
503 .name = "IN_TPDU",
504 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
505 S(ISO7816_E_RX_COMPL) |
506 S(ISO7816_E_TX_COMPL) |
507 S(ISO7816_E_RX_ERR_IND) |
508 S(ISO7816_E_TX_ERR_IND) |
Harald Welte1ac9ef92019-10-09 22:20:16 +0200509 S(ISO7816_E_TPDU_DONE_IND) |
510 S(ISO7816_E_WTIME_EXP),
Harald Welte06348362019-05-19 00:45:17 +0200511 .out_state_mask = S(ISO7816_S_RESET) |
512 S(ISO7816_S_WAIT_TPDU) |
513 S(ISO7816_S_IN_TPDU),
514 .action = iso7816_3_in_tpdu_action,
515 },
Harald Welte06348362019-05-19 00:45:17 +0200516 [ISO7816_S_WAIT_PPS_RSP] = {
517 .name = "WAIT_PPS_RESP",
Eric Wildad1edce2019-11-27 16:51:08 +0100518 .in_event_mask = S(ISO7816_E_TX_COMPL) |
519 S(ISO7816_E_TX_ERR_IND) |
520 S(ISO7816_E_WTIME_EXP),
Harald Welte06348362019-05-19 00:45:17 +0200521 .out_state_mask = S(ISO7816_S_RESET) |
522 S(ISO7816_S_WAIT_TPDU) |
523 S(ISO7816_S_WAIT_PPS_RSP) |
524 S(ISO7816_S_IN_PPS_RSP),
Eric Wildad1edce2019-11-27 16:51:08 +0100525 .action = iso7816_3_s_wait_pps_rsp_action,
Harald Welte06348362019-05-19 00:45:17 +0200526 },
527 [ISO7816_S_IN_PPS_RSP] = {
528 .name = "IN_PPS_RESP",
Eric Wildad1edce2019-11-27 16:51:08 +0100529 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
530 S(ISO7816_E_RX_COMPL) |
531 S(ISO7816_E_RX_ERR_IND) |
532 S(ISO7816_E_PPS_DONE_IND) |
533 S(ISO7816_E_PPS_FAILED_IND) |
534 S(ISO7816_E_WTIME_EXP),
Harald Welte06348362019-05-19 00:45:17 +0200535 .out_state_mask = S(ISO7816_S_RESET) |
536 S(ISO7816_S_WAIT_TPDU) |
537 S(ISO7816_S_IN_PPS_RSP),
Eric Wildad1edce2019-11-27 16:51:08 +0100538 .action = iso7816_3_s_ins_pps_rsp_action,
Harald Welte06348362019-05-19 00:45:17 +0200539 },
540};
541static struct osmo_fsm iso7816_3_fsm = {
542 .name = "ISO7816-3",
543 .states = iso7816_3_states,
544 .num_states = ARRAY_SIZE(iso7816_3_states),
545 .log_subsys = DISO7816,
546 .event_names = iso7816_3_event_names,
547 .allstate_action = iso7816_3_allstate_action,
Harald Welte1ac9ef92019-10-09 22:20:16 +0200548 .allstate_event_mask = S(ISO7816_E_CARD_REMOVAL) |
Harald Welte06348362019-05-19 00:45:17 +0200549 S(ISO7816_E_POWER_DN_IND) |
550 S(ISO7816_E_RESET_ACT_IND) |
551 S(ISO7816_E_HW_ERR_IND) |
552 S(ISO7816_E_ABORT_REQ),
553};
554
555/***********************************************************************
556 * ATR FSM
557 ***********************************************************************/
558
Eric Wild6d3b2fc2020-03-30 03:12:09 +0200559/* type-safe method to obtain atr_fsm_priv from fi */
560static struct atr_fsm_priv *get_atr_fsm_priv(struct osmo_fsm_inst *fi)
561{
562 OSMO_ASSERT(fi);
563 OSMO_ASSERT(fi->fsm == &atr_fsm);
564 return (struct atr_fsm_priv *) fi->priv;
565}
Harald Welte06348362019-05-19 00:45:17 +0200566
567/* obtain the [software] guard time in milli-seconds from the atr fsm_inst */
568static uint32_t atr_fi_gt_ms(struct osmo_fsm_inst *fi)
569{
570 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
571 struct iso7816_3_priv *ip;
572
573 OSMO_ASSERT(fi->fsm == &atr_fsm);
574 OSMO_ASSERT(parent_fi);
575 ip = get_iso7816_3_priv(parent_fi);
576
577 return ip->guard_time_ms;
578}
579
580/* obtain the 'byte' parmeter of an ISO7816_E_RX event */
581static uint8_t get_rx_byte_evt(struct osmo_fsm_inst *fi, void *data)
582{
583 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
584 uint8_t byte = *(uint8_t *)data;
585
586 /* apply inverse convention */
587 if (ip->convention_convert)
588 byte = convention_convert_lut[byte];
589
590 return byte;
591}
592
593/* append a single byte to the ATR */
594static int atr_append_byte(struct osmo_fsm_inst *fi, uint8_t byte)
595{
Eric Wild6d3b2fc2020-03-30 03:12:09 +0200596 struct atr_fsm_priv *atp = get_atr_fsm_priv(fi);
Harald Welte06348362019-05-19 00:45:17 +0200597
598 if (!msgb_tailroom(atp->atr)) {
599 LOGPFSML(fi, LOGL_ERROR, "ATR overflow !?!");
600 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_SW_ERR_IND, NULL);
601 return -1;
602 }
603 msgb_put_u8(atp->atr, byte);
604 return 0;
605}
606
607static void atr_wait_ts_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
608{
Eric Wild6d3b2fc2020-03-30 03:12:09 +0200609 struct atr_fsm_priv *atp = get_atr_fsm_priv(fi);
Harald Welte06348362019-05-19 00:45:17 +0200610
611 /* reset state to its initial value */
612 atp->hist_len = 0;
613 atp->y = 0;
614 atp->i = 0;
615 if (!atp->atr)
616 atp->atr = msgb_alloc_c(fi, 33, "ATR"); /* TS + 32 chars */
617 else
618 msgb_reset(atp->atr);
619 atp->computed_checksum = 0;
620 atp->protocol_support = 0;
621}
622
623static void atr_wait_ts_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
624{
Eric Wild6d3b2fc2020-03-30 03:12:09 +0200625 struct atr_fsm_priv *atp = get_atr_fsm_priv(fi);
Harald Welte06348362019-05-19 00:45:17 +0200626 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
627 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
628 uint8_t byte;
629
630 switch (event) {
631 case ISO7816_E_RX_SINGLE:
632 OSMO_ASSERT(msgb_length(atp->atr) == 0);
633restart:
634 byte = get_rx_byte_evt(parent_fi, data);
635 LOGPFSML(fi, LOGL_DEBUG, "RX byte '%02x'\n", byte);
636 switch (byte) {
637 case 0x23:
638 /* direct convention used, but decoded using inverse
639 * convention (a parity error should also have occurred) */
640 /* fall-through */
641 case 0x30:
642 /* inverse convention used, but decoded using direct
643 * convention (a parity error should also have occurred) */
644 ip->convention_convert = !ip->convention_convert;
645 goto restart;
646 break;
647 case 0x3b: /* direct convention used and correctly decoded */
648 /* fall-through */
649 case 0x3f: /* inverse convention used and correctly decoded */
650 atr_append_byte(fi, byte);
651 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_T0, atr_fi_gt_ms(fi), T_GUARD);
652 break;
653 default:
654 LOGPFSML(fi, LOGL_ERROR, "Invalid TS received: 0x%02X\n", byte);
655 /* FIXME: somehow indiicate to user */
656 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_SW_ERR_IND, NULL);
657 break;
658 }
659 atp->i = 0; /* first interface byte sub-group is coming (T0 is kind of TD0) */
660 break;
Harald Welte1ac9ef92019-10-09 22:20:16 +0200661 case ISO7816_E_WTIME_EXP:
662 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_ATR_ERR_IND, NULL);
663 break;
Harald Welte06348362019-05-19 00:45:17 +0200664 default:
665 OSMO_ASSERT(0);
666 }
667}
668
669static void atr_wait_tX_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
670{
Eric Wild6d3b2fc2020-03-30 03:12:09 +0200671 struct atr_fsm_priv *atp = get_atr_fsm_priv(fi);
Harald Welte06348362019-05-19 00:45:17 +0200672 uint32_t guard_time_ms = atr_fi_gt_ms(fi);
673 uint8_t byte;
674
675 switch (event) {
676 case ISO7816_E_RX_SINGLE:
677 byte = get_rx_byte_evt(fi->proc.parent, data);
678 LOGPFSML(fi, LOGL_DEBUG, "RX byte '%02x'\n", byte);
679 atr_append_byte(fi, byte);
680 switch (fi->state) {
681 case ATR_S_WAIT_T0: /* see ISO/IEC 7816-3:2006 section 8.2.2 */
682 case ATR_S_WAIT_TD: /* see ISO/IEC 7816-3:2006 section 8.2.3 */
683 if (fi->state == ATR_S_WAIT_T0) {
684 /* save number of hist. bytes */
685 atp->hist_len = (byte & 0x0f);
686 } else {
687 /* remember supported protocol to know if TCK will be present */
688 atp->protocol_support |= (1<<(byte & 0x0f));
689 }
690 atp->y = (byte & 0xf0); /* remember incoming interface bytes */
691 atp->i++;
692 if (atp->y & 0x10) {
693 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_TA, guard_time_ms, T_GUARD);
694 break;
695 }
696 /* fall-through */
697 case ATR_S_WAIT_TA: /* see ISO/IEC 7816-3:2006 section 8.2.3 */
698 if (atp->y & 0x20) {
699 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_TB, guard_time_ms, T_GUARD);
700 break;
701 }
702 /* fall-through */
703 case ATR_S_WAIT_TB: /* see ISO/IEC 7816-3:2006 section 8.2.3 */
704 if (atp->y & 0x40) {
705 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_TC, guard_time_ms, T_GUARD);
706 break;
707 }
708 /* fall-through */
709 case ATR_S_WAIT_TC: /* see ISO/IEC 7816-3:2006 section 8.2.3 */
710 if (atp->y & 0x80) {
711 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_TD, guard_time_ms, T_GUARD);
712 break;
713 } else if (atp->hist_len) {
714 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_HIST, guard_time_ms, T_GUARD);
715 break;
716 }
717 /* fall-through */
718 case ATR_S_WAIT_HIST: /* see ISO/IEC 7816-3:2006 section 8.2.4 */
719 if (atp->hist_len)
720 atp->hist_len--;
721 if (atp->hist_len == 0) {
722 if (atp->protocol_support > 1) {
723 /* wait for check byte */
724 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_TCK,
725 guard_time_ms, T_GUARD);
726 break;
Eric Wild70d212d2019-11-27 15:05:09 +0100727 } else {
728 /* no TCK present, ATR complete; notify parent */
729 osmo_fsm_inst_state_chg(fi, ATR_S_DONE, 0, 0);
730 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_ATR_DONE_IND, atp->atr);
Harald Welte06348362019-05-19 00:45:17 +0200731 }
732 } else {
733 break;
734 }
735 /* fall-through */
736 case ATR_S_WAIT_TCK: /* see ISO/IEC 7816-3:2006 section 8.2.5 */
737 /* verify checksum if present */
738 if (fi->state == ATR_S_WAIT_TCK) {
739 uint8_t ui;
740 uint8_t *atr = msgb_data(atp->atr);
741 LOGPFSML(fi, LOGL_INFO, "Complete ATR: %s\n", msgb_hexdump(atp->atr));
742 for (ui = 1; ui < msgb_length(atp->atr)-1; ui++) {
743 atp->computed_checksum ^= atr[ui];
744 }
745 if (atp->computed_checksum != byte) {
746 /* checkum error. report to user? */
747 LOGPFSML(fi, LOGL_ERROR,
748 "computed checksum %02x doesn't match TCK=%02x\n",
749 atp->computed_checksum, byte);
750 }
751 /* ATR complete; notify parent */
752 osmo_fsm_inst_state_chg(fi, ATR_S_DONE, 0, 0);
753 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_ATR_DONE_IND, atp->atr);
754 }
755 break;
756 default:
757 OSMO_ASSERT(0);
758 }
759 break;
Harald Welte1ac9ef92019-10-09 22:20:16 +0200760 case ISO7816_E_WTIME_EXP:
761 switch (fi->state) {
762 case ATR_S_WAIT_HIST:
763 case ATR_S_WAIT_TCK:
764 /* Some cards have an ATR with long indication of historical bytes */
765 /* FIXME: should we check the checksum? */
766 osmo_fsm_inst_state_chg(fi, ATR_S_DONE, 0, 0);
767 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_ATR_DONE_IND, atp->atr);
768 break;
769 default:
770 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_ATR_ERR_IND, NULL);
771 break;
772 }
773 break;
Harald Welte06348362019-05-19 00:45:17 +0200774 default:
775 OSMO_ASSERT(0);
776 }
777}
778
Eric Wild2f5cdd12019-11-27 18:40:44 +0100779static void atr_done_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
780{
781 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
782 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
783
784 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 0);
785}
786
Harald Welte06348362019-05-19 00:45:17 +0200787static const struct osmo_fsm_state atr_states[] = {
788 [ATR_S_WAIT_TS] = {
789 .name = "WAIT_TS",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200790 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
791 S(ISO7816_E_WTIME_EXP),
Harald Welte06348362019-05-19 00:45:17 +0200792 .out_state_mask = S(ATR_S_WAIT_TS) |
793 S(ATR_S_WAIT_T0),
794 .action = atr_wait_ts_action,
795 .onenter = atr_wait_ts_onenter,
796 },
797 [ATR_S_WAIT_T0] = {
798 .name = "WAIT_T0",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200799 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
800 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200801 .out_state_mask = S(ATR_S_WAIT_TS) |
802 S(ATR_S_WAIT_TA) |
Harald Welte06348362019-05-19 00:45:17 +0200803 S(ATR_S_WAIT_TB) |
804 S(ATR_S_WAIT_TC) |
805 S(ATR_S_WAIT_TD) |
806 S(ATR_S_WAIT_HIST) |
807 S(ATR_S_WAIT_TCK) |
808 S(ATR_S_WAIT_T0),
809 .action = atr_wait_tX_action,
810 },
811 [ATR_S_WAIT_TA] = {
812 .name = "WAIT_TA",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200813 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
814 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200815 .out_state_mask = S(ATR_S_WAIT_TS) |
816 S(ATR_S_WAIT_TB) |
Harald Welte06348362019-05-19 00:45:17 +0200817 S(ATR_S_WAIT_TC) |
818 S(ATR_S_WAIT_TD) |
819 S(ATR_S_WAIT_HIST) |
820 S(ATR_S_WAIT_TCK) |
821 S(ATR_S_WAIT_T0),
822 .action = atr_wait_tX_action,
823 },
824 [ATR_S_WAIT_TB] = {
825 .name = "WAIT_TB",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200826 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
827 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200828 .out_state_mask = S(ATR_S_WAIT_TS) |
829 S(ATR_S_WAIT_TC) |
Harald Welte06348362019-05-19 00:45:17 +0200830 S(ATR_S_WAIT_TD) |
831 S(ATR_S_WAIT_HIST) |
832 S(ATR_S_WAIT_TCK) |
833 S(ATR_S_WAIT_T0),
834 .action = atr_wait_tX_action,
835 },
836 [ATR_S_WAIT_TC] = {
837 .name = "WAIT_TC",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200838 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
839 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200840 .out_state_mask = S(ATR_S_WAIT_TS) |
841 S(ATR_S_WAIT_TD) |
Harald Welte06348362019-05-19 00:45:17 +0200842 S(ATR_S_WAIT_HIST) |
843 S(ATR_S_WAIT_TCK) |
844 S(ATR_S_WAIT_T0),
845 .action = atr_wait_tX_action,
846 },
847 [ATR_S_WAIT_TD] = {
848 .name = "WAIT_TD",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200849 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
850 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200851 .out_state_mask = S(ATR_S_WAIT_TS) |
852 S(ATR_S_WAIT_TA) |
Harald Welte06348362019-05-19 00:45:17 +0200853 S(ATR_S_WAIT_TB) |
854 S(ATR_S_WAIT_TC) |
855 S(ATR_S_WAIT_TD) |
856 S(ATR_S_WAIT_HIST) |
857 S(ATR_S_WAIT_TCK) |
858 S(ATR_S_WAIT_T0),
859 .action = atr_wait_tX_action,
860 },
861 [ATR_S_WAIT_HIST] = {
862 .name = "WAIT_HIST",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200863 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
864 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200865 .out_state_mask = S(ATR_S_WAIT_TS) |
866 S(ATR_S_WAIT_TCK) |
Harald Welte1ac9ef92019-10-09 22:20:16 +0200867 S(ATR_S_WAIT_T0) |
868 S(ATR_S_DONE),
Harald Welte06348362019-05-19 00:45:17 +0200869 .action = atr_wait_tX_action,
870 },
871 [ATR_S_WAIT_TCK] = {
872 .name = "WAIT_TCK",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200873 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
874 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200875 .out_state_mask = S(ATR_S_WAIT_TS) |
876 S(ATR_S_DONE),
Harald Welte06348362019-05-19 00:45:17 +0200877 .action = atr_wait_tX_action,
878 },
879 [ATR_S_DONE] = {
880 .name = "DONE",
881 .in_event_mask = 0,
Harald Welte704d99a2019-10-09 21:39:27 +0200882 .out_state_mask = S(ATR_S_WAIT_TS),
Eric Wild2f5cdd12019-11-27 18:40:44 +0100883 .onenter = atr_done_onenter
Harald Welte06348362019-05-19 00:45:17 +0200884 },
885
886};
887static struct osmo_fsm atr_fsm = {
888 .name = "ATR",
889 .states = atr_states,
890 .num_states = ARRAY_SIZE(atr_states),
891 .log_subsys = DATR,
892 .event_names = iso7816_3_event_names,
893};
894
895/***********************************************************************
896 * PPS FSM
897 ***********************************************************************/
Eric Wildad1edce2019-11-27 16:51:08 +0100898struct pps_fsm_priv {
899 struct msgb* tx_cmd;
900 struct msgb* rx_cmd;
901 uint8_t pps0_recv;
902};
903
Eric Wild2f5cdd12019-11-27 18:40:44 +0100904static void pps_s_pps_req_init_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
Eric Wildad1edce2019-11-27 16:51:08 +0100905{
906 struct pps_fsm_priv *atp = fi->priv;
907
908 if (!atp->rx_cmd)
Eric Wild9e622dc2019-11-27 14:43:16 +0100909 atp->rx_cmd = msgb_alloc_c(fi, 6, "PPSRSP"); /* at most 6 */
Eric Wildad1edce2019-11-27 16:51:08 +0100910 else
911 msgb_reset(atp->rx_cmd);
Eric Wild9e622dc2019-11-27 14:43:16 +0100912
913 /* notify in case card got pulled out */
Eric Wild759a6462019-11-11 14:22:52 +0100914 if (atp->tx_cmd && old_state != PPS_S_DONE){
Eric Wild9e622dc2019-11-27 14:43:16 +0100915 osmo_fsm_inst_dispatch(fi->proc.parent,
916 ISO7816_E_PPS_FAILED_IND, atp->tx_cmd);
917 atp->tx_cmd = 0;
918 }
Eric Wildad1edce2019-11-27 16:51:08 +0100919}
920
Eric Wild2f5cdd12019-11-27 18:40:44 +0100921static void pps_s_pps_req_init_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
Eric Wildad1edce2019-11-27 16:51:08 +0100922{
923 struct pps_fsm_priv *atp = fi->priv;
Eric Wildad1edce2019-11-27 16:51:08 +0100924 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
925 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
926
Eric Wild9e622dc2019-11-27 14:43:16 +0100927 /* keep the buffer to compare it with the received response */
928 atp->tx_cmd = data;
929
Eric Wildad1edce2019-11-27 16:51:08 +0100930 switch (event) {
931 case ISO7816_E_XCEIVE_PPS_CMD:
Eric Wild2f5cdd12019-11-27 18:40:44 +0100932 osmo_fsm_inst_state_chg(fi, PPS_S_TX_PPS_REQ, 0, 0);
933 card_uart_set_rx_threshold(ip->uart, 1);
Eric Wildad1edce2019-11-27 16:51:08 +0100934 card_uart_tx(ip->uart, msgb_data(data), msgb_length(data), true);
935 break;
936 default:
937 OSMO_ASSERT(0);
938 }
939}
940
Eric Wild2f5cdd12019-11-27 18:40:44 +0100941static void pps_s_tx_pps_req_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
942{
943 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
944 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
945
946 switch (event) {
947 case ISO7816_E_TX_COMPL:
948 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 6);
949 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPSX, 0, 0);
950 break;
951 default:
952 OSMO_ASSERT(0);
953 }
954}
955
956
957
958
Eric Wildad1edce2019-11-27 16:51:08 +0100959static void pps_wait_pX_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
960{
961 struct pps_fsm_priv *atp = fi->priv;
Eric Wild2f5cdd12019-11-27 18:40:44 +0100962 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
963 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
Eric Wildad1edce2019-11-27 16:51:08 +0100964 uint8_t byte;
965
966 switch (event) {
967 case ISO7816_E_RX_SINGLE:
968 byte = get_rx_byte_evt(fi->proc.parent, data);
969 LOGPFSML(fi, LOGL_DEBUG, "RX byte '%02x'\n", byte);
970 msgb_put_u8(atp->rx_cmd, byte);
971 switch (fi->state) {
Eric Wild2f5cdd12019-11-27 18:40:44 +0100972 case PPS_S_WAIT_PPSX:
Eric Wildad1edce2019-11-27 16:51:08 +0100973 if (byte == 0xff)
974 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPS0, 0, 0);
975 break;
976 case PPS_S_WAIT_PPS0:
977 atp->pps0_recv = byte;
978 if(atp->pps0_recv & (1 << 4)) {
979 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPS1, 0, 0);
980 break;
981 } else if (atp->pps0_recv & (1 << 5)) {
982 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPS2, 0, 0);
983 break;
984 } else if (atp->pps0_recv & (1 << 6)) {
985 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPS3, 0, 0);
986 break;
987 }
988 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PCK, 0, 0);
989 break;
990 case PPS_S_WAIT_PPS1:
991 if (atp->pps0_recv & (1 << 5)) {
992 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPS2, 0, 0);
993 break;
994 } else if (atp->pps0_recv & (1 << 6)) {
995 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPS3, 0, 0);
996 break;
997 }
998 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PCK, 0, 0);
999 break;
1000 case PPS_S_WAIT_PPS2:
1001 if (atp->pps0_recv & (1 << 6)) {
1002 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPS3, 0, 0);
1003 break;
1004 }
1005 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PCK, 0, 0);
1006 break;
1007 case PPS_S_WAIT_PPS3:
1008 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PCK, 0, 0);
1009 break;
1010 case PPS_S_WAIT_PCK:
1011 /* verify checksum if present */
1012 if (fi->state == PPS_S_WAIT_PCK) {
1013 uint8_t *pps_received = msgb_data(atp->rx_cmd);
1014 uint8_t *pps_sent = msgb_data(atp->tx_cmd);
1015
Eric Wild2f5cdd12019-11-27 18:40:44 +01001016 osmo_fsm_inst_state_chg(fi, PPS_S_DONE, 0, 0);
Eric Wildad1edce2019-11-27 16:51:08 +01001017
1018 /* pps was successful if response equals request
1019 * rx buffer stays with the fsm, tx buffer gets handed back and freed
1020 * by the cb */
1021 if (msgb_length(atp->rx_cmd) == msgb_length(atp->tx_cmd) &&
1022 !memcmp(pps_received, pps_sent, msgb_length(atp->rx_cmd))) {
1023 osmo_fsm_inst_dispatch(fi->proc.parent,
1024 ISO7816_E_PPS_DONE_IND, atp->tx_cmd);
1025 } else {
1026 osmo_fsm_inst_dispatch(fi->proc.parent,
1027 ISO7816_E_PPS_FAILED_IND, atp->tx_cmd);
1028 }
Eric Wild9e622dc2019-11-27 14:43:16 +01001029 /* ownership transfer */
1030 atp->tx_cmd = 0;
Eric Wildad1edce2019-11-27 16:51:08 +01001031 }
1032 break;
1033 default:
1034 OSMO_ASSERT(0);
1035 }
1036 break;
1037 case ISO7816_E_WTIME_EXP:
Eric Wild2f5cdd12019-11-27 18:40:44 +01001038 osmo_fsm_inst_state_chg(fi, PPS_S_DONE, 0, 0);
Eric Wildad1edce2019-11-27 16:51:08 +01001039 /* FIXME: timeout handling if no pps supported ? */
1040 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_RX_ERR_IND, NULL);
1041 break;
1042 default:
1043 OSMO_ASSERT(0);
1044 }
1045}
1046
Harald Welte06348362019-05-19 00:45:17 +02001047
Eric Wild2f5cdd12019-11-27 18:40:44 +01001048static void pps_s_done_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
1049{
1050 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1051 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1052
1053 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 0);
1054}
1055
1056
Harald Welte06348362019-05-19 00:45:17 +02001057static const struct osmo_fsm_state pps_states[] = {
Eric Wild2f5cdd12019-11-27 18:40:44 +01001058 [PPS_S_PPS_REQ_INIT] = {
1059 .name = "INIT",
Eric Wildad1edce2019-11-27 16:51:08 +01001060 .in_event_mask = S(ISO7816_E_XCEIVE_PPS_CMD) |
1061 S(ISO7816_E_WTIME_EXP),
Eric Wild2f5cdd12019-11-27 18:40:44 +01001062 .out_state_mask = S(PPS_S_PPS_REQ_INIT) |
1063 S(PPS_S_TX_PPS_REQ),
1064 .action = pps_s_pps_req_init_action,
1065 .onenter = pps_s_pps_req_init_onenter,
Eric Wildad1edce2019-11-27 16:51:08 +01001066 },
Eric Wild2f5cdd12019-11-27 18:40:44 +01001067 [PPS_S_TX_PPS_REQ] = {
1068 .name = "TX_PPS_REQ",
1069 .in_event_mask = S(ISO7816_E_TX_COMPL),
1070 .out_state_mask = S(PPS_S_WAIT_PPSX),
1071 .action = pps_s_tx_pps_req_action,
1072 },
1073 [PPS_S_WAIT_PPSX] = {
Harald Welte06348362019-05-19 00:45:17 +02001074 .name = "WAIT_PPSS",
Eric Wildad1edce2019-11-27 16:51:08 +01001075 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
1076 S(ISO7816_E_WTIME_EXP),
1077 .out_state_mask = S(PPS_S_WAIT_PPS0) |
Eric Wild2f5cdd12019-11-27 18:40:44 +01001078 S(PPS_S_WAIT_PPSX),
Eric Wildad1edce2019-11-27 16:51:08 +01001079 .action = pps_wait_pX_action,
Harald Welte06348362019-05-19 00:45:17 +02001080 },
1081 [PPS_S_WAIT_PPS0] = {
1082 .name = "WAIT_PPS0",
Eric Wildad1edce2019-11-27 16:51:08 +01001083 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
1084 S(ISO7816_E_WTIME_EXP),
1085 .out_state_mask = S(PPS_S_WAIT_PPS1) |
1086 S(PPS_S_WAIT_PPS2) |
1087 S(PPS_S_WAIT_PPS3) |
1088 S(PPS_S_WAIT_PCK),
1089 .action = pps_wait_pX_action,
Harald Welte06348362019-05-19 00:45:17 +02001090 },
1091 [PPS_S_WAIT_PPS1] = {
1092 .name = "WAIT_PPS1",
Eric Wildad1edce2019-11-27 16:51:08 +01001093 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
1094 S(ISO7816_E_WTIME_EXP),
1095 .out_state_mask = S(PPS_S_WAIT_PPS2) |
1096 S(PPS_S_WAIT_PPS3) |
1097 S(PPS_S_WAIT_PCK),
1098 .action = pps_wait_pX_action,
Harald Welte06348362019-05-19 00:45:17 +02001099 },
1100 [PPS_S_WAIT_PPS2] = {
1101 .name = "WAIT_PPS2",
Eric Wildad1edce2019-11-27 16:51:08 +01001102 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
1103 S(ISO7816_E_WTIME_EXP),
1104 .out_state_mask = S(PPS_S_WAIT_PPS3) |
1105 S(PPS_S_WAIT_PCK),
1106 .action = pps_wait_pX_action,
Harald Welte06348362019-05-19 00:45:17 +02001107 },
1108 [PPS_S_WAIT_PPS3] = {
1109 .name = "WAIT_PPS3",
Eric Wildad1edce2019-11-27 16:51:08 +01001110 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
1111 S(ISO7816_E_WTIME_EXP),
1112 .out_state_mask = S(PPS_S_WAIT_PCK),
1113 .action = pps_wait_pX_action,
Harald Welte06348362019-05-19 00:45:17 +02001114 },
1115 [PPS_S_WAIT_PCK] = {
1116 .name = "WAIT_PCK",
Eric Wildad1edce2019-11-27 16:51:08 +01001117 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
1118 S(ISO7816_E_WTIME_EXP),
Eric Wild2f5cdd12019-11-27 18:40:44 +01001119 .out_state_mask = S(PPS_S_DONE),
Eric Wildad1edce2019-11-27 16:51:08 +01001120 .action = pps_wait_pX_action,
Harald Welte06348362019-05-19 00:45:17 +02001121 },
Eric Wild2f5cdd12019-11-27 18:40:44 +01001122 [PPS_S_DONE] = {
1123 .name = "DONE",
Eric Wildad1edce2019-11-27 16:51:08 +01001124 .in_event_mask = 0,
Eric Wild2f5cdd12019-11-27 18:40:44 +01001125 .out_state_mask = S(PPS_S_PPS_REQ_INIT),
1126 .action = NULL,
1127 .onenter = pps_s_done_onenter,
Harald Welte06348362019-05-19 00:45:17 +02001128 },
1129};
1130
1131static struct osmo_fsm pps_fsm = {
1132 .name = "PPS",
1133 .states = pps_states,
1134 .num_states = ARRAY_SIZE(pps_states),
1135 .log_subsys = DPPS,
1136 .event_names = iso7816_3_event_names,
1137};
1138
1139/***********************************************************************
1140 * TPDU FSM
1141 ***********************************************************************/
1142
Harald Welte65087832019-10-01 09:16:49 +02001143/* In this FSM weu use the msgb for the TPDU as follows:
1144 * - 5-byte TPDU header is at msg->data
1145 * - COMMAND TPDU:
1146 * - command bytes are provided after the header at msg->l2h
1147 * - in case of incremental transmission, l3h points to next to-be-transmitted byte
1148 * - RESPONSE TPDU:
1149 * - any response bytes are stored after the header at msg->l2h
1150 */
1151
1152static inline struct osim_apdu_cmd_hdr *msgb_tpdu_hdr(struct msgb *msg) {
1153 return (struct osim_apdu_cmd_hdr *) msgb_data(msg);
1154}
1155
Harald Welte06348362019-05-19 00:45:17 +02001156struct tpdu_fsm_priv {
1157 struct msgb *tpdu;
Harald Welte65087832019-10-01 09:16:49 +02001158 bool is_command; /* is this a command TPDU (true) or a response (false) */
Harald Welte06348362019-05-19 00:45:17 +02001159};
1160
1161/* type-safe method to obtain iso7816_3_priv from fi */
1162static struct tpdu_fsm_priv *get_tpdu_fsm_priv(struct osmo_fsm_inst *fi)
1163{
1164 OSMO_ASSERT(fi);
1165 OSMO_ASSERT(fi->fsm == &tpdu_fsm);
1166 return (struct tpdu_fsm_priv *) fi->priv;
1167}
1168
Eric Wild9e622dc2019-11-27 14:43:16 +01001169static void tpdu_s_init_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
1170{
1171 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
1172
1173 /* notify in case card got pulled out */
Eric Wild759a6462019-11-11 14:22:52 +01001174 if (tfp->tpdu && old_state != TPDU_S_DONE){
Eric Wild9e622dc2019-11-27 14:43:16 +01001175 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_TPDU_FAILED_IND, tfp->tpdu);
1176 tfp->tpdu = 0;
1177 }
1178}
Harald Welte06348362019-05-19 00:45:17 +02001179
1180static void tpdu_s_init_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1181{
1182 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
1183 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1184 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1185 struct osim_apdu_cmd_hdr *tpduh;
1186
1187 switch (event) {
1188 case ISO7816_E_XCEIVE_TPDU_CMD:
1189 /* start transmission of a TPDU by sending the 5-byte header */
1190 tfp->tpdu = (struct msgb *)data;
1191 OSMO_ASSERT(msgb_length(tfp->tpdu) >= sizeof(*tpduh));
Harald Welte43281fe2020-07-30 20:29:02 +02001192 /* l2h = after the 5byte header */
Harald Welte06348362019-05-19 00:45:17 +02001193 tfp->tpdu->l2h = msgb_data(tfp->tpdu) + sizeof(*tpduh);
Harald Welte43281fe2020-07-30 20:29:02 +02001194 /* l4h = where we start to receive from the card */
1195 tfp->tpdu->l4h = msgb_l2(tfp->tpdu) + msgb_l2len(tfp->tpdu);
Harald Welte65087832019-10-01 09:16:49 +02001196 if (msgb_l2len(tfp->tpdu)) {
1197 tfp->is_command = true;
Harald Welte43281fe2020-07-30 20:29:02 +02001198 /* l3h = used as 'next byte to write' pointer */
Harald Welte65087832019-10-01 09:16:49 +02001199 tfp->tpdu->l3h = tfp->tpdu->l2h; /* next tx byte == first byte of body */
1200 } else
1201 tfp->is_command = false;
1202 tpduh = msgb_tpdu_hdr(tfp->tpdu);
1203 LOGPFSML(fi, LOGL_DEBUG, "Transmitting %s TPDU header %s via UART\n",
1204 tfp->is_command ? "COMMAND" : "RESPONSE",
Harald Welte06348362019-05-19 00:45:17 +02001205 osmo_hexdump_nospc((uint8_t *) tpduh, sizeof(*tpduh)));
1206 osmo_fsm_inst_state_chg(fi, TPDU_S_TX_HDR, 0, 0);
Harald Welte6603d952019-10-09 20:50:13 +02001207 card_uart_tx(ip->uart, (uint8_t *) tpduh, sizeof(*tpduh), true);
Harald Welte06348362019-05-19 00:45:17 +02001208 break;
1209 default:
1210 OSMO_ASSERT(0);
1211 }
1212}
1213
Eric Wilde84a5712019-11-28 17:30:30 +01001214
Harald Welte06348362019-05-19 00:45:17 +02001215static void tpdu_s_tx_hdr_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1216{
Eric Wild2f5cdd12019-11-27 18:40:44 +01001217 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1218 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
Harald Welte06348362019-05-19 00:45:17 +02001219 OSMO_ASSERT(fi->fsm == &tpdu_fsm);
1220 switch (event) {
1221 case ISO7816_E_TX_COMPL:
Eric Wild2f5cdd12019-11-27 18:40:44 +01001222
1223 card_uart_set_rx_threshold(ip->uart, 1);
1224 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 1);
Harald Welte06348362019-05-19 00:45:17 +02001225 /* Rx of single byte is already enabled by previous card_uart_tx() call */
1226 osmo_fsm_inst_state_chg(fi, TPDU_S_PROCEDURE, 0, 0);
1227 break;
1228 default:
1229 OSMO_ASSERT(0);
1230 }
1231}
1232
1233
Eric Wilde84a5712019-11-28 17:30:30 +01001234#if 0
1235#include <hal_gpio.h>
1236#endif
Harald Welte06348362019-05-19 00:45:17 +02001237static void tpdu_s_procedure_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1238{
1239 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
Harald Welte65087832019-10-01 09:16:49 +02001240 struct osim_apdu_cmd_hdr *tpduh = msgb_tpdu_hdr(tfp->tpdu);
Harald Welte06348362019-05-19 00:45:17 +02001241 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1242 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1243 uint8_t byte;
1244
1245 switch (event) {
1246 case ISO7816_E_RX_SINGLE:
1247 byte = get_rx_byte_evt(fi->proc.parent, data);
1248 LOGPFSML(fi, LOGL_DEBUG, "Received 0x%02x from UART\n", byte);
1249 if (byte == 0x60) {
1250 /* NULL: wait for another procedure byte */
Eric Wild2f5cdd12019-11-27 18:40:44 +01001251 card_uart_set_rx_threshold(ip->uart, 1);
1252 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 1);
Harald Welte06348362019-05-19 00:45:17 +02001253 osmo_fsm_inst_state_chg(fi, TPDU_S_PROCEDURE, 0, 0);
1254 } else if ((byte >= 0x60 && byte <= 0x6f) || (byte >= 0x90 && byte <= 0x9f)) {
1255 //msgb_apdu_sw(tfp->apdu) = byte << 8;
1256 msgb_put(tfp->tpdu, byte);
1257 /* receive second SW byte (SW2) */
Eric Wild2f5cdd12019-11-27 18:40:44 +01001258 card_uart_set_rx_threshold(ip->uart, 1);
1259 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 1);
Harald Welte06348362019-05-19 00:45:17 +02001260 osmo_fsm_inst_state_chg(fi, TPDU_S_SW2, 0, 0);
1261 break;
1262 } else if (byte == tpduh->ins) {
Harald Welte65087832019-10-01 09:16:49 +02001263 if (tfp->is_command) {
Harald Welte06348362019-05-19 00:45:17 +02001264 /* transmit all remaining bytes */
Eric Wild9a2279c2019-11-27 18:30:18 +01001265#if 0
1266// rx -> tx delay
1267 gpio_set_pin_level(PIN_PB12, true);
1268 delay_us(1);
1269 gpio_set_pin_level(PIN_PB12, false);
1270#endif
Harald Welte6603d952019-10-09 20:50:13 +02001271 card_uart_tx(ip->uart, msgb_l2(tfp->tpdu), msgb_l2len(tfp->tpdu), true);
Harald Welte06348362019-05-19 00:45:17 +02001272 osmo_fsm_inst_state_chg(fi, TPDU_S_TX_REMAINING, 0, 0);
1273 } else {
1274 card_uart_set_rx_threshold(ip->uart, tpduh->p3);
Eric Wild2f5cdd12019-11-27 18:40:44 +01001275 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, tpduh->p3);
Harald Welte06348362019-05-19 00:45:17 +02001276 osmo_fsm_inst_state_chg(fi, TPDU_S_RX_REMAINING, 0, 0);
1277 }
1278 } else if (byte == (tpduh->ins ^ 0xFF)) {
Harald Welte65087832019-10-01 09:16:49 +02001279 /* transmit/recieve single byte then wait for proc */
1280 if (tfp->is_command) {
1281 /* transmit *next*, not first byte */
1282 OSMO_ASSERT(msgb_l3len(tfp->tpdu) >= 0);
Harald Welte6603d952019-10-09 20:50:13 +02001283 card_uart_tx(ip->uart, msgb_l3(tfp->tpdu), 1, false);
Harald Welte65087832019-10-01 09:16:49 +02001284 osmo_fsm_inst_state_chg(fi, TPDU_S_TX_SINGLE, 0, 0);
1285 } else {
Eric Wild2f5cdd12019-11-27 18:40:44 +01001286 card_uart_set_rx_threshold(ip->uart, 1);
1287 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 1);
Harald Welte65087832019-10-01 09:16:49 +02001288 osmo_fsm_inst_state_chg(fi, TPDU_S_RX_SINGLE, 0, 0);
1289 }
Harald Welte06348362019-05-19 00:45:17 +02001290 } else
1291 OSMO_ASSERT(0);
1292 break;
1293 default:
1294 OSMO_ASSERT(0);
1295 }
1296}
1297
1298/* UART is transmitting remaining data; we wait for ISO7816_E_TX_COMPL */
1299static void tpdu_s_tx_remaining_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1300{
1301 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1302 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1303
1304 switch (event) {
1305 case ISO7816_E_TX_COMPL:
1306 card_uart_set_rx_threshold(ip->uart, 1);
Eric Wild2f5cdd12019-11-27 18:40:44 +01001307 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 1);
Harald Welte06348362019-05-19 00:45:17 +02001308 osmo_fsm_inst_state_chg(fi, TPDU_S_SW1, 0, 0);
1309 break;
1310 default:
1311 OSMO_ASSERT(0);
1312 }
1313}
1314
1315/* UART is transmitting single byte of data; we wait for ISO7816_E_TX_COMPL */
1316static void tpdu_s_tx_single_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1317{
Harald Welte65087832019-10-01 09:16:49 +02001318 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
Eric Wild2f5cdd12019-11-27 18:40:44 +01001319 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1320 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
Harald Welte65087832019-10-01 09:16:49 +02001321
Harald Welte06348362019-05-19 00:45:17 +02001322 switch (event) {
1323 case ISO7816_E_TX_COMPL:
Harald Welte65087832019-10-01 09:16:49 +02001324 tfp->tpdu->l3h += 1;
Eric Wild2f5cdd12019-11-27 18:40:44 +01001325 card_uart_set_rx_threshold(ip->uart, 1);
1326 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 1);
Harald Welte65087832019-10-01 09:16:49 +02001327 if (msgb_l3len(tfp->tpdu))
1328 osmo_fsm_inst_state_chg(fi, TPDU_S_PROCEDURE, 0, 0);
1329 else
1330 osmo_fsm_inst_state_chg(fi, TPDU_S_SW1, 0, 0);
Harald Welte06348362019-05-19 00:45:17 +02001331 break;
1332 default:
1333 OSMO_ASSERT(0);
1334 }
1335}
1336
1337/* UART is receiving remaining data; we wait for ISO7816_E_RX_COMPL */
1338static void tpdu_s_rx_remaining_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1339{
1340 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
Harald Welte65087832019-10-01 09:16:49 +02001341 struct osim_apdu_cmd_hdr *tpduh = msgb_tpdu_hdr(tfp->tpdu);
Harald Welte06348362019-05-19 00:45:17 +02001342 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1343 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1344 int rc;
1345
1346 switch (event) {
1347 case ISO7816_E_RX_COMPL:
1348 /* retrieve pending byte(s) */
1349 rc = card_uart_rx(ip->uart, msgb_l2(tfp->tpdu), tpduh->p3);
Harald Welte65087832019-10-01 09:16:49 +02001350 OSMO_ASSERT(rc > 0);
1351 msgb_put(tfp->tpdu, rc);
1352 if (msgb_l2len(tfp->tpdu) != tpduh->p3) {
1353 LOGPFSML(fi, LOGL_ERROR, "expected %u bytes; read %d\n", tpduh->p3,
1354 msgb_l2len(tfp->tpdu));
1355 }
Harald Welte06348362019-05-19 00:45:17 +02001356 card_uart_set_rx_threshold(ip->uart, 1);
Eric Wild2f5cdd12019-11-27 18:40:44 +01001357 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 1);
Harald Welte06348362019-05-19 00:45:17 +02001358 osmo_fsm_inst_state_chg(fi, TPDU_S_SW1, 0, 0);
1359 break;
1360 default:
1361 OSMO_ASSERT(0);
1362 }
1363}
1364
1365/* UART is receiving single byte of data; we wait for ISO7816_E_RX_SINGLE */
1366static void tpdu_s_rx_single_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1367{
1368 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
Harald Welte65087832019-10-01 09:16:49 +02001369 struct osim_apdu_cmd_hdr *tpduh = msgb_tpdu_hdr(tfp->tpdu);
Eric Wild2f5cdd12019-11-27 18:40:44 +01001370 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1371 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
Harald Welte06348362019-05-19 00:45:17 +02001372 uint8_t byte;
1373
1374 switch (event) {
1375 case ISO7816_E_RX_SINGLE:
1376 byte = get_rx_byte_evt(fi->proc.parent, data);
1377 LOGPFSML(fi, LOGL_DEBUG, "Received 0x%02x from UART\n", byte);
Harald Welte65087832019-10-01 09:16:49 +02001378 msgb_put_u8(tfp->tpdu, byte);
Eric Wild2f5cdd12019-11-27 18:40:44 +01001379
1380 card_uart_set_rx_threshold(ip->uart, 1);
1381 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 1);
1382
Harald Welte65087832019-10-01 09:16:49 +02001383 /* determine if number of expected bytes received */
1384 if (msgb_l2len(tfp->tpdu) == tpduh->p3)
Harald Welte06348362019-05-19 00:45:17 +02001385 osmo_fsm_inst_state_chg(fi, TPDU_S_SW1, 0, 0);
Harald Welte65087832019-10-01 09:16:49 +02001386 else
Harald Welte06348362019-05-19 00:45:17 +02001387 osmo_fsm_inst_state_chg(fi, TPDU_S_PROCEDURE, 0, 0);
1388 break;
1389 default:
1390 OSMO_ASSERT(0);
1391 }
1392}
1393
1394static void tpdu_s_sw1_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1395{
1396 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
1397 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1398 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1399 uint8_t byte;
1400
1401 switch (event) {
1402 case ISO7816_E_RX_SINGLE:
1403 byte = get_rx_byte_evt(fi->proc.parent, data);
1404 LOGPFSML(fi, LOGL_DEBUG, "Received 0x%02x from UART\n", byte);
1405 /* record byte */
1406 //msgb_apdu_sw(tfp->apdu) = byte << 8;
1407 msgb_put_u8(tfp->tpdu, byte);
1408 card_uart_set_rx_threshold(ip->uart, 1);
Eric Wild2f5cdd12019-11-27 18:40:44 +01001409 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 1);
Harald Welte06348362019-05-19 00:45:17 +02001410 osmo_fsm_inst_state_chg(fi, TPDU_S_SW2, 0, 0);
1411 break;
1412 default:
1413 OSMO_ASSERT(0);
1414 }
1415}
1416
1417static void tpdu_s_sw2_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1418{
1419 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
1420 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1421 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1422 uint8_t byte;
1423
1424 switch (event) {
1425 case ISO7816_E_RX_SINGLE:
1426 byte = get_rx_byte_evt(fi->proc.parent, data);
1427 LOGPFSML(fi, LOGL_DEBUG, "Received 0x%02x from UART\n", byte);
1428 /* record SW2 byte */
1429 //msgb_apdu_sw(tfp->apdu) &= 0xFF00;
1430 //msgb_apdu_sw(tfp->apdu) |= byte;
1431 msgb_put_u8(tfp->tpdu, byte);
1432 osmo_fsm_inst_state_chg(fi, TPDU_S_DONE, 0, 0);
1433 /* Notify parent FSM */
1434 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_TPDU_DONE_IND, tfp->tpdu);
Eric Wild9e622dc2019-11-27 14:43:16 +01001435
1436 /* ownership transfer */
1437 tfp->tpdu = 0;
Harald Welte06348362019-05-19 00:45:17 +02001438 break;
1439 default:
1440 OSMO_ASSERT(0);
1441 }
1442}
1443
1444static void tpdu_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1445{
1446 OSMO_ASSERT(fi->fsm == &tpdu_fsm);
1447
1448 switch (event) {
1449 case ISO7816_E_RX_ERR_IND:
1450 case ISO7816_E_TX_ERR_IND:
1451 /* FIXME: handle this in some different way */
1452 osmo_fsm_inst_state_chg(fi, TPDU_S_DONE, 0, 0);
Eric Wild2f5cdd12019-11-27 18:40:44 +01001453 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_TPDU_FAILED_IND, NULL);
Harald Welte06348362019-05-19 00:45:17 +02001454 break;
1455 case ISO7816_E_TPDU_CLEAR_REQ:
1456 osmo_fsm_inst_state_chg(fi, TPDU_S_INIT, 0, 0);
1457 break;
1458 }
1459}
1460
Eric Wild2f5cdd12019-11-27 18:40:44 +01001461
1462static void tpdu_s_done_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
1463{
1464 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1465 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1466
1467 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 0);
1468}
1469
Harald Welte06348362019-05-19 00:45:17 +02001470static const struct osmo_fsm_state tpdu_states[] = {
1471 [TPDU_S_INIT] = {
1472 .name = "INIT",
1473 .in_event_mask = S(ISO7816_E_XCEIVE_TPDU_CMD) |
1474 S(ISO7816_E_TX_COMPL),
1475 .out_state_mask = S(TPDU_S_INIT) |
1476 S(TPDU_S_TX_HDR),
1477 .action = tpdu_s_init_action,
Eric Wild9e622dc2019-11-27 14:43:16 +01001478 .onenter = tpdu_s_init_onenter,
Harald Welte06348362019-05-19 00:45:17 +02001479 },
1480 [TPDU_S_TX_HDR] = {
1481 .name = "TX_HDR",
1482 .in_event_mask = S(ISO7816_E_TX_COMPL),
1483 .out_state_mask = S(TPDU_S_INIT) |
1484 S(TPDU_S_PROCEDURE),
1485 .action = tpdu_s_tx_hdr_action,
1486 },
1487 [TPDU_S_PROCEDURE] = {
1488 .name = "PROCEDURE",
1489 .in_event_mask = S(ISO7816_E_RX_SINGLE),
1490 .out_state_mask = S(TPDU_S_INIT) |
1491 S(TPDU_S_PROCEDURE) |
1492 S(TPDU_S_RX_REMAINING) |
1493 S(TPDU_S_RX_SINGLE) |
1494 S(TPDU_S_TX_REMAINING) |
1495 S(TPDU_S_TX_SINGLE) |
1496 S(TPDU_S_SW2),
1497 .action = tpdu_s_procedure_action,
1498 },
1499 [TPDU_S_TX_REMAINING] = {
1500 .name = "TX_REMAINING",
1501 .in_event_mask = S(ISO7816_E_TX_COMPL),
1502 .out_state_mask = S(TPDU_S_INIT) |
1503 S(TPDU_S_SW1),
1504 .action = tpdu_s_tx_remaining_action,
1505 },
1506 [TPDU_S_TX_SINGLE] = {
1507 .name = "TX_SINGLE",
1508 .in_event_mask = S(ISO7816_E_TX_COMPL),
1509 .out_state_mask = S(TPDU_S_INIT) |
1510 S(TPDU_S_PROCEDURE),
1511 .action = tpdu_s_tx_single_action,
1512 },
1513 [TPDU_S_RX_REMAINING] = {
1514 .name = "RX_REMAINING",
1515 .in_event_mask = S(ISO7816_E_RX_COMPL),
1516 .out_state_mask = S(TPDU_S_INIT) |
1517 S(TPDU_S_SW1),
1518 .action = tpdu_s_rx_remaining_action,
1519 },
1520 [TPDU_S_RX_SINGLE] = {
1521 .name = "RX_SINGLE",
1522 .in_event_mask = S(ISO7816_E_RX_SINGLE),
1523 .out_state_mask = S(TPDU_S_INIT) |
1524 S(TPDU_S_PROCEDURE),
1525 .action = tpdu_s_rx_single_action,
1526 },
1527 [TPDU_S_SW1] = {
1528 .name = "SW1",
1529 .in_event_mask = S(ISO7816_E_RX_SINGLE),
1530 .out_state_mask = S(TPDU_S_INIT) |
1531 S(TPDU_S_SW2),
1532 .action = tpdu_s_sw1_action,
1533 },
1534 [TPDU_S_SW2] = {
1535 .name = "SW2",
1536 .in_event_mask = S(ISO7816_E_RX_SINGLE),
1537 .out_state_mask = S(TPDU_S_INIT) |
1538 S(TPDU_S_DONE),
1539 .action = tpdu_s_sw2_action,
1540 },
1541 [TPDU_S_DONE] = {
1542 .name = "DONE",
1543 .in_event_mask = 0,
1544 .out_state_mask = S(TPDU_S_INIT),
1545 .action = NULL,
Eric Wild2f5cdd12019-11-27 18:40:44 +01001546 .onenter = tpdu_s_done_onenter,
Harald Welte06348362019-05-19 00:45:17 +02001547 },
1548};
1549static struct osmo_fsm tpdu_fsm = {
1550 .name = "TPDU",
1551 .states = tpdu_states,
1552 .num_states = ARRAY_SIZE(tpdu_states),
1553 .allstate_event_mask = S(ISO7816_E_RX_ERR_IND) |
1554 S(ISO7816_E_TX_ERR_IND) |
1555 S(ISO7816_E_TPDU_CLEAR_REQ),
1556 .allstate_action = tpdu_allstate_action,
1557 .log_subsys = DTPDU,
1558 .event_names = iso7816_3_event_names,
1559};
1560
1561struct osmo_fsm_inst *iso7816_fsm_alloc(void *ctx, int log_level, const char *id,
1562 struct card_uart *cuart, iso7816_user_cb user_cb,
1563 void *user_priv)
1564{
1565 struct iso7816_3_priv *ip;
1566 struct osmo_fsm_inst *fi;
1567
1568 fi = osmo_fsm_inst_alloc(&iso7816_3_fsm, ctx, NULL, log_level, id);
1569 ip = talloc_zero(fi, struct iso7816_3_priv);
1570 if (!ip)
1571 goto out_fi;
1572 fi->priv = ip;
1573
1574 ip->uart = cuart;
1575 cuart->priv = fi;
1576 cuart->handle_event = tpdu_uart_notification;
1577
1578 ip->user_cb = user_cb;
1579 ip->user_priv = user_priv;
1580
1581 ip->atr_fi = osmo_fsm_inst_alloc_child(&atr_fsm, fi, ISO7816_E_SW_ERR_IND);
1582 if (!ip->atr_fi)
1583 goto out_fi;
1584 ip->atr_fi->priv = talloc_zero(ip->atr_fi, struct atr_fsm_priv);
1585 if (!ip->atr_fi->priv)
1586 goto out_atr;
1587
1588 ip->tpdu_fi = osmo_fsm_inst_alloc_child(&tpdu_fsm, fi, ISO7816_E_SW_ERR_IND);
1589 if (!ip->tpdu_fi)
1590 goto out_atr;
1591 ip->tpdu_fi->priv = talloc_zero(ip->tpdu_fi, struct tpdu_fsm_priv);
1592 if (!ip->tpdu_fi->priv)
1593 goto out_tpdu;
1594
Eric Wildad1edce2019-11-27 16:51:08 +01001595#if 1
Harald Welte06348362019-05-19 00:45:17 +02001596 ip->pps_fi = osmo_fsm_inst_alloc_child(&pps_fsm, fi, ISO7816_E_SW_ERR_IND);
1597 if (!ip->pps_fi)
1598 goto out_tpdu;
1599 ip->pps_fi->priv = talloc_zero(ip->pps_fi, struct pps_fsm_priv);
1600 if (!ip->pps_fi->priv)
1601 goto out_pps;
1602#endif
1603
1604 /* This ensures the 'onenter' function of the initial state is called */
1605 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
1606
1607 return fi;
1608
Eric Wildad1edce2019-11-27 16:51:08 +01001609#if 1
Harald Welte06348362019-05-19 00:45:17 +02001610out_pps:
1611 osmo_fsm_inst_free(ip->pps_fi);
1612#endif
1613out_tpdu:
1614 osmo_fsm_inst_free(ip->tpdu_fi);
1615out_atr:
1616 osmo_fsm_inst_free(ip->atr_fi);
1617out_fi:
1618 osmo_fsm_inst_free(fi);
1619 cuart->priv = NULL;
1620 return NULL;
1621}
1622
1623void *iso7816_fsm_get_user_priv(struct osmo_fsm_inst *fi)
1624{
1625 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
1626 return ip->user_priv;
1627}
1628
1629
1630static __attribute__((constructor)) void on_dso_load_iso7816(void)
1631{
Harald Welte89b1e062019-12-01 13:30:14 +01001632 OSMO_ASSERT(osmo_fsm_register(&iso7816_3_fsm) == 0);
1633 OSMO_ASSERT(osmo_fsm_register(&atr_fsm) == 0);
1634 OSMO_ASSERT(osmo_fsm_register(&tpdu_fsm) == 0);
1635 OSMO_ASSERT(osmo_fsm_register(&pps_fsm) == 0);
Harald Welte06348362019-05-19 00:45:17 +02001636}