blob: 2796d308e7c86ef84ed6032c0265cdf5b8a1b4a6 [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
131/***********************************************************************
132 * ISO7816-3 Main FSM
133 ***********************************************************************/
134
135static const struct value_string iso7816_3_event_names[] = {
136 { ISO7816_E_RX_SINGLE, "UART_RX_SINGLE" },
137 { ISO7816_E_RX_COMPL, "UART_RX_COMPL" },
138 { ISO7816_E_TX_COMPL, "UART_TX_COMPL" },
139 { ISO7816_E_POWER_UP_IND, "POWER_UP_IND" },
140 { ISO7816_E_RESET_REL_IND, "RESET_REL_IND" },
141 { ISO7816_E_RX_ERR_IND, "RX_ERR_IND" },
142 { ISO7816_E_TX_ERR_IND, "TX_ERR_IND" },
143 { ISO7816_E_ATR_DONE_IND, "ATR_DONE_IND" },
Harald Welte1ac9ef92019-10-09 22:20:16 +0200144 { ISO7816_E_ATR_ERR_IND, "ATR_ERR_IND" },
Harald Welte06348362019-05-19 00:45:17 +0200145 { ISO7816_E_TPDU_DONE_IND, "TPDU_DONE_IND" },
146 { ISO7816_E_XCEIVE_TPDU_CMD, "XCEIVE_TPDU_CMD" },
147 /* allstate events */
148 { ISO7816_E_WTIME_EXP, "WAIT_TIME_EXP" },
149 { ISO7816_E_HW_ERR_IND, "HW_ERR_IND" },
150 { ISO7816_E_SW_ERR_IND, "SW_ERR_IND" },
151 { ISO7816_E_CARD_REMOVAL, "CARD_REMOVAL" },
152 { ISO7816_E_POWER_DN_IND, "POWER_DN_IND" },
153 { ISO7816_E_RESET_ACT_IND, "RESET_ACT_IND" },
154 { ISO7816_E_ABORT_REQ, "ABORT_REQ" },
155 { ISO7816_E_TPDU_CLEAR_REQ, "TPDU_CLEAR_REQ" },
156 { 0, NULL }
157};
158
159struct iso7816_3_priv {
160 uint8_t slot_nr;
161 /* child FSM instances */
162 struct osmo_fsm_inst *atr_fi;
163 struct osmo_fsm_inst *pps_fi;
164 struct osmo_fsm_inst *tpdu_fi;
165 /* other data */
166 bool convention_convert;/*!< If convention conversion is needed */
167 uint16_t guard_time_ms;
168 /* underlying UART */
169 struct card_uart *uart;
170 iso7816_user_cb user_cb;
171 void *user_priv;
172};
173
174/* type-safe method to obtain iso7816_3_priv from fi */
175static struct iso7816_3_priv *get_iso7816_3_priv(struct osmo_fsm_inst *fi)
176{
177 OSMO_ASSERT(fi);
178 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
179 return (struct iso7816_3_priv *) fi->priv;
180}
181
182/* convert from clock cycles of the CLK line to milli-seconds */
183uint32_t fi_cycles2ms(struct osmo_fsm_inst *fi, uint32_t cyclces)
184{
185 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
186 /* FIXME */
187 return 1000;
188}
189
190/* card UART notifies us: dispatch to (main ISO7816-3) FSM */
191static void tpdu_uart_notification(struct card_uart *cuart, enum card_uart_event evt, void *data)
192{
193 struct osmo_fsm_inst *fi = (struct osmo_fsm_inst *) cuart->priv;
194 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
195
196 LOGPFSML(fi, LOGL_DEBUG, "UART Notification '%s'\n",
197 get_value_string(card_uart_event_vals, evt));
198
199 /* FIXME: Set only flags here; Main loop polls flags and dispatches events */
200
201 switch (evt) {
202 case CUART_E_RX_SINGLE:
203 osmo_fsm_inst_dispatch(fi, ISO7816_E_RX_SINGLE, data);
204 break;
205 case CUART_E_RX_COMPLETE:
206 osmo_fsm_inst_dispatch(fi, ISO7816_E_RX_COMPL, data);
207 break;
208 case CUART_E_RX_TIMEOUT:
209 osmo_fsm_inst_dispatch(fi, ISO7816_E_WTIME_EXP, data);
210 break;
211 case CUART_E_TX_COMPLETE:
212 osmo_fsm_inst_dispatch(fi, ISO7816_E_TX_COMPL, data);
213 break;
214 }
215}
216
217static void iso7816_3_reset_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
218{
219 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
220 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
221
Eric Wild2f5cdd12019-11-27 18:40:44 +0100222 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 0);
223
Harald Welte06348362019-05-19 00:45:17 +0200224 /* go back to initial state in child FSMs */
225 osmo_fsm_inst_state_chg(ip->atr_fi, ATR_S_WAIT_TS, 0, 0);
Eric Wild2f5cdd12019-11-27 18:40:44 +0100226 osmo_fsm_inst_state_chg(ip->pps_fi, PPS_S_PPS_REQ_INIT, 0, 0);
Harald Welte06348362019-05-19 00:45:17 +0200227 osmo_fsm_inst_state_chg(ip->tpdu_fi, TPDU_S_INIT, 0, 0);
228}
229
230static void iso7816_3_reset_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
231{
232 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
233 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
Eric Wild9e622dc2019-11-27 14:43:16 +0100234 struct msgb *msg;
Harald Welte06348362019-05-19 00:45:17 +0200235
236 switch (event) {
237 case ISO7816_E_RESET_REL_IND:
238 /* TOOD: this should happen before reset is released */
239 card_uart_ctrl(ip->uart, CUART_CTL_RX, true);
Eric Wild2f5cdd12019-11-27 18:40:44 +0100240
241 /* let's be reasonable here: the 40k cycle delay to ATR start is
242 * ~1.4ms @ 2.5Mhz/6720 baud, 1ETU = 372 cycles -> 40k/372=107/12ETU ~ 9 byte
243 * default timeout for rx is 9600 ETU, ATR might be missing the TCK
244 * so it might time out, so just add this delay */
245 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 32+9);
246 osmo_fsm_inst_state_chg(fi, ISO7816_S_WAIT_ATR, 0, 0);
Harald Welte06348362019-05-19 00:45:17 +0200247 break;
Eric Wild759a6462019-11-11 14:22:52 +0100248 case ISO7816_E_POWER_UP_IND:
249 break;
Eric Wild9e622dc2019-11-27 14:43:16 +0100250 case ISO7816_E_PPS_FAILED_IND:
251 msg = data;
252 /* notify user about PPS result */
253 ip->user_cb(fi, event, 0, msg);
254 break;
255 case ISO7816_E_TPDU_FAILED_IND:
256 msg = data;
257 /* hand finished TPDU to user */
258 ip->user_cb(fi, event, 0, msg);
259 break;
Harald Welte06348362019-05-19 00:45:17 +0200260 default:
261 OSMO_ASSERT(0);
262 }
263}
264
265static void iso7816_3_wait_atr_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
266{
267 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
268 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
269
270 switch (event) {
271 case ISO7816_E_RX_SINGLE:
272 osmo_fsm_inst_state_chg(fi, ISO7816_S_IN_ATR, 0, 0);
273 osmo_fsm_inst_dispatch(ip->atr_fi, event, data);
274 break;
Harald Welte1ac9ef92019-10-09 22:20:16 +0200275 case ISO7816_E_WTIME_EXP:
276 ip->user_cb(fi, event, 0, NULL);
277 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
278 break;
Harald Welte06348362019-05-19 00:45:17 +0200279 default:
280 OSMO_ASSERT(0);
281 }
282}
283
284static void iso7816_3_in_atr_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
285{
286 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
287 struct msgb *atr;
288 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
289
290 switch (event) {
291 case ISO7816_E_RX_SINGLE:
292 case ISO7816_E_RX_ERR_IND:
Harald Welte1ac9ef92019-10-09 22:20:16 +0200293 case ISO7816_E_WTIME_EXP:
Harald Welte06348362019-05-19 00:45:17 +0200294 /* simply pass this through to the child FSM for the ATR */
295 osmo_fsm_inst_dispatch(ip->atr_fi, event, data);
296 break;
297 case ISO7816_E_ATR_DONE_IND:
298 atr = data;
299 /* FIXME: verify ATR result: success / failure */
300 osmo_fsm_inst_state_chg(fi, ISO7816_S_WAIT_TPDU, 0, 0);
301 /* notify user about ATR */
302 ip->user_cb(fi, event, 0, atr);
303 break;
Harald Welte1ac9ef92019-10-09 22:20:16 +0200304 case ISO7816_E_ATR_ERR_IND:
Eric Wild91552312019-11-18 13:57:11 +0100305 atr = data;
Harald Welte1ac9ef92019-10-09 22:20:16 +0200306 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
307 ip->user_cb(fi, event, 0, atr);
308 break;
Harald Welte06348362019-05-19 00:45:17 +0200309 default:
310 OSMO_ASSERT(0);
311 }
312}
313
314static void iso7816_3_wait_tpdu_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
315{
316 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
317 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
Eric Wild2f5cdd12019-11-27 18:40:44 +0100318 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 0);
Eric Wildfd0bace2019-11-27 18:33:09 +0100319 card_uart_ctrl(ip->uart, CUART_CTL_NO_RXTX, true);
Harald Welte06348362019-05-19 00:45:17 +0200320 /* reset the TPDU state machine */
321 osmo_fsm_inst_dispatch(ip->tpdu_fi, ISO7816_E_TPDU_CLEAR_REQ, NULL);
322}
323
324static void iso7816_3_wait_tpdu_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
325{
326 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
327 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
328
329 switch (event) {
330 case ISO7816_E_XCEIVE_TPDU_CMD:
331 /* "data" contains a msgb-wrapped TPDU */
332 osmo_fsm_inst_state_chg(fi, ISO7816_S_IN_TPDU, 0, 0);
333 /* pass on to sub-fsm */
334 osmo_fsm_inst_dispatch(ip->tpdu_fi, event, data);
335 break;
Eric Wildad1edce2019-11-27 16:51:08 +0100336 case ISO7816_E_XCEIVE_PPS_CMD:
337 osmo_fsm_inst_state_chg(fi, ISO7816_S_WAIT_PPS_RSP, 0, 0);
Eric Wild2f5cdd12019-11-27 18:40:44 +0100338 osmo_fsm_inst_state_chg(ip->pps_fi, PPS_S_PPS_REQ_INIT, 0, 0);
Eric Wildad1edce2019-11-27 16:51:08 +0100339 osmo_fsm_inst_dispatch(ip->pps_fi, event, data);
340 break;
Harald Welte06348362019-05-19 00:45:17 +0200341 default:
342 OSMO_ASSERT(0);
343 }
344}
345
346static void iso7816_3_in_tpdu_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
347{
348 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
349 struct msgb *apdu;
350 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
351
352 switch (event) {
353 case ISO7816_E_RX_SINGLE:
354 case ISO7816_E_RX_COMPL:
355 case ISO7816_E_RX_ERR_IND:
356 case ISO7816_E_TX_COMPL:
357 case ISO7816_E_TX_ERR_IND:
358 /* simply pass this through to the child FSM for the ATR */
359 osmo_fsm_inst_dispatch(ip->tpdu_fi, event, data);
360 break;
361 case ISO7816_E_TPDU_DONE_IND:
362 apdu = data;
363 osmo_fsm_inst_state_chg(fi, ISO7816_S_WAIT_TPDU, 0, 0);
364 /* hand finished TPDU to user */
365 ip->user_cb(fi, event, 0, apdu);
366 break;
Harald Welte1ac9ef92019-10-09 22:20:16 +0200367 case ISO7816_E_WTIME_EXP:
368 /* FIXME: power off? */
369 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
370 break;
Harald Welte06348362019-05-19 00:45:17 +0200371 default:
372 OSMO_ASSERT(0);
373 }
374}
375
376static void iso7816_3_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
377{
378 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
379
380 switch (event) {
Harald Welte06348362019-05-19 00:45:17 +0200381 case ISO7816_E_HW_ERR_IND:
382 case ISO7816_E_CARD_REMOVAL:
383 /* FIXME: power off? */
384 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
385 break;
386 case ISO7816_E_POWER_DN_IND:
387 case ISO7816_E_RESET_ACT_IND:
388 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
389 break;
390 case ISO7816_E_ABORT_REQ:
391 /* FIXME */
392 break;
393 default:
394 OSMO_ASSERT(0);
395 break;
396 }
397}
398
Eric Wildad1edce2019-11-27 16:51:08 +0100399
400static void iso7816_3_s_wait_pps_rsp_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
401{
Eric Wild2f5cdd12019-11-27 18:40:44 +0100402 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
Eric Wildad1edce2019-11-27 16:51:08 +0100403 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
404 switch (event) {
405 case ISO7816_E_TX_COMPL:
406 /* Rx of single byte is already enabled by previous card_uart_tx() call */
407 osmo_fsm_inst_state_chg(fi, ISO7816_S_IN_PPS_RSP, 0, 0);
Eric Wild2f5cdd12019-11-27 18:40:44 +0100408 osmo_fsm_inst_dispatch(ip->pps_fi, event, data);
Eric Wildad1edce2019-11-27 16:51:08 +0100409 break;
410 default:
411 OSMO_ASSERT(0);
412 }
413}
414
415static void iso7816_3_s_ins_pps_rsp_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
416{
417 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
418 struct msgb *ppsrsp;
419 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
420
421 switch (event) {
422 case ISO7816_E_RX_SINGLE:
423 case ISO7816_E_WTIME_EXP:
424 /* simply pass this through to the child FSM for the ATR */
425 osmo_fsm_inst_dispatch(ip->pps_fi, event, data);
426 break;
427 case ISO7816_E_PPS_DONE_IND:
428 case ISO7816_E_PPS_FAILED_IND:
429 ppsrsp = data;
430 osmo_fsm_inst_state_chg(fi, ISO7816_S_WAIT_TPDU, 0, 0);
431 /* notify user about PPS result */
432 ip->user_cb(fi, event, 0, ppsrsp);
433 break;
434 case ISO7816_E_RX_ERR_IND:
435 ppsrsp = data;
436 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
437 ip->user_cb(fi, event, 0, ppsrsp);
438 break;
439 default:
440 OSMO_ASSERT(0);
441 }
442}
443
Harald Welte06348362019-05-19 00:45:17 +0200444static const struct osmo_fsm_state iso7816_3_states[] = {
445 [ISO7816_S_RESET] = {
446 .name = "RESET",
Eric Wild9e622dc2019-11-27 14:43:16 +0100447 .in_event_mask = S(ISO7816_E_RESET_REL_IND) |
Eric Wild2f5cdd12019-11-27 18:40:44 +0100448 S(ISO7816_E_POWER_UP_IND) |
Eric Wild9e622dc2019-11-27 14:43:16 +0100449 S(ISO7816_E_PPS_FAILED_IND)|
450 S(ISO7816_E_TPDU_FAILED_IND),
Harald Welte06348362019-05-19 00:45:17 +0200451 .out_state_mask = S(ISO7816_S_WAIT_ATR) |
452 S(ISO7816_S_RESET),
453 .action = iso7816_3_reset_action,
454 .onenter = iso7816_3_reset_onenter,
455 },
456 [ISO7816_S_WAIT_ATR] = {
457 .name = "WAIT_ATR",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200458 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
459 S(ISO7816_E_WTIME_EXP),
Harald Welte06348362019-05-19 00:45:17 +0200460 .out_state_mask = S(ISO7816_S_RESET) |
461 S(ISO7816_S_IN_ATR),
462 .action = iso7816_3_wait_atr_action,
463 },
464 [ISO7816_S_IN_ATR] = {
465 .name = "IN_ATR",
466 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
467 S(ISO7816_E_RX_ERR_IND) |
Harald Welte1ac9ef92019-10-09 22:20:16 +0200468 S(ISO7816_E_ATR_DONE_IND) |
469 S(ISO7816_E_ATR_ERR_IND) |
470 S(ISO7816_E_WTIME_EXP),
Harald Welte06348362019-05-19 00:45:17 +0200471 .out_state_mask = S(ISO7816_S_RESET) |
472 S(ISO7816_S_IN_ATR) |
473 S(ISO7816_S_WAIT_TPDU),
474 .action = iso7816_3_in_atr_action,
475 },
476 [ISO7816_S_WAIT_TPDU] = {
477 .name = "WAIT_TPDU",
Eric Wildad1edce2019-11-27 16:51:08 +0100478 .in_event_mask = S(ISO7816_E_XCEIVE_TPDU_CMD) |
479 S(ISO7816_E_XCEIVE_PPS_CMD),
Harald Welte06348362019-05-19 00:45:17 +0200480 .out_state_mask = S(ISO7816_S_RESET) |
481 S(ISO7816_S_WAIT_TPDU) |
482 S(ISO7816_S_IN_TPDU) |
Eric Wildad1edce2019-11-27 16:51:08 +0100483 S(ISO7816_S_WAIT_PPS_RSP),
Harald Welte06348362019-05-19 00:45:17 +0200484 .action = iso7816_3_wait_tpdu_action,
485 .onenter = iso7816_3_wait_tpdu_onenter,
486 },
487 [ISO7816_S_IN_TPDU] = {
488 .name = "IN_TPDU",
489 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
490 S(ISO7816_E_RX_COMPL) |
491 S(ISO7816_E_TX_COMPL) |
492 S(ISO7816_E_RX_ERR_IND) |
493 S(ISO7816_E_TX_ERR_IND) |
Harald Welte1ac9ef92019-10-09 22:20:16 +0200494 S(ISO7816_E_TPDU_DONE_IND) |
495 S(ISO7816_E_WTIME_EXP),
Harald Welte06348362019-05-19 00:45:17 +0200496 .out_state_mask = S(ISO7816_S_RESET) |
497 S(ISO7816_S_WAIT_TPDU) |
498 S(ISO7816_S_IN_TPDU),
499 .action = iso7816_3_in_tpdu_action,
500 },
Harald Welte06348362019-05-19 00:45:17 +0200501 [ISO7816_S_WAIT_PPS_RSP] = {
502 .name = "WAIT_PPS_RESP",
Eric Wildad1edce2019-11-27 16:51:08 +0100503 .in_event_mask = S(ISO7816_E_TX_COMPL) |
504 S(ISO7816_E_TX_ERR_IND) |
505 S(ISO7816_E_WTIME_EXP),
Harald Welte06348362019-05-19 00:45:17 +0200506 .out_state_mask = S(ISO7816_S_RESET) |
507 S(ISO7816_S_WAIT_TPDU) |
508 S(ISO7816_S_WAIT_PPS_RSP) |
509 S(ISO7816_S_IN_PPS_RSP),
Eric Wildad1edce2019-11-27 16:51:08 +0100510 .action = iso7816_3_s_wait_pps_rsp_action,
Harald Welte06348362019-05-19 00:45:17 +0200511 },
512 [ISO7816_S_IN_PPS_RSP] = {
513 .name = "IN_PPS_RESP",
Eric Wildad1edce2019-11-27 16:51:08 +0100514 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
515 S(ISO7816_E_RX_COMPL) |
516 S(ISO7816_E_RX_ERR_IND) |
517 S(ISO7816_E_PPS_DONE_IND) |
518 S(ISO7816_E_PPS_FAILED_IND) |
519 S(ISO7816_E_WTIME_EXP),
Harald Welte06348362019-05-19 00:45:17 +0200520 .out_state_mask = S(ISO7816_S_RESET) |
521 S(ISO7816_S_WAIT_TPDU) |
522 S(ISO7816_S_IN_PPS_RSP),
Eric Wildad1edce2019-11-27 16:51:08 +0100523 .action = iso7816_3_s_ins_pps_rsp_action,
Harald Welte06348362019-05-19 00:45:17 +0200524 },
525};
526static struct osmo_fsm iso7816_3_fsm = {
527 .name = "ISO7816-3",
528 .states = iso7816_3_states,
529 .num_states = ARRAY_SIZE(iso7816_3_states),
530 .log_subsys = DISO7816,
531 .event_names = iso7816_3_event_names,
532 .allstate_action = iso7816_3_allstate_action,
Harald Welte1ac9ef92019-10-09 22:20:16 +0200533 .allstate_event_mask = S(ISO7816_E_CARD_REMOVAL) |
Harald Welte06348362019-05-19 00:45:17 +0200534 S(ISO7816_E_POWER_DN_IND) |
535 S(ISO7816_E_RESET_ACT_IND) |
536 S(ISO7816_E_HW_ERR_IND) |
537 S(ISO7816_E_ABORT_REQ),
538};
539
540/***********************************************************************
541 * ATR FSM
542 ***********************************************************************/
543
544struct atr_fsm_priv {
545 uint8_t hist_len; /*!< store the number of expected historical bytes */
546 uint8_t y; /*!< last mask of the upcoming TA, TB, TC, TD interface bytes */
547 uint8_t i; /*!< interface byte subgroup number */
548 struct msgb *atr; /*!< ATR data */
549 uint8_t computed_checksum;
550 uint16_t protocol_support;
551};
552
553/* obtain the [software] guard time in milli-seconds from the atr fsm_inst */
554static uint32_t atr_fi_gt_ms(struct osmo_fsm_inst *fi)
555{
556 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
557 struct iso7816_3_priv *ip;
558
559 OSMO_ASSERT(fi->fsm == &atr_fsm);
560 OSMO_ASSERT(parent_fi);
561 ip = get_iso7816_3_priv(parent_fi);
562
563 return ip->guard_time_ms;
564}
565
566/* obtain the 'byte' parmeter of an ISO7816_E_RX event */
567static uint8_t get_rx_byte_evt(struct osmo_fsm_inst *fi, void *data)
568{
569 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
570 uint8_t byte = *(uint8_t *)data;
571
572 /* apply inverse convention */
573 if (ip->convention_convert)
574 byte = convention_convert_lut[byte];
575
576 return byte;
577}
578
579/* append a single byte to the ATR */
580static int atr_append_byte(struct osmo_fsm_inst *fi, uint8_t byte)
581{
582 struct atr_fsm_priv *atp = fi->priv;
583
584 if (!msgb_tailroom(atp->atr)) {
585 LOGPFSML(fi, LOGL_ERROR, "ATR overflow !?!");
586 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_SW_ERR_IND, NULL);
587 return -1;
588 }
589 msgb_put_u8(atp->atr, byte);
590 return 0;
591}
592
593static void atr_wait_ts_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
594{
595 struct atr_fsm_priv *atp = fi->priv;
596
597 /* reset state to its initial value */
598 atp->hist_len = 0;
599 atp->y = 0;
600 atp->i = 0;
601 if (!atp->atr)
602 atp->atr = msgb_alloc_c(fi, 33, "ATR"); /* TS + 32 chars */
603 else
604 msgb_reset(atp->atr);
605 atp->computed_checksum = 0;
606 atp->protocol_support = 0;
607}
608
609static void atr_wait_ts_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
610{
611 struct atr_fsm_priv *atp = fi->priv;
612 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
613 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
614 uint8_t byte;
615
616 switch (event) {
617 case ISO7816_E_RX_SINGLE:
618 OSMO_ASSERT(msgb_length(atp->atr) == 0);
619restart:
620 byte = get_rx_byte_evt(parent_fi, data);
621 LOGPFSML(fi, LOGL_DEBUG, "RX byte '%02x'\n", byte);
622 switch (byte) {
623 case 0x23:
624 /* direct convention used, but decoded using inverse
625 * convention (a parity error should also have occurred) */
626 /* fall-through */
627 case 0x30:
628 /* inverse convention used, but decoded using direct
629 * convention (a parity error should also have occurred) */
630 ip->convention_convert = !ip->convention_convert;
631 goto restart;
632 break;
633 case 0x3b: /* direct convention used and correctly decoded */
634 /* fall-through */
635 case 0x3f: /* inverse convention used and correctly decoded */
636 atr_append_byte(fi, byte);
637 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_T0, atr_fi_gt_ms(fi), T_GUARD);
638 break;
639 default:
640 LOGPFSML(fi, LOGL_ERROR, "Invalid TS received: 0x%02X\n", byte);
641 /* FIXME: somehow indiicate to user */
642 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_SW_ERR_IND, NULL);
643 break;
644 }
645 atp->i = 0; /* first interface byte sub-group is coming (T0 is kind of TD0) */
646 break;
Harald Welte1ac9ef92019-10-09 22:20:16 +0200647 case ISO7816_E_WTIME_EXP:
648 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_ATR_ERR_IND, NULL);
649 break;
Harald Welte06348362019-05-19 00:45:17 +0200650 default:
651 OSMO_ASSERT(0);
652 }
653}
654
655static void atr_wait_tX_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
656{
657 struct atr_fsm_priv *atp = fi->priv;
658 uint32_t guard_time_ms = atr_fi_gt_ms(fi);
659 uint8_t byte;
660
661 switch (event) {
662 case ISO7816_E_RX_SINGLE:
663 byte = get_rx_byte_evt(fi->proc.parent, data);
664 LOGPFSML(fi, LOGL_DEBUG, "RX byte '%02x'\n", byte);
665 atr_append_byte(fi, byte);
666 switch (fi->state) {
667 case ATR_S_WAIT_T0: /* see ISO/IEC 7816-3:2006 section 8.2.2 */
668 case ATR_S_WAIT_TD: /* see ISO/IEC 7816-3:2006 section 8.2.3 */
669 if (fi->state == ATR_S_WAIT_T0) {
670 /* save number of hist. bytes */
671 atp->hist_len = (byte & 0x0f);
672 } else {
673 /* remember supported protocol to know if TCK will be present */
674 atp->protocol_support |= (1<<(byte & 0x0f));
675 }
676 atp->y = (byte & 0xf0); /* remember incoming interface bytes */
677 atp->i++;
678 if (atp->y & 0x10) {
679 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_TA, guard_time_ms, T_GUARD);
680 break;
681 }
682 /* fall-through */
683 case ATR_S_WAIT_TA: /* see ISO/IEC 7816-3:2006 section 8.2.3 */
684 if (atp->y & 0x20) {
685 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_TB, guard_time_ms, T_GUARD);
686 break;
687 }
688 /* fall-through */
689 case ATR_S_WAIT_TB: /* see ISO/IEC 7816-3:2006 section 8.2.3 */
690 if (atp->y & 0x40) {
691 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_TC, guard_time_ms, T_GUARD);
692 break;
693 }
694 /* fall-through */
695 case ATR_S_WAIT_TC: /* see ISO/IEC 7816-3:2006 section 8.2.3 */
696 if (atp->y & 0x80) {
697 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_TD, guard_time_ms, T_GUARD);
698 break;
699 } else if (atp->hist_len) {
700 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_HIST, guard_time_ms, T_GUARD);
701 break;
702 }
703 /* fall-through */
704 case ATR_S_WAIT_HIST: /* see ISO/IEC 7816-3:2006 section 8.2.4 */
705 if (atp->hist_len)
706 atp->hist_len--;
707 if (atp->hist_len == 0) {
708 if (atp->protocol_support > 1) {
709 /* wait for check byte */
710 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_TCK,
711 guard_time_ms, T_GUARD);
712 break;
Eric Wild70d212d2019-11-27 15:05:09 +0100713 } else {
714 /* no TCK present, ATR complete; notify parent */
715 osmo_fsm_inst_state_chg(fi, ATR_S_DONE, 0, 0);
716 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_ATR_DONE_IND, atp->atr);
Harald Welte06348362019-05-19 00:45:17 +0200717 }
718 } else {
719 break;
720 }
721 /* fall-through */
722 case ATR_S_WAIT_TCK: /* see ISO/IEC 7816-3:2006 section 8.2.5 */
723 /* verify checksum if present */
724 if (fi->state == ATR_S_WAIT_TCK) {
725 uint8_t ui;
726 uint8_t *atr = msgb_data(atp->atr);
727 LOGPFSML(fi, LOGL_INFO, "Complete ATR: %s\n", msgb_hexdump(atp->atr));
728 for (ui = 1; ui < msgb_length(atp->atr)-1; ui++) {
729 atp->computed_checksum ^= atr[ui];
730 }
731 if (atp->computed_checksum != byte) {
732 /* checkum error. report to user? */
733 LOGPFSML(fi, LOGL_ERROR,
734 "computed checksum %02x doesn't match TCK=%02x\n",
735 atp->computed_checksum, byte);
736 }
737 /* ATR complete; notify parent */
738 osmo_fsm_inst_state_chg(fi, ATR_S_DONE, 0, 0);
739 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_ATR_DONE_IND, atp->atr);
740 }
741 break;
742 default:
743 OSMO_ASSERT(0);
744 }
745 break;
Harald Welte1ac9ef92019-10-09 22:20:16 +0200746 case ISO7816_E_WTIME_EXP:
747 switch (fi->state) {
748 case ATR_S_WAIT_HIST:
749 case ATR_S_WAIT_TCK:
750 /* Some cards have an ATR with long indication of historical bytes */
751 /* FIXME: should we check the checksum? */
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 break;
755 default:
756 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_ATR_ERR_IND, NULL);
757 break;
758 }
759 break;
Harald Welte06348362019-05-19 00:45:17 +0200760 default:
761 OSMO_ASSERT(0);
762 }
763}
764
Eric Wild2f5cdd12019-11-27 18:40:44 +0100765static void atr_done_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
766{
767 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
768 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
769
770 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 0);
771}
772
Harald Welte06348362019-05-19 00:45:17 +0200773static const struct osmo_fsm_state atr_states[] = {
774 [ATR_S_WAIT_TS] = {
775 .name = "WAIT_TS",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200776 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
777 S(ISO7816_E_WTIME_EXP),
Harald Welte06348362019-05-19 00:45:17 +0200778 .out_state_mask = S(ATR_S_WAIT_TS) |
779 S(ATR_S_WAIT_T0),
780 .action = atr_wait_ts_action,
781 .onenter = atr_wait_ts_onenter,
782 },
783 [ATR_S_WAIT_T0] = {
784 .name = "WAIT_T0",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200785 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
786 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200787 .out_state_mask = S(ATR_S_WAIT_TS) |
788 S(ATR_S_WAIT_TA) |
Harald Welte06348362019-05-19 00:45:17 +0200789 S(ATR_S_WAIT_TB) |
790 S(ATR_S_WAIT_TC) |
791 S(ATR_S_WAIT_TD) |
792 S(ATR_S_WAIT_HIST) |
793 S(ATR_S_WAIT_TCK) |
794 S(ATR_S_WAIT_T0),
795 .action = atr_wait_tX_action,
796 },
797 [ATR_S_WAIT_TA] = {
798 .name = "WAIT_TA",
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_TB) |
Harald Welte06348362019-05-19 00:45:17 +0200803 S(ATR_S_WAIT_TC) |
804 S(ATR_S_WAIT_TD) |
805 S(ATR_S_WAIT_HIST) |
806 S(ATR_S_WAIT_TCK) |
807 S(ATR_S_WAIT_T0),
808 .action = atr_wait_tX_action,
809 },
810 [ATR_S_WAIT_TB] = {
811 .name = "WAIT_TB",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200812 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
813 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200814 .out_state_mask = S(ATR_S_WAIT_TS) |
815 S(ATR_S_WAIT_TC) |
Harald Welte06348362019-05-19 00:45:17 +0200816 S(ATR_S_WAIT_TD) |
817 S(ATR_S_WAIT_HIST) |
818 S(ATR_S_WAIT_TCK) |
819 S(ATR_S_WAIT_T0),
820 .action = atr_wait_tX_action,
821 },
822 [ATR_S_WAIT_TC] = {
823 .name = "WAIT_TC",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200824 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
825 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200826 .out_state_mask = S(ATR_S_WAIT_TS) |
827 S(ATR_S_WAIT_TD) |
Harald Welte06348362019-05-19 00:45:17 +0200828 S(ATR_S_WAIT_HIST) |
829 S(ATR_S_WAIT_TCK) |
830 S(ATR_S_WAIT_T0),
831 .action = atr_wait_tX_action,
832 },
833 [ATR_S_WAIT_TD] = {
834 .name = "WAIT_TD",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200835 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
836 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200837 .out_state_mask = S(ATR_S_WAIT_TS) |
838 S(ATR_S_WAIT_TA) |
Harald Welte06348362019-05-19 00:45:17 +0200839 S(ATR_S_WAIT_TB) |
840 S(ATR_S_WAIT_TC) |
841 S(ATR_S_WAIT_TD) |
842 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_HIST] = {
848 .name = "WAIT_HIST",
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_TCK) |
Harald Welte1ac9ef92019-10-09 22:20:16 +0200853 S(ATR_S_WAIT_T0) |
854 S(ATR_S_DONE),
Harald Welte06348362019-05-19 00:45:17 +0200855 .action = atr_wait_tX_action,
856 },
857 [ATR_S_WAIT_TCK] = {
858 .name = "WAIT_TCK",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200859 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
860 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200861 .out_state_mask = S(ATR_S_WAIT_TS) |
862 S(ATR_S_DONE),
Harald Welte06348362019-05-19 00:45:17 +0200863 .action = atr_wait_tX_action,
864 },
865 [ATR_S_DONE] = {
866 .name = "DONE",
867 .in_event_mask = 0,
Harald Welte704d99a2019-10-09 21:39:27 +0200868 .out_state_mask = S(ATR_S_WAIT_TS),
Eric Wild2f5cdd12019-11-27 18:40:44 +0100869 .onenter = atr_done_onenter
Harald Welte06348362019-05-19 00:45:17 +0200870 },
871
872};
873static struct osmo_fsm atr_fsm = {
874 .name = "ATR",
875 .states = atr_states,
876 .num_states = ARRAY_SIZE(atr_states),
877 .log_subsys = DATR,
878 .event_names = iso7816_3_event_names,
879};
880
881/***********************************************************************
882 * PPS FSM
883 ***********************************************************************/
Eric Wildad1edce2019-11-27 16:51:08 +0100884struct pps_fsm_priv {
885 struct msgb* tx_cmd;
886 struct msgb* rx_cmd;
887 uint8_t pps0_recv;
888};
889
Eric Wild2f5cdd12019-11-27 18:40:44 +0100890static void pps_s_pps_req_init_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
Eric Wildad1edce2019-11-27 16:51:08 +0100891{
892 struct pps_fsm_priv *atp = fi->priv;
893
894 if (!atp->rx_cmd)
Eric Wild9e622dc2019-11-27 14:43:16 +0100895 atp->rx_cmd = msgb_alloc_c(fi, 6, "PPSRSP"); /* at most 6 */
Eric Wildad1edce2019-11-27 16:51:08 +0100896 else
897 msgb_reset(atp->rx_cmd);
Eric Wild9e622dc2019-11-27 14:43:16 +0100898
899 /* notify in case card got pulled out */
Eric Wild759a6462019-11-11 14:22:52 +0100900 if (atp->tx_cmd && old_state != PPS_S_DONE){
Eric Wild9e622dc2019-11-27 14:43:16 +0100901 osmo_fsm_inst_dispatch(fi->proc.parent,
902 ISO7816_E_PPS_FAILED_IND, atp->tx_cmd);
903 atp->tx_cmd = 0;
904 }
Eric Wildad1edce2019-11-27 16:51:08 +0100905}
906
Eric Wild2f5cdd12019-11-27 18:40:44 +0100907static void pps_s_pps_req_init_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
Eric Wildad1edce2019-11-27 16:51:08 +0100908{
909 struct pps_fsm_priv *atp = fi->priv;
Eric Wildad1edce2019-11-27 16:51:08 +0100910 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
911 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
912
Eric Wild9e622dc2019-11-27 14:43:16 +0100913 /* keep the buffer to compare it with the received response */
914 atp->tx_cmd = data;
915
Eric Wildad1edce2019-11-27 16:51:08 +0100916 switch (event) {
917 case ISO7816_E_XCEIVE_PPS_CMD:
Eric Wild2f5cdd12019-11-27 18:40:44 +0100918 osmo_fsm_inst_state_chg(fi, PPS_S_TX_PPS_REQ, 0, 0);
919 card_uart_set_rx_threshold(ip->uart, 1);
Eric Wildad1edce2019-11-27 16:51:08 +0100920 card_uart_tx(ip->uart, msgb_data(data), msgb_length(data), true);
921 break;
922 default:
923 OSMO_ASSERT(0);
924 }
925}
926
Eric Wild2f5cdd12019-11-27 18:40:44 +0100927static void pps_s_tx_pps_req_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
928{
929 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
930 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
931
932 switch (event) {
933 case ISO7816_E_TX_COMPL:
934 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 6);
935 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPSX, 0, 0);
936 break;
937 default:
938 OSMO_ASSERT(0);
939 }
940}
941
942
943
944
Eric Wildad1edce2019-11-27 16:51:08 +0100945static void pps_wait_pX_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
946{
947 struct pps_fsm_priv *atp = fi->priv;
Eric Wild2f5cdd12019-11-27 18:40:44 +0100948 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
949 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
Eric Wildad1edce2019-11-27 16:51:08 +0100950 uint8_t byte;
951
952 switch (event) {
953 case ISO7816_E_RX_SINGLE:
954 byte = get_rx_byte_evt(fi->proc.parent, data);
955 LOGPFSML(fi, LOGL_DEBUG, "RX byte '%02x'\n", byte);
956 msgb_put_u8(atp->rx_cmd, byte);
957 switch (fi->state) {
Eric Wild2f5cdd12019-11-27 18:40:44 +0100958 case PPS_S_WAIT_PPSX:
Eric Wildad1edce2019-11-27 16:51:08 +0100959 if (byte == 0xff)
960 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPS0, 0, 0);
961 break;
962 case PPS_S_WAIT_PPS0:
963 atp->pps0_recv = byte;
964 if(atp->pps0_recv & (1 << 4)) {
965 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPS1, 0, 0);
966 break;
967 } else if (atp->pps0_recv & (1 << 5)) {
968 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPS2, 0, 0);
969 break;
970 } else if (atp->pps0_recv & (1 << 6)) {
971 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPS3, 0, 0);
972 break;
973 }
974 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PCK, 0, 0);
975 break;
976 case PPS_S_WAIT_PPS1:
977 if (atp->pps0_recv & (1 << 5)) {
978 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPS2, 0, 0);
979 break;
980 } else if (atp->pps0_recv & (1 << 6)) {
981 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPS3, 0, 0);
982 break;
983 }
984 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PCK, 0, 0);
985 break;
986 case PPS_S_WAIT_PPS2:
987 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_PPS3:
994 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PCK, 0, 0);
995 break;
996 case PPS_S_WAIT_PCK:
997 /* verify checksum if present */
998 if (fi->state == PPS_S_WAIT_PCK) {
999 uint8_t *pps_received = msgb_data(atp->rx_cmd);
1000 uint8_t *pps_sent = msgb_data(atp->tx_cmd);
1001
Eric Wild2f5cdd12019-11-27 18:40:44 +01001002 osmo_fsm_inst_state_chg(fi, PPS_S_DONE, 0, 0);
Eric Wildad1edce2019-11-27 16:51:08 +01001003
1004 /* pps was successful if response equals request
1005 * rx buffer stays with the fsm, tx buffer gets handed back and freed
1006 * by the cb */
1007 if (msgb_length(atp->rx_cmd) == msgb_length(atp->tx_cmd) &&
1008 !memcmp(pps_received, pps_sent, msgb_length(atp->rx_cmd))) {
1009 osmo_fsm_inst_dispatch(fi->proc.parent,
1010 ISO7816_E_PPS_DONE_IND, atp->tx_cmd);
1011 } else {
1012 osmo_fsm_inst_dispatch(fi->proc.parent,
1013 ISO7816_E_PPS_FAILED_IND, atp->tx_cmd);
1014 }
Eric Wild9e622dc2019-11-27 14:43:16 +01001015 /* ownership transfer */
1016 atp->tx_cmd = 0;
Eric Wildad1edce2019-11-27 16:51:08 +01001017 }
1018 break;
1019 default:
1020 OSMO_ASSERT(0);
1021 }
1022 break;
1023 case ISO7816_E_WTIME_EXP:
Eric Wild2f5cdd12019-11-27 18:40:44 +01001024 osmo_fsm_inst_state_chg(fi, PPS_S_DONE, 0, 0);
Eric Wildad1edce2019-11-27 16:51:08 +01001025 /* FIXME: timeout handling if no pps supported ? */
1026 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_RX_ERR_IND, NULL);
1027 break;
1028 default:
1029 OSMO_ASSERT(0);
1030 }
1031}
1032
Harald Welte06348362019-05-19 00:45:17 +02001033
Eric Wild2f5cdd12019-11-27 18:40:44 +01001034static void pps_s_done_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
1035{
1036 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1037 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1038
1039 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 0);
1040}
1041
1042
Harald Welte06348362019-05-19 00:45:17 +02001043static const struct osmo_fsm_state pps_states[] = {
Eric Wild2f5cdd12019-11-27 18:40:44 +01001044 [PPS_S_PPS_REQ_INIT] = {
1045 .name = "INIT",
Eric Wildad1edce2019-11-27 16:51:08 +01001046 .in_event_mask = S(ISO7816_E_XCEIVE_PPS_CMD) |
1047 S(ISO7816_E_WTIME_EXP),
Eric Wild2f5cdd12019-11-27 18:40:44 +01001048 .out_state_mask = S(PPS_S_PPS_REQ_INIT) |
1049 S(PPS_S_TX_PPS_REQ),
1050 .action = pps_s_pps_req_init_action,
1051 .onenter = pps_s_pps_req_init_onenter,
Eric Wildad1edce2019-11-27 16:51:08 +01001052 },
Eric Wild2f5cdd12019-11-27 18:40:44 +01001053 [PPS_S_TX_PPS_REQ] = {
1054 .name = "TX_PPS_REQ",
1055 .in_event_mask = S(ISO7816_E_TX_COMPL),
1056 .out_state_mask = S(PPS_S_WAIT_PPSX),
1057 .action = pps_s_tx_pps_req_action,
1058 },
1059 [PPS_S_WAIT_PPSX] = {
Harald Welte06348362019-05-19 00:45:17 +02001060 .name = "WAIT_PPSS",
Eric Wildad1edce2019-11-27 16:51:08 +01001061 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
1062 S(ISO7816_E_WTIME_EXP),
1063 .out_state_mask = S(PPS_S_WAIT_PPS0) |
Eric Wild2f5cdd12019-11-27 18:40:44 +01001064 S(PPS_S_WAIT_PPSX),
Eric Wildad1edce2019-11-27 16:51:08 +01001065 .action = pps_wait_pX_action,
Harald Welte06348362019-05-19 00:45:17 +02001066 },
1067 [PPS_S_WAIT_PPS0] = {
1068 .name = "WAIT_PPS0",
Eric Wildad1edce2019-11-27 16:51:08 +01001069 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
1070 S(ISO7816_E_WTIME_EXP),
1071 .out_state_mask = S(PPS_S_WAIT_PPS1) |
1072 S(PPS_S_WAIT_PPS2) |
1073 S(PPS_S_WAIT_PPS3) |
1074 S(PPS_S_WAIT_PCK),
1075 .action = pps_wait_pX_action,
Harald Welte06348362019-05-19 00:45:17 +02001076 },
1077 [PPS_S_WAIT_PPS1] = {
1078 .name = "WAIT_PPS1",
Eric Wildad1edce2019-11-27 16:51:08 +01001079 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
1080 S(ISO7816_E_WTIME_EXP),
1081 .out_state_mask = S(PPS_S_WAIT_PPS2) |
1082 S(PPS_S_WAIT_PPS3) |
1083 S(PPS_S_WAIT_PCK),
1084 .action = pps_wait_pX_action,
Harald Welte06348362019-05-19 00:45:17 +02001085 },
1086 [PPS_S_WAIT_PPS2] = {
1087 .name = "WAIT_PPS2",
Eric Wildad1edce2019-11-27 16:51:08 +01001088 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
1089 S(ISO7816_E_WTIME_EXP),
1090 .out_state_mask = 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_PPS3] = {
1095 .name = "WAIT_PPS3",
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_PCK),
1099 .action = pps_wait_pX_action,
Harald Welte06348362019-05-19 00:45:17 +02001100 },
1101 [PPS_S_WAIT_PCK] = {
1102 .name = "WAIT_PCK",
Eric Wildad1edce2019-11-27 16:51:08 +01001103 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
1104 S(ISO7816_E_WTIME_EXP),
Eric Wild2f5cdd12019-11-27 18:40:44 +01001105 .out_state_mask = S(PPS_S_DONE),
Eric Wildad1edce2019-11-27 16:51:08 +01001106 .action = pps_wait_pX_action,
Harald Welte06348362019-05-19 00:45:17 +02001107 },
Eric Wild2f5cdd12019-11-27 18:40:44 +01001108 [PPS_S_DONE] = {
1109 .name = "DONE",
Eric Wildad1edce2019-11-27 16:51:08 +01001110 .in_event_mask = 0,
Eric Wild2f5cdd12019-11-27 18:40:44 +01001111 .out_state_mask = S(PPS_S_PPS_REQ_INIT),
1112 .action = NULL,
1113 .onenter = pps_s_done_onenter,
Harald Welte06348362019-05-19 00:45:17 +02001114 },
1115};
1116
1117static struct osmo_fsm pps_fsm = {
1118 .name = "PPS",
1119 .states = pps_states,
1120 .num_states = ARRAY_SIZE(pps_states),
1121 .log_subsys = DPPS,
1122 .event_names = iso7816_3_event_names,
1123};
1124
1125/***********************************************************************
1126 * TPDU FSM
1127 ***********************************************************************/
1128
Harald Welte65087832019-10-01 09:16:49 +02001129/* In this FSM weu use the msgb for the TPDU as follows:
1130 * - 5-byte TPDU header is at msg->data
1131 * - COMMAND TPDU:
1132 * - command bytes are provided after the header at msg->l2h
1133 * - in case of incremental transmission, l3h points to next to-be-transmitted byte
1134 * - RESPONSE TPDU:
1135 * - any response bytes are stored after the header at msg->l2h
1136 */
1137
1138static inline struct osim_apdu_cmd_hdr *msgb_tpdu_hdr(struct msgb *msg) {
1139 return (struct osim_apdu_cmd_hdr *) msgb_data(msg);
1140}
1141
Harald Welte06348362019-05-19 00:45:17 +02001142struct tpdu_fsm_priv {
1143 struct msgb *tpdu;
Harald Welte65087832019-10-01 09:16:49 +02001144 bool is_command; /* is this a command TPDU (true) or a response (false) */
Harald Welte06348362019-05-19 00:45:17 +02001145};
1146
1147/* type-safe method to obtain iso7816_3_priv from fi */
1148static struct tpdu_fsm_priv *get_tpdu_fsm_priv(struct osmo_fsm_inst *fi)
1149{
1150 OSMO_ASSERT(fi);
1151 OSMO_ASSERT(fi->fsm == &tpdu_fsm);
1152 return (struct tpdu_fsm_priv *) fi->priv;
1153}
1154
Eric Wild9e622dc2019-11-27 14:43:16 +01001155static void tpdu_s_init_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
1156{
1157 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
1158
1159 /* notify in case card got pulled out */
Eric Wild759a6462019-11-11 14:22:52 +01001160 if (tfp->tpdu && old_state != TPDU_S_DONE){
Eric Wild9e622dc2019-11-27 14:43:16 +01001161 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_TPDU_FAILED_IND, tfp->tpdu);
1162 tfp->tpdu = 0;
1163 }
1164}
Harald Welte06348362019-05-19 00:45:17 +02001165
1166static void tpdu_s_init_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1167{
1168 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
1169 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1170 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1171 struct osim_apdu_cmd_hdr *tpduh;
1172
1173 switch (event) {
1174 case ISO7816_E_XCEIVE_TPDU_CMD:
1175 /* start transmission of a TPDU by sending the 5-byte header */
1176 tfp->tpdu = (struct msgb *)data;
1177 OSMO_ASSERT(msgb_length(tfp->tpdu) >= sizeof(*tpduh));
Harald Welte43281fe2020-07-30 20:29:02 +02001178 /* l2h = after the 5byte header */
Harald Welte06348362019-05-19 00:45:17 +02001179 tfp->tpdu->l2h = msgb_data(tfp->tpdu) + sizeof(*tpduh);
Harald Welte43281fe2020-07-30 20:29:02 +02001180 /* l4h = where we start to receive from the card */
1181 tfp->tpdu->l4h = msgb_l2(tfp->tpdu) + msgb_l2len(tfp->tpdu);
Harald Welte65087832019-10-01 09:16:49 +02001182 if (msgb_l2len(tfp->tpdu)) {
1183 tfp->is_command = true;
Harald Welte43281fe2020-07-30 20:29:02 +02001184 /* l3h = used as 'next byte to write' pointer */
Harald Welte65087832019-10-01 09:16:49 +02001185 tfp->tpdu->l3h = tfp->tpdu->l2h; /* next tx byte == first byte of body */
1186 } else
1187 tfp->is_command = false;
1188 tpduh = msgb_tpdu_hdr(tfp->tpdu);
1189 LOGPFSML(fi, LOGL_DEBUG, "Transmitting %s TPDU header %s via UART\n",
1190 tfp->is_command ? "COMMAND" : "RESPONSE",
Harald Welte06348362019-05-19 00:45:17 +02001191 osmo_hexdump_nospc((uint8_t *) tpduh, sizeof(*tpduh)));
1192 osmo_fsm_inst_state_chg(fi, TPDU_S_TX_HDR, 0, 0);
Harald Welte6603d952019-10-09 20:50:13 +02001193 card_uart_tx(ip->uart, (uint8_t *) tpduh, sizeof(*tpduh), true);
Harald Welte06348362019-05-19 00:45:17 +02001194 break;
1195 default:
1196 OSMO_ASSERT(0);
1197 }
1198}
1199
Eric Wilde84a5712019-11-28 17:30:30 +01001200
Harald Welte06348362019-05-19 00:45:17 +02001201static void tpdu_s_tx_hdr_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1202{
Eric Wild2f5cdd12019-11-27 18:40:44 +01001203 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1204 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
Harald Welte06348362019-05-19 00:45:17 +02001205 OSMO_ASSERT(fi->fsm == &tpdu_fsm);
1206 switch (event) {
1207 case ISO7816_E_TX_COMPL:
Eric Wild2f5cdd12019-11-27 18:40:44 +01001208
1209 card_uart_set_rx_threshold(ip->uart, 1);
1210 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 1);
Harald Welte06348362019-05-19 00:45:17 +02001211 /* Rx of single byte is already enabled by previous card_uart_tx() call */
1212 osmo_fsm_inst_state_chg(fi, TPDU_S_PROCEDURE, 0, 0);
1213 break;
1214 default:
1215 OSMO_ASSERT(0);
1216 }
1217}
1218
1219
Eric Wilde84a5712019-11-28 17:30:30 +01001220#if 0
1221#include <hal_gpio.h>
1222#endif
Harald Welte06348362019-05-19 00:45:17 +02001223static void tpdu_s_procedure_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1224{
1225 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
Harald Welte65087832019-10-01 09:16:49 +02001226 struct osim_apdu_cmd_hdr *tpduh = msgb_tpdu_hdr(tfp->tpdu);
Harald Welte06348362019-05-19 00:45:17 +02001227 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1228 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1229 uint8_t byte;
1230
1231 switch (event) {
1232 case ISO7816_E_RX_SINGLE:
1233 byte = get_rx_byte_evt(fi->proc.parent, data);
1234 LOGPFSML(fi, LOGL_DEBUG, "Received 0x%02x from UART\n", byte);
1235 if (byte == 0x60) {
1236 /* NULL: wait for another procedure byte */
Eric Wild2f5cdd12019-11-27 18:40:44 +01001237 card_uart_set_rx_threshold(ip->uart, 1);
1238 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 1);
Harald Welte06348362019-05-19 00:45:17 +02001239 osmo_fsm_inst_state_chg(fi, TPDU_S_PROCEDURE, 0, 0);
1240 } else if ((byte >= 0x60 && byte <= 0x6f) || (byte >= 0x90 && byte <= 0x9f)) {
1241 //msgb_apdu_sw(tfp->apdu) = byte << 8;
1242 msgb_put(tfp->tpdu, byte);
1243 /* receive second SW byte (SW2) */
Eric Wild2f5cdd12019-11-27 18:40:44 +01001244 card_uart_set_rx_threshold(ip->uart, 1);
1245 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 1);
Harald Welte06348362019-05-19 00:45:17 +02001246 osmo_fsm_inst_state_chg(fi, TPDU_S_SW2, 0, 0);
1247 break;
1248 } else if (byte == tpduh->ins) {
Harald Welte65087832019-10-01 09:16:49 +02001249 if (tfp->is_command) {
Harald Welte06348362019-05-19 00:45:17 +02001250 /* transmit all remaining bytes */
Eric Wild9a2279c2019-11-27 18:30:18 +01001251#if 0
1252// rx -> tx delay
1253 gpio_set_pin_level(PIN_PB12, true);
1254 delay_us(1);
1255 gpio_set_pin_level(PIN_PB12, false);
1256#endif
Harald Welte6603d952019-10-09 20:50:13 +02001257 card_uart_tx(ip->uart, msgb_l2(tfp->tpdu), msgb_l2len(tfp->tpdu), true);
Harald Welte06348362019-05-19 00:45:17 +02001258 osmo_fsm_inst_state_chg(fi, TPDU_S_TX_REMAINING, 0, 0);
1259 } else {
1260 card_uart_set_rx_threshold(ip->uart, tpduh->p3);
Eric Wild2f5cdd12019-11-27 18:40:44 +01001261 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, tpduh->p3);
Harald Welte06348362019-05-19 00:45:17 +02001262 osmo_fsm_inst_state_chg(fi, TPDU_S_RX_REMAINING, 0, 0);
1263 }
1264 } else if (byte == (tpduh->ins ^ 0xFF)) {
Harald Welte65087832019-10-01 09:16:49 +02001265 /* transmit/recieve single byte then wait for proc */
1266 if (tfp->is_command) {
1267 /* transmit *next*, not first byte */
1268 OSMO_ASSERT(msgb_l3len(tfp->tpdu) >= 0);
Harald Welte6603d952019-10-09 20:50:13 +02001269 card_uart_tx(ip->uart, msgb_l3(tfp->tpdu), 1, false);
Harald Welte65087832019-10-01 09:16:49 +02001270 osmo_fsm_inst_state_chg(fi, TPDU_S_TX_SINGLE, 0, 0);
1271 } else {
Eric Wild2f5cdd12019-11-27 18:40:44 +01001272 card_uart_set_rx_threshold(ip->uart, 1);
1273 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 1);
Harald Welte65087832019-10-01 09:16:49 +02001274 osmo_fsm_inst_state_chg(fi, TPDU_S_RX_SINGLE, 0, 0);
1275 }
Harald Welte06348362019-05-19 00:45:17 +02001276 } else
1277 OSMO_ASSERT(0);
1278 break;
1279 default:
1280 OSMO_ASSERT(0);
1281 }
1282}
1283
1284/* UART is transmitting remaining data; we wait for ISO7816_E_TX_COMPL */
1285static void tpdu_s_tx_remaining_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1286{
1287 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1288 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1289
1290 switch (event) {
1291 case ISO7816_E_TX_COMPL:
1292 card_uart_set_rx_threshold(ip->uart, 1);
Eric Wild2f5cdd12019-11-27 18:40:44 +01001293 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 1);
Harald Welte06348362019-05-19 00:45:17 +02001294 osmo_fsm_inst_state_chg(fi, TPDU_S_SW1, 0, 0);
1295 break;
1296 default:
1297 OSMO_ASSERT(0);
1298 }
1299}
1300
1301/* UART is transmitting single byte of data; we wait for ISO7816_E_TX_COMPL */
1302static void tpdu_s_tx_single_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1303{
Harald Welte65087832019-10-01 09:16:49 +02001304 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
Eric Wild2f5cdd12019-11-27 18:40:44 +01001305 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1306 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
Harald Welte65087832019-10-01 09:16:49 +02001307
Harald Welte06348362019-05-19 00:45:17 +02001308 switch (event) {
1309 case ISO7816_E_TX_COMPL:
Harald Welte65087832019-10-01 09:16:49 +02001310 tfp->tpdu->l3h += 1;
Eric Wild2f5cdd12019-11-27 18:40:44 +01001311 card_uart_set_rx_threshold(ip->uart, 1);
1312 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 1);
Harald Welte65087832019-10-01 09:16:49 +02001313 if (msgb_l3len(tfp->tpdu))
1314 osmo_fsm_inst_state_chg(fi, TPDU_S_PROCEDURE, 0, 0);
1315 else
1316 osmo_fsm_inst_state_chg(fi, TPDU_S_SW1, 0, 0);
Harald Welte06348362019-05-19 00:45:17 +02001317 break;
1318 default:
1319 OSMO_ASSERT(0);
1320 }
1321}
1322
1323/* UART is receiving remaining data; we wait for ISO7816_E_RX_COMPL */
1324static void tpdu_s_rx_remaining_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1325{
1326 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
Harald Welte65087832019-10-01 09:16:49 +02001327 struct osim_apdu_cmd_hdr *tpduh = msgb_tpdu_hdr(tfp->tpdu);
Harald Welte06348362019-05-19 00:45:17 +02001328 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1329 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1330 int rc;
1331
1332 switch (event) {
1333 case ISO7816_E_RX_COMPL:
1334 /* retrieve pending byte(s) */
1335 rc = card_uart_rx(ip->uart, msgb_l2(tfp->tpdu), tpduh->p3);
Harald Welte65087832019-10-01 09:16:49 +02001336 OSMO_ASSERT(rc > 0);
1337 msgb_put(tfp->tpdu, rc);
1338 if (msgb_l2len(tfp->tpdu) != tpduh->p3) {
1339 LOGPFSML(fi, LOGL_ERROR, "expected %u bytes; read %d\n", tpduh->p3,
1340 msgb_l2len(tfp->tpdu));
1341 }
Harald Welte06348362019-05-19 00:45:17 +02001342 card_uart_set_rx_threshold(ip->uart, 1);
Eric Wild2f5cdd12019-11-27 18:40:44 +01001343 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 1);
Harald Welte06348362019-05-19 00:45:17 +02001344 osmo_fsm_inst_state_chg(fi, TPDU_S_SW1, 0, 0);
1345 break;
1346 default:
1347 OSMO_ASSERT(0);
1348 }
1349}
1350
1351/* UART is receiving single byte of data; we wait for ISO7816_E_RX_SINGLE */
1352static void tpdu_s_rx_single_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1353{
1354 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
Harald Welte65087832019-10-01 09:16:49 +02001355 struct osim_apdu_cmd_hdr *tpduh = msgb_tpdu_hdr(tfp->tpdu);
Eric Wild2f5cdd12019-11-27 18:40:44 +01001356 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1357 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
Harald Welte06348362019-05-19 00:45:17 +02001358 uint8_t byte;
1359
1360 switch (event) {
1361 case ISO7816_E_RX_SINGLE:
1362 byte = get_rx_byte_evt(fi->proc.parent, data);
1363 LOGPFSML(fi, LOGL_DEBUG, "Received 0x%02x from UART\n", byte);
Harald Welte65087832019-10-01 09:16:49 +02001364 msgb_put_u8(tfp->tpdu, byte);
Eric Wild2f5cdd12019-11-27 18:40:44 +01001365
1366 card_uart_set_rx_threshold(ip->uart, 1);
1367 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 1);
1368
Harald Welte65087832019-10-01 09:16:49 +02001369 /* determine if number of expected bytes received */
1370 if (msgb_l2len(tfp->tpdu) == tpduh->p3)
Harald Welte06348362019-05-19 00:45:17 +02001371 osmo_fsm_inst_state_chg(fi, TPDU_S_SW1, 0, 0);
Harald Welte65087832019-10-01 09:16:49 +02001372 else
Harald Welte06348362019-05-19 00:45:17 +02001373 osmo_fsm_inst_state_chg(fi, TPDU_S_PROCEDURE, 0, 0);
1374 break;
1375 default:
1376 OSMO_ASSERT(0);
1377 }
1378}
1379
1380static void tpdu_s_sw1_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1381{
1382 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
1383 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1384 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1385 uint8_t byte;
1386
1387 switch (event) {
1388 case ISO7816_E_RX_SINGLE:
1389 byte = get_rx_byte_evt(fi->proc.parent, data);
1390 LOGPFSML(fi, LOGL_DEBUG, "Received 0x%02x from UART\n", byte);
1391 /* record byte */
1392 //msgb_apdu_sw(tfp->apdu) = byte << 8;
1393 msgb_put_u8(tfp->tpdu, byte);
1394 card_uart_set_rx_threshold(ip->uart, 1);
Eric Wild2f5cdd12019-11-27 18:40:44 +01001395 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 1);
Harald Welte06348362019-05-19 00:45:17 +02001396 osmo_fsm_inst_state_chg(fi, TPDU_S_SW2, 0, 0);
1397 break;
1398 default:
1399 OSMO_ASSERT(0);
1400 }
1401}
1402
1403static void tpdu_s_sw2_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1404{
1405 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
1406 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1407 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1408 uint8_t byte;
1409
1410 switch (event) {
1411 case ISO7816_E_RX_SINGLE:
1412 byte = get_rx_byte_evt(fi->proc.parent, data);
1413 LOGPFSML(fi, LOGL_DEBUG, "Received 0x%02x from UART\n", byte);
1414 /* record SW2 byte */
1415 //msgb_apdu_sw(tfp->apdu) &= 0xFF00;
1416 //msgb_apdu_sw(tfp->apdu) |= byte;
1417 msgb_put_u8(tfp->tpdu, byte);
1418 osmo_fsm_inst_state_chg(fi, TPDU_S_DONE, 0, 0);
1419 /* Notify parent FSM */
1420 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_TPDU_DONE_IND, tfp->tpdu);
Eric Wild9e622dc2019-11-27 14:43:16 +01001421
1422 /* ownership transfer */
1423 tfp->tpdu = 0;
Harald Welte06348362019-05-19 00:45:17 +02001424 break;
1425 default:
1426 OSMO_ASSERT(0);
1427 }
1428}
1429
1430static void tpdu_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1431{
1432 OSMO_ASSERT(fi->fsm == &tpdu_fsm);
1433
1434 switch (event) {
1435 case ISO7816_E_RX_ERR_IND:
1436 case ISO7816_E_TX_ERR_IND:
1437 /* FIXME: handle this in some different way */
1438 osmo_fsm_inst_state_chg(fi, TPDU_S_DONE, 0, 0);
Eric Wild2f5cdd12019-11-27 18:40:44 +01001439 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_TPDU_FAILED_IND, NULL);
Harald Welte06348362019-05-19 00:45:17 +02001440 break;
1441 case ISO7816_E_TPDU_CLEAR_REQ:
1442 osmo_fsm_inst_state_chg(fi, TPDU_S_INIT, 0, 0);
1443 break;
1444 }
1445}
1446
Eric Wild2f5cdd12019-11-27 18:40:44 +01001447
1448static void tpdu_s_done_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
1449{
1450 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1451 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1452
1453 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 0);
1454}
1455
Harald Welte06348362019-05-19 00:45:17 +02001456static const struct osmo_fsm_state tpdu_states[] = {
1457 [TPDU_S_INIT] = {
1458 .name = "INIT",
1459 .in_event_mask = S(ISO7816_E_XCEIVE_TPDU_CMD) |
1460 S(ISO7816_E_TX_COMPL),
1461 .out_state_mask = S(TPDU_S_INIT) |
1462 S(TPDU_S_TX_HDR),
1463 .action = tpdu_s_init_action,
Eric Wild9e622dc2019-11-27 14:43:16 +01001464 .onenter = tpdu_s_init_onenter,
Harald Welte06348362019-05-19 00:45:17 +02001465 },
1466 [TPDU_S_TX_HDR] = {
1467 .name = "TX_HDR",
1468 .in_event_mask = S(ISO7816_E_TX_COMPL),
1469 .out_state_mask = S(TPDU_S_INIT) |
1470 S(TPDU_S_PROCEDURE),
1471 .action = tpdu_s_tx_hdr_action,
1472 },
1473 [TPDU_S_PROCEDURE] = {
1474 .name = "PROCEDURE",
1475 .in_event_mask = S(ISO7816_E_RX_SINGLE),
1476 .out_state_mask = S(TPDU_S_INIT) |
1477 S(TPDU_S_PROCEDURE) |
1478 S(TPDU_S_RX_REMAINING) |
1479 S(TPDU_S_RX_SINGLE) |
1480 S(TPDU_S_TX_REMAINING) |
1481 S(TPDU_S_TX_SINGLE) |
1482 S(TPDU_S_SW2),
1483 .action = tpdu_s_procedure_action,
1484 },
1485 [TPDU_S_TX_REMAINING] = {
1486 .name = "TX_REMAINING",
1487 .in_event_mask = S(ISO7816_E_TX_COMPL),
1488 .out_state_mask = S(TPDU_S_INIT) |
1489 S(TPDU_S_SW1),
1490 .action = tpdu_s_tx_remaining_action,
1491 },
1492 [TPDU_S_TX_SINGLE] = {
1493 .name = "TX_SINGLE",
1494 .in_event_mask = S(ISO7816_E_TX_COMPL),
1495 .out_state_mask = S(TPDU_S_INIT) |
1496 S(TPDU_S_PROCEDURE),
1497 .action = tpdu_s_tx_single_action,
1498 },
1499 [TPDU_S_RX_REMAINING] = {
1500 .name = "RX_REMAINING",
1501 .in_event_mask = S(ISO7816_E_RX_COMPL),
1502 .out_state_mask = S(TPDU_S_INIT) |
1503 S(TPDU_S_SW1),
1504 .action = tpdu_s_rx_remaining_action,
1505 },
1506 [TPDU_S_RX_SINGLE] = {
1507 .name = "RX_SINGLE",
1508 .in_event_mask = S(ISO7816_E_RX_SINGLE),
1509 .out_state_mask = S(TPDU_S_INIT) |
1510 S(TPDU_S_PROCEDURE),
1511 .action = tpdu_s_rx_single_action,
1512 },
1513 [TPDU_S_SW1] = {
1514 .name = "SW1",
1515 .in_event_mask = S(ISO7816_E_RX_SINGLE),
1516 .out_state_mask = S(TPDU_S_INIT) |
1517 S(TPDU_S_SW2),
1518 .action = tpdu_s_sw1_action,
1519 },
1520 [TPDU_S_SW2] = {
1521 .name = "SW2",
1522 .in_event_mask = S(ISO7816_E_RX_SINGLE),
1523 .out_state_mask = S(TPDU_S_INIT) |
1524 S(TPDU_S_DONE),
1525 .action = tpdu_s_sw2_action,
1526 },
1527 [TPDU_S_DONE] = {
1528 .name = "DONE",
1529 .in_event_mask = 0,
1530 .out_state_mask = S(TPDU_S_INIT),
1531 .action = NULL,
Eric Wild2f5cdd12019-11-27 18:40:44 +01001532 .onenter = tpdu_s_done_onenter,
Harald Welte06348362019-05-19 00:45:17 +02001533 },
1534};
1535static struct osmo_fsm tpdu_fsm = {
1536 .name = "TPDU",
1537 .states = tpdu_states,
1538 .num_states = ARRAY_SIZE(tpdu_states),
1539 .allstate_event_mask = S(ISO7816_E_RX_ERR_IND) |
1540 S(ISO7816_E_TX_ERR_IND) |
1541 S(ISO7816_E_TPDU_CLEAR_REQ),
1542 .allstate_action = tpdu_allstate_action,
1543 .log_subsys = DTPDU,
1544 .event_names = iso7816_3_event_names,
1545};
1546
1547struct osmo_fsm_inst *iso7816_fsm_alloc(void *ctx, int log_level, const char *id,
1548 struct card_uart *cuart, iso7816_user_cb user_cb,
1549 void *user_priv)
1550{
1551 struct iso7816_3_priv *ip;
1552 struct osmo_fsm_inst *fi;
1553
1554 fi = osmo_fsm_inst_alloc(&iso7816_3_fsm, ctx, NULL, log_level, id);
1555 ip = talloc_zero(fi, struct iso7816_3_priv);
1556 if (!ip)
1557 goto out_fi;
1558 fi->priv = ip;
1559
1560 ip->uart = cuart;
1561 cuart->priv = fi;
1562 cuart->handle_event = tpdu_uart_notification;
1563
1564 ip->user_cb = user_cb;
1565 ip->user_priv = user_priv;
1566
1567 ip->atr_fi = osmo_fsm_inst_alloc_child(&atr_fsm, fi, ISO7816_E_SW_ERR_IND);
1568 if (!ip->atr_fi)
1569 goto out_fi;
1570 ip->atr_fi->priv = talloc_zero(ip->atr_fi, struct atr_fsm_priv);
1571 if (!ip->atr_fi->priv)
1572 goto out_atr;
1573
1574 ip->tpdu_fi = osmo_fsm_inst_alloc_child(&tpdu_fsm, fi, ISO7816_E_SW_ERR_IND);
1575 if (!ip->tpdu_fi)
1576 goto out_atr;
1577 ip->tpdu_fi->priv = talloc_zero(ip->tpdu_fi, struct tpdu_fsm_priv);
1578 if (!ip->tpdu_fi->priv)
1579 goto out_tpdu;
1580
Eric Wildad1edce2019-11-27 16:51:08 +01001581#if 1
Harald Welte06348362019-05-19 00:45:17 +02001582 ip->pps_fi = osmo_fsm_inst_alloc_child(&pps_fsm, fi, ISO7816_E_SW_ERR_IND);
1583 if (!ip->pps_fi)
1584 goto out_tpdu;
1585 ip->pps_fi->priv = talloc_zero(ip->pps_fi, struct pps_fsm_priv);
1586 if (!ip->pps_fi->priv)
1587 goto out_pps;
1588#endif
1589
1590 /* This ensures the 'onenter' function of the initial state is called */
1591 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
1592
1593 return fi;
1594
Eric Wildad1edce2019-11-27 16:51:08 +01001595#if 1
Harald Welte06348362019-05-19 00:45:17 +02001596out_pps:
1597 osmo_fsm_inst_free(ip->pps_fi);
1598#endif
1599out_tpdu:
1600 osmo_fsm_inst_free(ip->tpdu_fi);
1601out_atr:
1602 osmo_fsm_inst_free(ip->atr_fi);
1603out_fi:
1604 osmo_fsm_inst_free(fi);
1605 cuart->priv = NULL;
1606 return NULL;
1607}
1608
1609void *iso7816_fsm_get_user_priv(struct osmo_fsm_inst *fi)
1610{
1611 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
1612 return ip->user_priv;
1613}
1614
1615
1616static __attribute__((constructor)) void on_dso_load_iso7816(void)
1617{
Harald Welte89b1e062019-12-01 13:30:14 +01001618 OSMO_ASSERT(osmo_fsm_register(&iso7816_3_fsm) == 0);
1619 OSMO_ASSERT(osmo_fsm_register(&atr_fsm) == 0);
1620 OSMO_ASSERT(osmo_fsm_register(&tpdu_fsm) == 0);
1621 OSMO_ASSERT(osmo_fsm_register(&pps_fsm) == 0);
Harald Welte06348362019-05-19 00:45:17 +02001622}