blob: 412bea70b38c500c95a3843551802e4f1547e65d [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));
1178 tfp->tpdu->l2h = msgb_data(tfp->tpdu) + sizeof(*tpduh);
Harald Welte65087832019-10-01 09:16:49 +02001179 if (msgb_l2len(tfp->tpdu)) {
1180 tfp->is_command = true;
1181 tfp->tpdu->l3h = tfp->tpdu->l2h; /* next tx byte == first byte of body */
1182 } else
1183 tfp->is_command = false;
1184 tpduh = msgb_tpdu_hdr(tfp->tpdu);
1185 LOGPFSML(fi, LOGL_DEBUG, "Transmitting %s TPDU header %s via UART\n",
1186 tfp->is_command ? "COMMAND" : "RESPONSE",
Harald Welte06348362019-05-19 00:45:17 +02001187 osmo_hexdump_nospc((uint8_t *) tpduh, sizeof(*tpduh)));
1188 osmo_fsm_inst_state_chg(fi, TPDU_S_TX_HDR, 0, 0);
Harald Welte6603d952019-10-09 20:50:13 +02001189 card_uart_tx(ip->uart, (uint8_t *) tpduh, sizeof(*tpduh), true);
Harald Welte06348362019-05-19 00:45:17 +02001190 break;
1191 default:
1192 OSMO_ASSERT(0);
1193 }
1194}
1195
Eric Wild9a2279c2019-11-27 18:30:18 +01001196#include <hal_gpio.h>
Harald Welte06348362019-05-19 00:45:17 +02001197static void tpdu_s_tx_hdr_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1198{
Eric Wild2f5cdd12019-11-27 18:40:44 +01001199 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1200 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
Harald Welte06348362019-05-19 00:45:17 +02001201 OSMO_ASSERT(fi->fsm == &tpdu_fsm);
1202 switch (event) {
1203 case ISO7816_E_TX_COMPL:
Eric Wild2f5cdd12019-11-27 18:40:44 +01001204
1205 card_uart_set_rx_threshold(ip->uart, 1);
1206 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 1);
Harald Welte06348362019-05-19 00:45:17 +02001207 /* Rx of single byte is already enabled by previous card_uart_tx() call */
1208 osmo_fsm_inst_state_chg(fi, TPDU_S_PROCEDURE, 0, 0);
1209 break;
1210 default:
1211 OSMO_ASSERT(0);
1212 }
1213}
1214
1215
1216
1217static void tpdu_s_procedure_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1218{
1219 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
Harald Welte65087832019-10-01 09:16:49 +02001220 struct osim_apdu_cmd_hdr *tpduh = msgb_tpdu_hdr(tfp->tpdu);
Harald Welte06348362019-05-19 00:45:17 +02001221 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1222 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1223 uint8_t byte;
1224
1225 switch (event) {
1226 case ISO7816_E_RX_SINGLE:
1227 byte = get_rx_byte_evt(fi->proc.parent, data);
1228 LOGPFSML(fi, LOGL_DEBUG, "Received 0x%02x from UART\n", byte);
1229 if (byte == 0x60) {
1230 /* NULL: wait for another procedure byte */
Eric Wild2f5cdd12019-11-27 18:40:44 +01001231 card_uart_set_rx_threshold(ip->uart, 1);
1232 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 1);
Harald Welte06348362019-05-19 00:45:17 +02001233 osmo_fsm_inst_state_chg(fi, TPDU_S_PROCEDURE, 0, 0);
1234 } else if ((byte >= 0x60 && byte <= 0x6f) || (byte >= 0x90 && byte <= 0x9f)) {
1235 //msgb_apdu_sw(tfp->apdu) = byte << 8;
1236 msgb_put(tfp->tpdu, byte);
1237 /* receive second SW byte (SW2) */
Eric Wild2f5cdd12019-11-27 18:40:44 +01001238 card_uart_set_rx_threshold(ip->uart, 1);
1239 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 1);
Harald Welte06348362019-05-19 00:45:17 +02001240 osmo_fsm_inst_state_chg(fi, TPDU_S_SW2, 0, 0);
1241 break;
1242 } else if (byte == tpduh->ins) {
Harald Welte65087832019-10-01 09:16:49 +02001243 if (tfp->is_command) {
Harald Welte06348362019-05-19 00:45:17 +02001244 /* transmit all remaining bytes */
Eric Wild9a2279c2019-11-27 18:30:18 +01001245#if 0
1246// rx -> tx delay
1247 gpio_set_pin_level(PIN_PB12, true);
1248 delay_us(1);
1249 gpio_set_pin_level(PIN_PB12, false);
1250#endif
Harald Welte6603d952019-10-09 20:50:13 +02001251 card_uart_tx(ip->uart, msgb_l2(tfp->tpdu), msgb_l2len(tfp->tpdu), true);
Harald Welte06348362019-05-19 00:45:17 +02001252 osmo_fsm_inst_state_chg(fi, TPDU_S_TX_REMAINING, 0, 0);
1253 } else {
1254 card_uart_set_rx_threshold(ip->uart, tpduh->p3);
Eric Wild2f5cdd12019-11-27 18:40:44 +01001255 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, tpduh->p3);
Harald Welte06348362019-05-19 00:45:17 +02001256 osmo_fsm_inst_state_chg(fi, TPDU_S_RX_REMAINING, 0, 0);
1257 }
1258 } else if (byte == (tpduh->ins ^ 0xFF)) {
Harald Welte65087832019-10-01 09:16:49 +02001259 /* transmit/recieve single byte then wait for proc */
1260 if (tfp->is_command) {
1261 /* transmit *next*, not first byte */
1262 OSMO_ASSERT(msgb_l3len(tfp->tpdu) >= 0);
Harald Welte6603d952019-10-09 20:50:13 +02001263 card_uart_tx(ip->uart, msgb_l3(tfp->tpdu), 1, false);
Harald Welte65087832019-10-01 09:16:49 +02001264 osmo_fsm_inst_state_chg(fi, TPDU_S_TX_SINGLE, 0, 0);
1265 } else {
Eric Wild2f5cdd12019-11-27 18:40:44 +01001266 card_uart_set_rx_threshold(ip->uart, 1);
1267 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 1);
Harald Welte65087832019-10-01 09:16:49 +02001268 osmo_fsm_inst_state_chg(fi, TPDU_S_RX_SINGLE, 0, 0);
1269 }
Harald Welte06348362019-05-19 00:45:17 +02001270 } else
1271 OSMO_ASSERT(0);
1272 break;
1273 default:
1274 OSMO_ASSERT(0);
1275 }
1276}
1277
1278/* UART is transmitting remaining data; we wait for ISO7816_E_TX_COMPL */
1279static void tpdu_s_tx_remaining_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1280{
1281 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1282 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1283
1284 switch (event) {
1285 case ISO7816_E_TX_COMPL:
1286 card_uart_set_rx_threshold(ip->uart, 1);
Eric Wild2f5cdd12019-11-27 18:40:44 +01001287 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 1);
Harald Welte06348362019-05-19 00:45:17 +02001288 osmo_fsm_inst_state_chg(fi, TPDU_S_SW1, 0, 0);
1289 break;
1290 default:
1291 OSMO_ASSERT(0);
1292 }
1293}
1294
1295/* UART is transmitting single byte of data; we wait for ISO7816_E_TX_COMPL */
1296static void tpdu_s_tx_single_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1297{
Harald Welte65087832019-10-01 09:16:49 +02001298 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
Eric Wild2f5cdd12019-11-27 18:40:44 +01001299 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1300 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
Harald Welte65087832019-10-01 09:16:49 +02001301
Harald Welte06348362019-05-19 00:45:17 +02001302 switch (event) {
1303 case ISO7816_E_TX_COMPL:
Harald Welte65087832019-10-01 09:16:49 +02001304 tfp->tpdu->l3h += 1;
Eric Wild2f5cdd12019-11-27 18:40:44 +01001305 card_uart_set_rx_threshold(ip->uart, 1);
1306 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 1);
Harald Welte65087832019-10-01 09:16:49 +02001307 if (msgb_l3len(tfp->tpdu))
1308 osmo_fsm_inst_state_chg(fi, TPDU_S_PROCEDURE, 0, 0);
1309 else
1310 osmo_fsm_inst_state_chg(fi, TPDU_S_SW1, 0, 0);
Harald Welte06348362019-05-19 00:45:17 +02001311 break;
1312 default:
1313 OSMO_ASSERT(0);
1314 }
1315}
1316
1317/* UART is receiving remaining data; we wait for ISO7816_E_RX_COMPL */
1318static void tpdu_s_rx_remaining_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1319{
1320 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
Harald Welte65087832019-10-01 09:16:49 +02001321 struct osim_apdu_cmd_hdr *tpduh = msgb_tpdu_hdr(tfp->tpdu);
Harald Welte06348362019-05-19 00:45:17 +02001322 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1323 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1324 int rc;
1325
1326 switch (event) {
1327 case ISO7816_E_RX_COMPL:
1328 /* retrieve pending byte(s) */
1329 rc = card_uart_rx(ip->uart, msgb_l2(tfp->tpdu), tpduh->p3);
Harald Welte65087832019-10-01 09:16:49 +02001330 OSMO_ASSERT(rc > 0);
1331 msgb_put(tfp->tpdu, rc);
1332 if (msgb_l2len(tfp->tpdu) != tpduh->p3) {
1333 LOGPFSML(fi, LOGL_ERROR, "expected %u bytes; read %d\n", tpduh->p3,
1334 msgb_l2len(tfp->tpdu));
1335 }
Harald Welte06348362019-05-19 00:45:17 +02001336 card_uart_set_rx_threshold(ip->uart, 1);
Eric Wild2f5cdd12019-11-27 18:40:44 +01001337 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 1);
Harald Welte06348362019-05-19 00:45:17 +02001338 osmo_fsm_inst_state_chg(fi, TPDU_S_SW1, 0, 0);
1339 break;
1340 default:
1341 OSMO_ASSERT(0);
1342 }
1343}
1344
1345/* UART is receiving single byte of data; we wait for ISO7816_E_RX_SINGLE */
1346static void tpdu_s_rx_single_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1347{
1348 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
Harald Welte65087832019-10-01 09:16:49 +02001349 struct osim_apdu_cmd_hdr *tpduh = msgb_tpdu_hdr(tfp->tpdu);
Eric Wild2f5cdd12019-11-27 18:40:44 +01001350 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1351 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
Harald Welte06348362019-05-19 00:45:17 +02001352 uint8_t byte;
1353
1354 switch (event) {
1355 case ISO7816_E_RX_SINGLE:
1356 byte = get_rx_byte_evt(fi->proc.parent, data);
1357 LOGPFSML(fi, LOGL_DEBUG, "Received 0x%02x from UART\n", byte);
Harald Welte65087832019-10-01 09:16:49 +02001358 msgb_put_u8(tfp->tpdu, byte);
Eric Wild2f5cdd12019-11-27 18:40:44 +01001359
1360 card_uart_set_rx_threshold(ip->uart, 1);
1361 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 1);
1362
Harald Welte65087832019-10-01 09:16:49 +02001363 /* determine if number of expected bytes received */
1364 if (msgb_l2len(tfp->tpdu) == tpduh->p3)
Harald Welte06348362019-05-19 00:45:17 +02001365 osmo_fsm_inst_state_chg(fi, TPDU_S_SW1, 0, 0);
Harald Welte65087832019-10-01 09:16:49 +02001366 else
Harald Welte06348362019-05-19 00:45:17 +02001367 osmo_fsm_inst_state_chg(fi, TPDU_S_PROCEDURE, 0, 0);
1368 break;
1369 default:
1370 OSMO_ASSERT(0);
1371 }
1372}
1373
1374static void tpdu_s_sw1_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1375{
1376 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
1377 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1378 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1379 uint8_t byte;
1380
1381 switch (event) {
1382 case ISO7816_E_RX_SINGLE:
1383 byte = get_rx_byte_evt(fi->proc.parent, data);
1384 LOGPFSML(fi, LOGL_DEBUG, "Received 0x%02x from UART\n", byte);
1385 /* record byte */
1386 //msgb_apdu_sw(tfp->apdu) = byte << 8;
1387 msgb_put_u8(tfp->tpdu, byte);
1388 card_uart_set_rx_threshold(ip->uart, 1);
Eric Wild2f5cdd12019-11-27 18:40:44 +01001389 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 1);
Harald Welte06348362019-05-19 00:45:17 +02001390 osmo_fsm_inst_state_chg(fi, TPDU_S_SW2, 0, 0);
1391 break;
1392 default:
1393 OSMO_ASSERT(0);
1394 }
1395}
1396
1397static void tpdu_s_sw2_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1398{
1399 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
1400 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1401 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1402 uint8_t byte;
1403
1404 switch (event) {
1405 case ISO7816_E_RX_SINGLE:
1406 byte = get_rx_byte_evt(fi->proc.parent, data);
1407 LOGPFSML(fi, LOGL_DEBUG, "Received 0x%02x from UART\n", byte);
1408 /* record SW2 byte */
1409 //msgb_apdu_sw(tfp->apdu) &= 0xFF00;
1410 //msgb_apdu_sw(tfp->apdu) |= byte;
1411 msgb_put_u8(tfp->tpdu, byte);
1412 osmo_fsm_inst_state_chg(fi, TPDU_S_DONE, 0, 0);
1413 /* Notify parent FSM */
1414 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_TPDU_DONE_IND, tfp->tpdu);
Eric Wild9e622dc2019-11-27 14:43:16 +01001415
1416 /* ownership transfer */
1417 tfp->tpdu = 0;
Harald Welte06348362019-05-19 00:45:17 +02001418 break;
1419 default:
1420 OSMO_ASSERT(0);
1421 }
1422}
1423
1424static void tpdu_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1425{
1426 OSMO_ASSERT(fi->fsm == &tpdu_fsm);
1427
1428 switch (event) {
1429 case ISO7816_E_RX_ERR_IND:
1430 case ISO7816_E_TX_ERR_IND:
1431 /* FIXME: handle this in some different way */
1432 osmo_fsm_inst_state_chg(fi, TPDU_S_DONE, 0, 0);
Eric Wild2f5cdd12019-11-27 18:40:44 +01001433 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_TPDU_FAILED_IND, NULL);
Harald Welte06348362019-05-19 00:45:17 +02001434 break;
1435 case ISO7816_E_TPDU_CLEAR_REQ:
1436 osmo_fsm_inst_state_chg(fi, TPDU_S_INIT, 0, 0);
1437 break;
1438 }
1439}
1440
Eric Wild2f5cdd12019-11-27 18:40:44 +01001441
1442static void tpdu_s_done_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
1443{
1444 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1445 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1446
1447 card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 0);
1448}
1449
Harald Welte06348362019-05-19 00:45:17 +02001450static const struct osmo_fsm_state tpdu_states[] = {
1451 [TPDU_S_INIT] = {
1452 .name = "INIT",
1453 .in_event_mask = S(ISO7816_E_XCEIVE_TPDU_CMD) |
1454 S(ISO7816_E_TX_COMPL),
1455 .out_state_mask = S(TPDU_S_INIT) |
1456 S(TPDU_S_TX_HDR),
1457 .action = tpdu_s_init_action,
Eric Wild9e622dc2019-11-27 14:43:16 +01001458 .onenter = tpdu_s_init_onenter,
Harald Welte06348362019-05-19 00:45:17 +02001459 },
1460 [TPDU_S_TX_HDR] = {
1461 .name = "TX_HDR",
1462 .in_event_mask = S(ISO7816_E_TX_COMPL),
1463 .out_state_mask = S(TPDU_S_INIT) |
1464 S(TPDU_S_PROCEDURE),
1465 .action = tpdu_s_tx_hdr_action,
1466 },
1467 [TPDU_S_PROCEDURE] = {
1468 .name = "PROCEDURE",
1469 .in_event_mask = S(ISO7816_E_RX_SINGLE),
1470 .out_state_mask = S(TPDU_S_INIT) |
1471 S(TPDU_S_PROCEDURE) |
1472 S(TPDU_S_RX_REMAINING) |
1473 S(TPDU_S_RX_SINGLE) |
1474 S(TPDU_S_TX_REMAINING) |
1475 S(TPDU_S_TX_SINGLE) |
1476 S(TPDU_S_SW2),
1477 .action = tpdu_s_procedure_action,
1478 },
1479 [TPDU_S_TX_REMAINING] = {
1480 .name = "TX_REMAINING",
1481 .in_event_mask = S(ISO7816_E_TX_COMPL),
1482 .out_state_mask = S(TPDU_S_INIT) |
1483 S(TPDU_S_SW1),
1484 .action = tpdu_s_tx_remaining_action,
1485 },
1486 [TPDU_S_TX_SINGLE] = {
1487 .name = "TX_SINGLE",
1488 .in_event_mask = S(ISO7816_E_TX_COMPL),
1489 .out_state_mask = S(TPDU_S_INIT) |
1490 S(TPDU_S_PROCEDURE),
1491 .action = tpdu_s_tx_single_action,
1492 },
1493 [TPDU_S_RX_REMAINING] = {
1494 .name = "RX_REMAINING",
1495 .in_event_mask = S(ISO7816_E_RX_COMPL),
1496 .out_state_mask = S(TPDU_S_INIT) |
1497 S(TPDU_S_SW1),
1498 .action = tpdu_s_rx_remaining_action,
1499 },
1500 [TPDU_S_RX_SINGLE] = {
1501 .name = "RX_SINGLE",
1502 .in_event_mask = S(ISO7816_E_RX_SINGLE),
1503 .out_state_mask = S(TPDU_S_INIT) |
1504 S(TPDU_S_PROCEDURE),
1505 .action = tpdu_s_rx_single_action,
1506 },
1507 [TPDU_S_SW1] = {
1508 .name = "SW1",
1509 .in_event_mask = S(ISO7816_E_RX_SINGLE),
1510 .out_state_mask = S(TPDU_S_INIT) |
1511 S(TPDU_S_SW2),
1512 .action = tpdu_s_sw1_action,
1513 },
1514 [TPDU_S_SW2] = {
1515 .name = "SW2",
1516 .in_event_mask = S(ISO7816_E_RX_SINGLE),
1517 .out_state_mask = S(TPDU_S_INIT) |
1518 S(TPDU_S_DONE),
1519 .action = tpdu_s_sw2_action,
1520 },
1521 [TPDU_S_DONE] = {
1522 .name = "DONE",
1523 .in_event_mask = 0,
1524 .out_state_mask = S(TPDU_S_INIT),
1525 .action = NULL,
Eric Wild2f5cdd12019-11-27 18:40:44 +01001526 .onenter = tpdu_s_done_onenter,
Harald Welte06348362019-05-19 00:45:17 +02001527 },
1528};
1529static struct osmo_fsm tpdu_fsm = {
1530 .name = "TPDU",
1531 .states = tpdu_states,
1532 .num_states = ARRAY_SIZE(tpdu_states),
1533 .allstate_event_mask = S(ISO7816_E_RX_ERR_IND) |
1534 S(ISO7816_E_TX_ERR_IND) |
1535 S(ISO7816_E_TPDU_CLEAR_REQ),
1536 .allstate_action = tpdu_allstate_action,
1537 .log_subsys = DTPDU,
1538 .event_names = iso7816_3_event_names,
1539};
1540
1541struct osmo_fsm_inst *iso7816_fsm_alloc(void *ctx, int log_level, const char *id,
1542 struct card_uart *cuart, iso7816_user_cb user_cb,
1543 void *user_priv)
1544{
1545 struct iso7816_3_priv *ip;
1546 struct osmo_fsm_inst *fi;
1547
1548 fi = osmo_fsm_inst_alloc(&iso7816_3_fsm, ctx, NULL, log_level, id);
1549 ip = talloc_zero(fi, struct iso7816_3_priv);
1550 if (!ip)
1551 goto out_fi;
1552 fi->priv = ip;
1553
1554 ip->uart = cuart;
1555 cuart->priv = fi;
1556 cuart->handle_event = tpdu_uart_notification;
1557
1558 ip->user_cb = user_cb;
1559 ip->user_priv = user_priv;
1560
1561 ip->atr_fi = osmo_fsm_inst_alloc_child(&atr_fsm, fi, ISO7816_E_SW_ERR_IND);
1562 if (!ip->atr_fi)
1563 goto out_fi;
1564 ip->atr_fi->priv = talloc_zero(ip->atr_fi, struct atr_fsm_priv);
1565 if (!ip->atr_fi->priv)
1566 goto out_atr;
1567
1568 ip->tpdu_fi = osmo_fsm_inst_alloc_child(&tpdu_fsm, fi, ISO7816_E_SW_ERR_IND);
1569 if (!ip->tpdu_fi)
1570 goto out_atr;
1571 ip->tpdu_fi->priv = talloc_zero(ip->tpdu_fi, struct tpdu_fsm_priv);
1572 if (!ip->tpdu_fi->priv)
1573 goto out_tpdu;
1574
Eric Wildad1edce2019-11-27 16:51:08 +01001575#if 1
Harald Welte06348362019-05-19 00:45:17 +02001576 ip->pps_fi = osmo_fsm_inst_alloc_child(&pps_fsm, fi, ISO7816_E_SW_ERR_IND);
1577 if (!ip->pps_fi)
1578 goto out_tpdu;
1579 ip->pps_fi->priv = talloc_zero(ip->pps_fi, struct pps_fsm_priv);
1580 if (!ip->pps_fi->priv)
1581 goto out_pps;
1582#endif
1583
1584 /* This ensures the 'onenter' function of the initial state is called */
1585 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
1586
1587 return fi;
1588
Eric Wildad1edce2019-11-27 16:51:08 +01001589#if 1
Harald Welte06348362019-05-19 00:45:17 +02001590out_pps:
1591 osmo_fsm_inst_free(ip->pps_fi);
1592#endif
1593out_tpdu:
1594 osmo_fsm_inst_free(ip->tpdu_fi);
1595out_atr:
1596 osmo_fsm_inst_free(ip->atr_fi);
1597out_fi:
1598 osmo_fsm_inst_free(fi);
1599 cuart->priv = NULL;
1600 return NULL;
1601}
1602
1603void *iso7816_fsm_get_user_priv(struct osmo_fsm_inst *fi)
1604{
1605 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
1606 return ip->user_priv;
1607}
1608
1609
1610static __attribute__((constructor)) void on_dso_load_iso7816(void)
1611{
1612 osmo_fsm_register(&iso7816_3_fsm);
1613 osmo_fsm_register(&atr_fsm);
1614 osmo_fsm_register(&tpdu_fsm);
1615 osmo_fsm_register(&pps_fsm);
1616}