blob: d02a955ae2a4d689d9030bcb86d69c49e86a81a0 [file] [log] [blame]
Harald Welte06348362019-05-19 00:45:17 +02001/* ISO 7816-3 Finite State Machine (reader side)
2 *
3 * (C) 2019 by Harald Welte <laforge@gnumonks.org>
4 *
5 * inspired by earlier work
6 * (C) 2016-2017 by Harald Welte <hwelte@hmw-consulting.de>
7 * (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
22 */
23
24#include <string.h>
25
26#include <osmocom/core/utils.h>
27#include <osmocom/core/msgb.h>
28#include <osmocom/core/fsm.h>
29#include <osmocom/core/logging.h>
30#include <osmocom/sim/sim.h>
31
32#include "logging.h"
33#include "cuart.h"
34#include "iso7816_fsm.h"
35
36/* Section 8.2: the Answer-to-Reset (... a string of at most 32 bytes) */
37#define MAX_ATR_SIZE 32
38
39#define S(x) (1 << (x))
40
41/*! ISO 7816-3 states */
42enum iso7816_3_state {
43 ISO7816_S_RESET, /*!< in Reset */
44 ISO7816_S_WAIT_ATR, /*!< waiting for ATR to start */
45 ISO7816_S_IN_ATR, /*!< while we are receiving the ATR */
46 ISO7816_S_WAIT_TPDU, /*!< waiting for start of new TPDU */
47 ISO7816_S_IN_TPDU, /*!< inside a single TPDU */
48 ISO7816_S_IN_PPS_REQ, /*!< while we are inside the PPS request */
49 ISO7816_S_WAIT_PPS_RSP, /*!< waiting for start of the PPS response */
50 ISO7816_S_IN_PPS_RSP, /*!< while we are inside the PPS request */
51};
52
53/*! Answer-To-Reset (ATR) sub-states of ISO7816_S_IN_ATR
54 * @note defined in ISO/IEC 7816-3:2006(E) section 8
55 */
56enum atr_state {
57 ATR_S_WAIT_TS, /*!< initial byte */
58 ATR_S_WAIT_T0, /*!< format byte */
59 ATR_S_WAIT_TA, /*!< first sub-group interface byte */
60 ATR_S_WAIT_TB, /*!< second sub-group interface byte */
61 ATR_S_WAIT_TC, /*!< third sub-group interface byte */
62 ATR_S_WAIT_TD, /*!< fourth sub-group interface byte */
63 ATR_S_WAIT_HIST, /*!< historical byte */
64 ATR_S_WAIT_TCK, /*!< check byte */
65 ATR_S_DONE
66};
67
68/*! Protocol and Parameters Selection (PPS) sub-states of ISO7816_S_IN_PTS_REQ/ISO7816_S_IN_PTS_RSP
69 * @note defined in ISO/IEC 7816-3:2006(E) section 9
70 */
71enum pps_state {
Eric Wildad1edce2019-11-27 16:51:08 +010072 PPS_S_TX_PPS_REQ, /*!< tx pps request */
Harald Welte06348362019-05-19 00:45:17 +020073 PPS_S_WAIT_PPSS, /*!< initial byte */
74 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 */
79 PPS_S_WAIT_END, /*!< all done */
80 PPS_S_DONE
81};
82
83/*! Transport Protocol Data Unit (TPDU) sub-states of ISO7816_S_IN_TPDU
84 * @note defined in ISO/IEC 7816-3:2006(E) section 10 and 12
85 * @remark APDUs are formed by one or more command+response TPDUs
86 */
87enum tpdu_state {
88 TPDU_S_INIT, /*!< initial state */
89 TPDU_S_TX_HDR, /*!< transmitting hdr, waiting for completion */
90 TPDU_S_PROCEDURE, /*!< procedure byte (could also be SW1) */
91 TPDU_S_TX_REMAINING, /*!< Tx remaining data bytes */
92 TPDU_S_TX_SINGLE, /*!< Tx single data byte */
93 TPDU_S_RX_REMAINING, /*!< Rx remaining data bytes */
94 TPDU_S_RX_SINGLE, /*!< Rx single data byte */
95 TPDU_S_SW1, /*!< first status word */
96 TPDU_S_SW2, /*!< second status word */
97 TPDU_S_DONE,
98};
99
100/* FSM timer enumeration */
101enum iso7816_3_timer {
102 T_WAIT_ATR = 1,
103 T_GUARD,
104};
105
106/* forward declarations */
107static struct osmo_fsm iso7816_3_fsm;
108static struct osmo_fsm atr_fsm;
109static struct osmo_fsm tpdu_fsm;
110static struct osmo_fsm pps_fsm;
111
112/* look-up table for bit-wise inversion to convert from "inverse convention" to normal */
113static const uint8_t convention_convert_lut[256] = {
114 0xff, 0x7f, 0xbf, 0x3f, 0xdf, 0x5f, 0x9f, 0x1f, 0xef, 0x6f, 0xaf, 0x2f, 0xcf, 0x4f, 0x8f, 0x0f,
115 0xf7, 0x77, 0xb7, 0x37, 0xd7, 0x57, 0x97, 0x17, 0xe7, 0x67, 0xa7, 0x27, 0xc7, 0x47, 0x87, 0x07,
116 0xfb, 0x7b, 0xbb, 0x3b, 0xdb, 0x5b, 0x9b, 0x1b, 0xeb, 0x6b, 0xab, 0x2b, 0xcb, 0x4b, 0x8b, 0x0b,
117 0xf3, 0x73, 0xb3, 0x33, 0xd3, 0x53, 0x93, 0x13, 0xe3, 0x63, 0xa3, 0x23, 0xc3, 0x43, 0x83, 0x03,
118 0xfd, 0x7d, 0xbd, 0x3d, 0xdd, 0x5d, 0x9d, 0x1d, 0xed, 0x6d, 0xad, 0x2d, 0xcd, 0x4d, 0x8d, 0x0d,
119 0xf5, 0x75, 0xb5, 0x35, 0xd5, 0x55, 0x95, 0x15, 0xe5, 0x65, 0xa5, 0x25, 0xc5, 0x45, 0x85, 0x05,
120 0xf9, 0x79, 0xb9, 0x39, 0xd9, 0x59, 0x99, 0x19, 0xe9, 0x69, 0xa9, 0x29, 0xc9, 0x49, 0x89, 0x09,
121 0xf1, 0x71, 0xb1, 0x31, 0xd1, 0x51, 0x91, 0x11, 0xe1, 0x61, 0xa1, 0x21, 0xc1, 0x41, 0x81, 0x01,
122 0xfe, 0x7e, 0xbe, 0x3e, 0xde, 0x5e, 0x9e, 0x1e, 0xee, 0x6e, 0xae, 0x2e, 0xce, 0x4e, 0x8e, 0x0e,
123 0xf6, 0x76, 0xb6, 0x36, 0xd6, 0x56, 0x96, 0x16, 0xe6, 0x66, 0xa6, 0x26, 0xc6, 0x46, 0x86, 0x06,
124 0xfa, 0x7a, 0xba, 0x3a, 0xda, 0x5a, 0x9a, 0x1a, 0xea, 0x6a, 0xaa, 0x2a, 0xca, 0x4a, 0x8a, 0x0a,
125 0xf2, 0x72, 0xb2, 0x32, 0xd2, 0x52, 0x92, 0x12, 0xe2, 0x62, 0xa2, 0x22, 0xc2, 0x42, 0x82, 0x02,
126 0xfc, 0x7c, 0xbc, 0x3c, 0xdc, 0x5c, 0x9c, 0x1c, 0xec, 0x6c, 0xac, 0x2c, 0xcc, 0x4c, 0x8c, 0x0c,
127 0xf4, 0x74, 0xb4, 0x34, 0xd4, 0x54, 0x94, 0x14, 0xe4, 0x64, 0xa4, 0x24, 0xc4, 0x44, 0x84, 0x04,
128 0xf8, 0x78, 0xb8, 0x38, 0xd8, 0x58, 0x98, 0x18, 0xe8, 0x68, 0xa8, 0x28, 0xc8, 0x48, 0x88, 0x08,
129 0xf0, 0x70, 0xb0, 0x30, 0xd0, 0x50, 0x90, 0x10, 0xe0, 0x60, 0xa0, 0x20, 0xc0, 0x40, 0x80, 0x00,
130};
131
132/***********************************************************************
133 * ISO7816-3 Main FSM
134 ***********************************************************************/
135
136static const struct value_string iso7816_3_event_names[] = {
137 { ISO7816_E_RX_SINGLE, "UART_RX_SINGLE" },
138 { ISO7816_E_RX_COMPL, "UART_RX_COMPL" },
139 { ISO7816_E_TX_COMPL, "UART_TX_COMPL" },
140 { ISO7816_E_POWER_UP_IND, "POWER_UP_IND" },
141 { ISO7816_E_RESET_REL_IND, "RESET_REL_IND" },
142 { ISO7816_E_RX_ERR_IND, "RX_ERR_IND" },
143 { ISO7816_E_TX_ERR_IND, "TX_ERR_IND" },
144 { ISO7816_E_ATR_DONE_IND, "ATR_DONE_IND" },
Harald Welte1ac9ef92019-10-09 22:20:16 +0200145 { ISO7816_E_ATR_ERR_IND, "ATR_ERR_IND" },
Harald Welte06348362019-05-19 00:45:17 +0200146 { ISO7816_E_TPDU_DONE_IND, "TPDU_DONE_IND" },
147 { ISO7816_E_XCEIVE_TPDU_CMD, "XCEIVE_TPDU_CMD" },
148 /* allstate events */
149 { ISO7816_E_WTIME_EXP, "WAIT_TIME_EXP" },
150 { ISO7816_E_HW_ERR_IND, "HW_ERR_IND" },
151 { ISO7816_E_SW_ERR_IND, "SW_ERR_IND" },
152 { ISO7816_E_CARD_REMOVAL, "CARD_REMOVAL" },
153 { ISO7816_E_POWER_DN_IND, "POWER_DN_IND" },
154 { ISO7816_E_RESET_ACT_IND, "RESET_ACT_IND" },
155 { ISO7816_E_ABORT_REQ, "ABORT_REQ" },
156 { ISO7816_E_TPDU_CLEAR_REQ, "TPDU_CLEAR_REQ" },
157 { 0, NULL }
158};
159
160struct iso7816_3_priv {
161 uint8_t slot_nr;
162 /* child FSM instances */
163 struct osmo_fsm_inst *atr_fi;
164 struct osmo_fsm_inst *pps_fi;
165 struct osmo_fsm_inst *tpdu_fi;
166 /* other data */
167 bool convention_convert;/*!< If convention conversion is needed */
168 uint16_t guard_time_ms;
169 /* underlying UART */
170 struct card_uart *uart;
171 iso7816_user_cb user_cb;
172 void *user_priv;
173};
174
175/* type-safe method to obtain iso7816_3_priv from fi */
176static struct iso7816_3_priv *get_iso7816_3_priv(struct osmo_fsm_inst *fi)
177{
178 OSMO_ASSERT(fi);
179 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
180 return (struct iso7816_3_priv *) fi->priv;
181}
182
183/* convert from clock cycles of the CLK line to milli-seconds */
184uint32_t fi_cycles2ms(struct osmo_fsm_inst *fi, uint32_t cyclces)
185{
186 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
187 /* FIXME */
188 return 1000;
189}
190
191/* card UART notifies us: dispatch to (main ISO7816-3) FSM */
192static void tpdu_uart_notification(struct card_uart *cuart, enum card_uart_event evt, void *data)
193{
194 struct osmo_fsm_inst *fi = (struct osmo_fsm_inst *) cuart->priv;
195 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
196
197 LOGPFSML(fi, LOGL_DEBUG, "UART Notification '%s'\n",
198 get_value_string(card_uart_event_vals, evt));
199
200 /* FIXME: Set only flags here; Main loop polls flags and dispatches events */
201
202 switch (evt) {
203 case CUART_E_RX_SINGLE:
204 osmo_fsm_inst_dispatch(fi, ISO7816_E_RX_SINGLE, data);
205 break;
206 case CUART_E_RX_COMPLETE:
207 osmo_fsm_inst_dispatch(fi, ISO7816_E_RX_COMPL, data);
208 break;
209 case CUART_E_RX_TIMEOUT:
210 osmo_fsm_inst_dispatch(fi, ISO7816_E_WTIME_EXP, data);
211 break;
212 case CUART_E_TX_COMPLETE:
213 osmo_fsm_inst_dispatch(fi, ISO7816_E_TX_COMPL, data);
214 break;
215 }
216}
217
218static void iso7816_3_reset_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
219{
220 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
221 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
222
223 /* go back to initial state in child FSMs */
224 osmo_fsm_inst_state_chg(ip->atr_fi, ATR_S_WAIT_TS, 0, 0);
Eric Wildad1edce2019-11-27 16:51:08 +0100225 osmo_fsm_inst_state_chg(ip->pps_fi, PPS_S_TX_PPS_REQ, 0, 0);
Harald Welte06348362019-05-19 00:45:17 +0200226 osmo_fsm_inst_state_chg(ip->tpdu_fi, TPDU_S_INIT, 0, 0);
227}
228
229static void iso7816_3_reset_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
230{
231 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
232 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
233
234 switch (event) {
235 case ISO7816_E_RESET_REL_IND:
236 /* TOOD: this should happen before reset is released */
237 card_uart_ctrl(ip->uart, CUART_CTL_RX, true);
238 osmo_fsm_inst_state_chg_ms(fi, ISO7816_S_WAIT_ATR,
239 fi_cycles2ms(fi, 40000), T_WAIT_ATR);
240 break;
241 default:
242 OSMO_ASSERT(0);
243 }
244}
245
246static void iso7816_3_wait_atr_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
247{
248 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
249 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
250
251 switch (event) {
252 case ISO7816_E_RX_SINGLE:
253 osmo_fsm_inst_state_chg(fi, ISO7816_S_IN_ATR, 0, 0);
254 osmo_fsm_inst_dispatch(ip->atr_fi, event, data);
255 break;
Harald Welte1ac9ef92019-10-09 22:20:16 +0200256 case ISO7816_E_WTIME_EXP:
257 ip->user_cb(fi, event, 0, NULL);
258 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
259 break;
Harald Welte06348362019-05-19 00:45:17 +0200260 default:
261 OSMO_ASSERT(0);
262 }
263}
264
265static void iso7816_3_in_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 struct msgb *atr;
269 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
270
271 switch (event) {
272 case ISO7816_E_RX_SINGLE:
273 case ISO7816_E_RX_ERR_IND:
Harald Welte1ac9ef92019-10-09 22:20:16 +0200274 case ISO7816_E_WTIME_EXP:
Harald Welte06348362019-05-19 00:45:17 +0200275 /* simply pass this through to the child FSM for the ATR */
276 osmo_fsm_inst_dispatch(ip->atr_fi, event, data);
277 break;
278 case ISO7816_E_ATR_DONE_IND:
279 atr = data;
280 /* FIXME: verify ATR result: success / failure */
281 osmo_fsm_inst_state_chg(fi, ISO7816_S_WAIT_TPDU, 0, 0);
282 /* notify user about ATR */
283 ip->user_cb(fi, event, 0, atr);
284 break;
Harald Welte1ac9ef92019-10-09 22:20:16 +0200285 case ISO7816_E_ATR_ERR_IND:
286 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
287 ip->user_cb(fi, event, 0, atr);
288 break;
Harald Welte06348362019-05-19 00:45:17 +0200289 default:
290 OSMO_ASSERT(0);
291 }
292}
293
294static void iso7816_3_wait_tpdu_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
295{
296 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
297 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
Harald Weltebe86f852019-10-09 22:25:48 +0200298 card_uart_ctrl(ip->uart, CUART_CTL_RX, false);
Harald Welte06348362019-05-19 00:45:17 +0200299 /* reset the TPDU state machine */
300 osmo_fsm_inst_dispatch(ip->tpdu_fi, ISO7816_E_TPDU_CLEAR_REQ, NULL);
301}
302
303static void iso7816_3_wait_tpdu_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
304{
305 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
306 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
307
308 switch (event) {
309 case ISO7816_E_XCEIVE_TPDU_CMD:
310 /* "data" contains a msgb-wrapped TPDU */
311 osmo_fsm_inst_state_chg(fi, ISO7816_S_IN_TPDU, 0, 0);
312 /* pass on to sub-fsm */
313 osmo_fsm_inst_dispatch(ip->tpdu_fi, event, data);
314 break;
Eric Wildad1edce2019-11-27 16:51:08 +0100315 case ISO7816_E_XCEIVE_PPS_CMD:
316 osmo_fsm_inst_state_chg(fi, ISO7816_S_WAIT_PPS_RSP, 0, 0);
317 osmo_fsm_inst_state_chg(ip->pps_fi, PPS_S_TX_PPS_REQ, 0, 0);
318 osmo_fsm_inst_dispatch(ip->pps_fi, event, data);
319 break;
Harald Welte06348362019-05-19 00:45:17 +0200320 default:
321 OSMO_ASSERT(0);
322 }
323}
324
325static void iso7816_3_in_tpdu_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
326{
327 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
328 struct msgb *apdu;
329 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
330
331 switch (event) {
332 case ISO7816_E_RX_SINGLE:
333 case ISO7816_E_RX_COMPL:
334 case ISO7816_E_RX_ERR_IND:
335 case ISO7816_E_TX_COMPL:
336 case ISO7816_E_TX_ERR_IND:
337 /* simply pass this through to the child FSM for the ATR */
338 osmo_fsm_inst_dispatch(ip->tpdu_fi, event, data);
339 break;
340 case ISO7816_E_TPDU_DONE_IND:
341 apdu = data;
342 osmo_fsm_inst_state_chg(fi, ISO7816_S_WAIT_TPDU, 0, 0);
343 /* hand finished TPDU to user */
344 ip->user_cb(fi, event, 0, apdu);
345 break;
Harald Welte1ac9ef92019-10-09 22:20:16 +0200346 case ISO7816_E_WTIME_EXP:
347 /* FIXME: power off? */
348 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
349 break;
Harald Welte06348362019-05-19 00:45:17 +0200350 default:
351 OSMO_ASSERT(0);
352 }
353}
354
355static void iso7816_3_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
356{
357 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
358
359 switch (event) {
Harald Welte06348362019-05-19 00:45:17 +0200360 case ISO7816_E_HW_ERR_IND:
361 case ISO7816_E_CARD_REMOVAL:
362 /* FIXME: power off? */
363 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
364 break;
365 case ISO7816_E_POWER_DN_IND:
366 case ISO7816_E_RESET_ACT_IND:
367 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
368 break;
369 case ISO7816_E_ABORT_REQ:
370 /* FIXME */
371 break;
372 default:
373 OSMO_ASSERT(0);
374 break;
375 }
376}
377
Eric Wildad1edce2019-11-27 16:51:08 +0100378static void iso7816_3_in_pps_req_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
379{
380 struct iso7816_3_priv *tfp = get_iso7816_3_priv(fi);
381
382 switch (event) {
383 case ISO7816_E_XCEIVE_PPS_CMD:
384 osmo_fsm_inst_state_chg(fi, ISO7816_S_WAIT_PPS_RSP, 0, 0);
385 break;
386 default:
387 OSMO_ASSERT(0);
388 }
389}
390
391
392static void iso7816_3_s_wait_pps_rsp_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
393{
394 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
395 switch (event) {
396 case ISO7816_E_TX_COMPL:
397 /* Rx of single byte is already enabled by previous card_uart_tx() call */
398 osmo_fsm_inst_state_chg(fi, ISO7816_S_IN_PPS_RSP, 0, 0);
399 break;
400 default:
401 OSMO_ASSERT(0);
402 }
403}
404
405static void iso7816_3_s_ins_pps_rsp_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
406{
407 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
408 struct msgb *ppsrsp;
409 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
410
411 switch (event) {
412 case ISO7816_E_RX_SINGLE:
413 case ISO7816_E_WTIME_EXP:
414 /* simply pass this through to the child FSM for the ATR */
415 osmo_fsm_inst_dispatch(ip->pps_fi, event, data);
416 break;
417 case ISO7816_E_PPS_DONE_IND:
418 case ISO7816_E_PPS_FAILED_IND:
419 ppsrsp = data;
420 osmo_fsm_inst_state_chg(fi, ISO7816_S_WAIT_TPDU, 0, 0);
421 /* notify user about PPS result */
422 ip->user_cb(fi, event, 0, ppsrsp);
423 break;
424 case ISO7816_E_RX_ERR_IND:
425 ppsrsp = data;
426 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
427 ip->user_cb(fi, event, 0, ppsrsp);
428 break;
429 default:
430 OSMO_ASSERT(0);
431 }
432}
433
Harald Welte06348362019-05-19 00:45:17 +0200434static const struct osmo_fsm_state iso7816_3_states[] = {
435 [ISO7816_S_RESET] = {
436 .name = "RESET",
437 .in_event_mask = S(ISO7816_E_RESET_REL_IND),
438 .out_state_mask = S(ISO7816_S_WAIT_ATR) |
439 S(ISO7816_S_RESET),
440 .action = iso7816_3_reset_action,
441 .onenter = iso7816_3_reset_onenter,
442 },
443 [ISO7816_S_WAIT_ATR] = {
444 .name = "WAIT_ATR",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200445 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
446 S(ISO7816_E_WTIME_EXP),
Harald Welte06348362019-05-19 00:45:17 +0200447 .out_state_mask = S(ISO7816_S_RESET) |
448 S(ISO7816_S_IN_ATR),
449 .action = iso7816_3_wait_atr_action,
450 },
451 [ISO7816_S_IN_ATR] = {
452 .name = "IN_ATR",
453 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
454 S(ISO7816_E_RX_ERR_IND) |
Harald Welte1ac9ef92019-10-09 22:20:16 +0200455 S(ISO7816_E_ATR_DONE_IND) |
456 S(ISO7816_E_ATR_ERR_IND) |
457 S(ISO7816_E_WTIME_EXP),
Harald Welte06348362019-05-19 00:45:17 +0200458 .out_state_mask = S(ISO7816_S_RESET) |
459 S(ISO7816_S_IN_ATR) |
460 S(ISO7816_S_WAIT_TPDU),
461 .action = iso7816_3_in_atr_action,
462 },
463 [ISO7816_S_WAIT_TPDU] = {
464 .name = "WAIT_TPDU",
Eric Wildad1edce2019-11-27 16:51:08 +0100465 .in_event_mask = S(ISO7816_E_XCEIVE_TPDU_CMD) |
466 S(ISO7816_E_XCEIVE_PPS_CMD),
Harald Welte06348362019-05-19 00:45:17 +0200467 .out_state_mask = S(ISO7816_S_RESET) |
468 S(ISO7816_S_WAIT_TPDU) |
469 S(ISO7816_S_IN_TPDU) |
Eric Wildad1edce2019-11-27 16:51:08 +0100470 S(ISO7816_S_IN_PPS_REQ) |
471 S(ISO7816_S_WAIT_PPS_RSP),
Harald Welte06348362019-05-19 00:45:17 +0200472 .action = iso7816_3_wait_tpdu_action,
473 .onenter = iso7816_3_wait_tpdu_onenter,
474 },
475 [ISO7816_S_IN_TPDU] = {
476 .name = "IN_TPDU",
477 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
478 S(ISO7816_E_RX_COMPL) |
479 S(ISO7816_E_TX_COMPL) |
480 S(ISO7816_E_RX_ERR_IND) |
481 S(ISO7816_E_TX_ERR_IND) |
Harald Welte1ac9ef92019-10-09 22:20:16 +0200482 S(ISO7816_E_TPDU_DONE_IND) |
483 S(ISO7816_E_WTIME_EXP),
Harald Welte06348362019-05-19 00:45:17 +0200484 .out_state_mask = S(ISO7816_S_RESET) |
485 S(ISO7816_S_WAIT_TPDU) |
486 S(ISO7816_S_IN_TPDU),
487 .action = iso7816_3_in_tpdu_action,
488 },
489 [ISO7816_S_IN_PPS_REQ] = {
490 .name = "IN_PPS_REQ",
Eric Wildad1edce2019-11-27 16:51:08 +0100491 .in_event_mask = S(ISO7816_E_XCEIVE_TPDU_CMD),
Harald Welte06348362019-05-19 00:45:17 +0200492 .out_state_mask = S(ISO7816_S_RESET) |
493 S(ISO7816_S_WAIT_TPDU) |
494 S(ISO7816_S_IN_PPS_REQ) |
495 S(ISO7816_S_WAIT_PPS_RSP),
Eric Wildad1edce2019-11-27 16:51:08 +0100496 .action = iso7816_3_in_pps_req_action,
Harald Welte06348362019-05-19 00:45:17 +0200497 },
498 [ISO7816_S_WAIT_PPS_RSP] = {
499 .name = "WAIT_PPS_RESP",
Eric Wildad1edce2019-11-27 16:51:08 +0100500 .in_event_mask = S(ISO7816_E_TX_COMPL) |
501 S(ISO7816_E_TX_ERR_IND) |
502 S(ISO7816_E_WTIME_EXP),
Harald Welte06348362019-05-19 00:45:17 +0200503 .out_state_mask = S(ISO7816_S_RESET) |
504 S(ISO7816_S_WAIT_TPDU) |
505 S(ISO7816_S_WAIT_PPS_RSP) |
506 S(ISO7816_S_IN_PPS_RSP),
Eric Wildad1edce2019-11-27 16:51:08 +0100507 .action = iso7816_3_s_wait_pps_rsp_action,
Harald Welte06348362019-05-19 00:45:17 +0200508 },
509 [ISO7816_S_IN_PPS_RSP] = {
510 .name = "IN_PPS_RESP",
Eric Wildad1edce2019-11-27 16:51:08 +0100511 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
512 S(ISO7816_E_RX_COMPL) |
513 S(ISO7816_E_RX_ERR_IND) |
514 S(ISO7816_E_PPS_DONE_IND) |
515 S(ISO7816_E_PPS_FAILED_IND) |
516 S(ISO7816_E_WTIME_EXP),
Harald Welte06348362019-05-19 00:45:17 +0200517 .out_state_mask = S(ISO7816_S_RESET) |
518 S(ISO7816_S_WAIT_TPDU) |
519 S(ISO7816_S_IN_PPS_RSP),
Eric Wildad1edce2019-11-27 16:51:08 +0100520 .action = iso7816_3_s_ins_pps_rsp_action,
Harald Welte06348362019-05-19 00:45:17 +0200521 },
522};
523static struct osmo_fsm iso7816_3_fsm = {
524 .name = "ISO7816-3",
525 .states = iso7816_3_states,
526 .num_states = ARRAY_SIZE(iso7816_3_states),
527 .log_subsys = DISO7816,
528 .event_names = iso7816_3_event_names,
529 .allstate_action = iso7816_3_allstate_action,
Harald Welte1ac9ef92019-10-09 22:20:16 +0200530 .allstate_event_mask = S(ISO7816_E_CARD_REMOVAL) |
Harald Welte06348362019-05-19 00:45:17 +0200531 S(ISO7816_E_POWER_DN_IND) |
532 S(ISO7816_E_RESET_ACT_IND) |
533 S(ISO7816_E_HW_ERR_IND) |
534 S(ISO7816_E_ABORT_REQ),
535};
536
537/***********************************************************************
538 * ATR FSM
539 ***********************************************************************/
540
541struct atr_fsm_priv {
542 uint8_t hist_len; /*!< store the number of expected historical bytes */
543 uint8_t y; /*!< last mask of the upcoming TA, TB, TC, TD interface bytes */
544 uint8_t i; /*!< interface byte subgroup number */
545 struct msgb *atr; /*!< ATR data */
546 uint8_t computed_checksum;
547 uint16_t protocol_support;
548};
549
550/* obtain the [software] guard time in milli-seconds from the atr fsm_inst */
551static uint32_t atr_fi_gt_ms(struct osmo_fsm_inst *fi)
552{
553 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
554 struct iso7816_3_priv *ip;
555
556 OSMO_ASSERT(fi->fsm == &atr_fsm);
557 OSMO_ASSERT(parent_fi);
558 ip = get_iso7816_3_priv(parent_fi);
559
560 return ip->guard_time_ms;
561}
562
563/* obtain the 'byte' parmeter of an ISO7816_E_RX event */
564static uint8_t get_rx_byte_evt(struct osmo_fsm_inst *fi, void *data)
565{
566 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
567 uint8_t byte = *(uint8_t *)data;
568
569 /* apply inverse convention */
570 if (ip->convention_convert)
571 byte = convention_convert_lut[byte];
572
573 return byte;
574}
575
576/* append a single byte to the ATR */
577static int atr_append_byte(struct osmo_fsm_inst *fi, uint8_t byte)
578{
579 struct atr_fsm_priv *atp = fi->priv;
580
581 if (!msgb_tailroom(atp->atr)) {
582 LOGPFSML(fi, LOGL_ERROR, "ATR overflow !?!");
583 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_SW_ERR_IND, NULL);
584 return -1;
585 }
586 msgb_put_u8(atp->atr, byte);
587 return 0;
588}
589
590static void atr_wait_ts_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
591{
592 struct atr_fsm_priv *atp = fi->priv;
593
594 /* reset state to its initial value */
595 atp->hist_len = 0;
596 atp->y = 0;
597 atp->i = 0;
598 if (!atp->atr)
599 atp->atr = msgb_alloc_c(fi, 33, "ATR"); /* TS + 32 chars */
600 else
601 msgb_reset(atp->atr);
602 atp->computed_checksum = 0;
603 atp->protocol_support = 0;
604}
605
606static void atr_wait_ts_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
607{
608 struct atr_fsm_priv *atp = fi->priv;
609 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
610 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
611 uint8_t byte;
612
613 switch (event) {
614 case ISO7816_E_RX_SINGLE:
615 OSMO_ASSERT(msgb_length(atp->atr) == 0);
616restart:
617 byte = get_rx_byte_evt(parent_fi, data);
618 LOGPFSML(fi, LOGL_DEBUG, "RX byte '%02x'\n", byte);
619 switch (byte) {
620 case 0x23:
621 /* direct convention used, but decoded using inverse
622 * convention (a parity error should also have occurred) */
623 /* fall-through */
624 case 0x30:
625 /* inverse convention used, but decoded using direct
626 * convention (a parity error should also have occurred) */
627 ip->convention_convert = !ip->convention_convert;
628 goto restart;
629 break;
630 case 0x3b: /* direct convention used and correctly decoded */
631 /* fall-through */
632 case 0x3f: /* inverse convention used and correctly decoded */
633 atr_append_byte(fi, byte);
634 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_T0, atr_fi_gt_ms(fi), T_GUARD);
635 break;
636 default:
637 LOGPFSML(fi, LOGL_ERROR, "Invalid TS received: 0x%02X\n", byte);
638 /* FIXME: somehow indiicate to user */
639 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_SW_ERR_IND, NULL);
640 break;
641 }
642 atp->i = 0; /* first interface byte sub-group is coming (T0 is kind of TD0) */
643 break;
Harald Welte1ac9ef92019-10-09 22:20:16 +0200644 case ISO7816_E_WTIME_EXP:
645 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_ATR_ERR_IND, NULL);
646 break;
Harald Welte06348362019-05-19 00:45:17 +0200647 default:
648 OSMO_ASSERT(0);
649 }
650}
651
652static void atr_wait_tX_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
653{
654 struct atr_fsm_priv *atp = fi->priv;
655 uint32_t guard_time_ms = atr_fi_gt_ms(fi);
656 uint8_t byte;
657
658 switch (event) {
659 case ISO7816_E_RX_SINGLE:
660 byte = get_rx_byte_evt(fi->proc.parent, data);
661 LOGPFSML(fi, LOGL_DEBUG, "RX byte '%02x'\n", byte);
662 atr_append_byte(fi, byte);
663 switch (fi->state) {
664 case ATR_S_WAIT_T0: /* see ISO/IEC 7816-3:2006 section 8.2.2 */
665 case ATR_S_WAIT_TD: /* see ISO/IEC 7816-3:2006 section 8.2.3 */
666 if (fi->state == ATR_S_WAIT_T0) {
667 /* save number of hist. bytes */
668 atp->hist_len = (byte & 0x0f);
669 } else {
670 /* remember supported protocol to know if TCK will be present */
671 atp->protocol_support |= (1<<(byte & 0x0f));
672 }
673 atp->y = (byte & 0xf0); /* remember incoming interface bytes */
674 atp->i++;
675 if (atp->y & 0x10) {
676 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_TA, guard_time_ms, T_GUARD);
677 break;
678 }
679 /* fall-through */
680 case ATR_S_WAIT_TA: /* see ISO/IEC 7816-3:2006 section 8.2.3 */
681 if (atp->y & 0x20) {
682 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_TB, guard_time_ms, T_GUARD);
683 break;
684 }
685 /* fall-through */
686 case ATR_S_WAIT_TB: /* see ISO/IEC 7816-3:2006 section 8.2.3 */
687 if (atp->y & 0x40) {
688 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_TC, guard_time_ms, T_GUARD);
689 break;
690 }
691 /* fall-through */
692 case ATR_S_WAIT_TC: /* see ISO/IEC 7816-3:2006 section 8.2.3 */
693 if (atp->y & 0x80) {
694 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_TD, guard_time_ms, T_GUARD);
695 break;
696 } else if (atp->hist_len) {
697 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_HIST, guard_time_ms, T_GUARD);
698 break;
699 }
700 /* fall-through */
701 case ATR_S_WAIT_HIST: /* see ISO/IEC 7816-3:2006 section 8.2.4 */
702 if (atp->hist_len)
703 atp->hist_len--;
704 if (atp->hist_len == 0) {
705 if (atp->protocol_support > 1) {
706 /* wait for check byte */
707 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_TCK,
708 guard_time_ms, T_GUARD);
709 break;
Eric Wild70d212d2019-11-27 15:05:09 +0100710 } else {
711 /* no TCK present, ATR complete; notify parent */
712 osmo_fsm_inst_state_chg(fi, ATR_S_DONE, 0, 0);
713 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_ATR_DONE_IND, atp->atr);
Harald Welte06348362019-05-19 00:45:17 +0200714 }
715 } else {
716 break;
717 }
718 /* fall-through */
719 case ATR_S_WAIT_TCK: /* see ISO/IEC 7816-3:2006 section 8.2.5 */
720 /* verify checksum if present */
721 if (fi->state == ATR_S_WAIT_TCK) {
722 uint8_t ui;
723 uint8_t *atr = msgb_data(atp->atr);
724 LOGPFSML(fi, LOGL_INFO, "Complete ATR: %s\n", msgb_hexdump(atp->atr));
725 for (ui = 1; ui < msgb_length(atp->atr)-1; ui++) {
726 atp->computed_checksum ^= atr[ui];
727 }
728 if (atp->computed_checksum != byte) {
729 /* checkum error. report to user? */
730 LOGPFSML(fi, LOGL_ERROR,
731 "computed checksum %02x doesn't match TCK=%02x\n",
732 atp->computed_checksum, byte);
733 }
734 /* ATR complete; notify parent */
735 osmo_fsm_inst_state_chg(fi, ATR_S_DONE, 0, 0);
736 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_ATR_DONE_IND, atp->atr);
737 }
738 break;
739 default:
740 OSMO_ASSERT(0);
741 }
742 break;
Harald Welte1ac9ef92019-10-09 22:20:16 +0200743 case ISO7816_E_WTIME_EXP:
744 switch (fi->state) {
745 case ATR_S_WAIT_HIST:
746 case ATR_S_WAIT_TCK:
747 /* Some cards have an ATR with long indication of historical bytes */
748 /* FIXME: should we check the checksum? */
749 osmo_fsm_inst_state_chg(fi, ATR_S_DONE, 0, 0);
750 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_ATR_DONE_IND, atp->atr);
751 break;
752 default:
753 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_ATR_ERR_IND, NULL);
754 break;
755 }
756 break;
Harald Welte06348362019-05-19 00:45:17 +0200757 default:
758 OSMO_ASSERT(0);
759 }
760}
761
762static const struct osmo_fsm_state atr_states[] = {
763 [ATR_S_WAIT_TS] = {
764 .name = "WAIT_TS",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200765 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
766 S(ISO7816_E_WTIME_EXP),
Harald Welte06348362019-05-19 00:45:17 +0200767 .out_state_mask = S(ATR_S_WAIT_TS) |
768 S(ATR_S_WAIT_T0),
769 .action = atr_wait_ts_action,
770 .onenter = atr_wait_ts_onenter,
771 },
772 [ATR_S_WAIT_T0] = {
773 .name = "WAIT_T0",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200774 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
775 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200776 .out_state_mask = S(ATR_S_WAIT_TS) |
777 S(ATR_S_WAIT_TA) |
Harald Welte06348362019-05-19 00:45:17 +0200778 S(ATR_S_WAIT_TB) |
779 S(ATR_S_WAIT_TC) |
780 S(ATR_S_WAIT_TD) |
781 S(ATR_S_WAIT_HIST) |
782 S(ATR_S_WAIT_TCK) |
783 S(ATR_S_WAIT_T0),
784 .action = atr_wait_tX_action,
785 },
786 [ATR_S_WAIT_TA] = {
787 .name = "WAIT_TA",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200788 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
789 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200790 .out_state_mask = S(ATR_S_WAIT_TS) |
791 S(ATR_S_WAIT_TB) |
Harald Welte06348362019-05-19 00:45:17 +0200792 S(ATR_S_WAIT_TC) |
793 S(ATR_S_WAIT_TD) |
794 S(ATR_S_WAIT_HIST) |
795 S(ATR_S_WAIT_TCK) |
796 S(ATR_S_WAIT_T0),
797 .action = atr_wait_tX_action,
798 },
799 [ATR_S_WAIT_TB] = {
800 .name = "WAIT_TB",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200801 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
802 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200803 .out_state_mask = S(ATR_S_WAIT_TS) |
804 S(ATR_S_WAIT_TC) |
Harald Welte06348362019-05-19 00:45:17 +0200805 S(ATR_S_WAIT_TD) |
806 S(ATR_S_WAIT_HIST) |
807 S(ATR_S_WAIT_TCK) |
808 S(ATR_S_WAIT_T0),
809 .action = atr_wait_tX_action,
810 },
811 [ATR_S_WAIT_TC] = {
812 .name = "WAIT_TC",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200813 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
814 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200815 .out_state_mask = S(ATR_S_WAIT_TS) |
816 S(ATR_S_WAIT_TD) |
Harald Welte06348362019-05-19 00:45:17 +0200817 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_TD] = {
823 .name = "WAIT_TD",
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_TA) |
Harald Welte06348362019-05-19 00:45:17 +0200828 S(ATR_S_WAIT_TB) |
829 S(ATR_S_WAIT_TC) |
830 S(ATR_S_WAIT_TD) |
831 S(ATR_S_WAIT_HIST) |
832 S(ATR_S_WAIT_TCK) |
833 S(ATR_S_WAIT_T0),
834 .action = atr_wait_tX_action,
835 },
836 [ATR_S_WAIT_HIST] = {
837 .name = "WAIT_HIST",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200838 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
839 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200840 .out_state_mask = S(ATR_S_WAIT_TS) |
841 S(ATR_S_WAIT_TCK) |
Harald Welte1ac9ef92019-10-09 22:20:16 +0200842 S(ATR_S_WAIT_T0) |
843 S(ATR_S_DONE),
Harald Welte06348362019-05-19 00:45:17 +0200844 .action = atr_wait_tX_action,
845 },
846 [ATR_S_WAIT_TCK] = {
847 .name = "WAIT_TCK",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200848 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
849 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200850 .out_state_mask = S(ATR_S_WAIT_TS) |
851 S(ATR_S_DONE),
Harald Welte06348362019-05-19 00:45:17 +0200852 .action = atr_wait_tX_action,
853 },
854 [ATR_S_DONE] = {
855 .name = "DONE",
856 .in_event_mask = 0,
Harald Welte704d99a2019-10-09 21:39:27 +0200857 .out_state_mask = S(ATR_S_WAIT_TS),
Harald Welte06348362019-05-19 00:45:17 +0200858 //.action = atr_done_action,
859 },
860
861};
862static struct osmo_fsm atr_fsm = {
863 .name = "ATR",
864 .states = atr_states,
865 .num_states = ARRAY_SIZE(atr_states),
866 .log_subsys = DATR,
867 .event_names = iso7816_3_event_names,
868};
869
870/***********************************************************************
871 * PPS FSM
872 ***********************************************************************/
Eric Wildad1edce2019-11-27 16:51:08 +0100873struct pps_fsm_priv {
874 struct msgb* tx_cmd;
875 struct msgb* rx_cmd;
876 uint8_t pps0_recv;
877};
878
879static void pps_s_wait_ppss_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
880{
881 struct pps_fsm_priv *atp = fi->priv;
882
883 if (!atp->rx_cmd)
884 atp->rx_cmd = msgb_alloc_c(fi, 6, "ATR"); /* TS + 32 chars */
885 else
886 msgb_reset(atp->rx_cmd);
887}
888
889static void pps_s_tx_pps_req_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
890{
891 struct pps_fsm_priv *atp = fi->priv;
892 atp->tx_cmd = data;
893 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
894 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
895
896 switch (event) {
897 case ISO7816_E_XCEIVE_PPS_CMD:
898 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPSS, 0, 0);
899 card_uart_tx(ip->uart, msgb_data(data), msgb_length(data), true);
900 break;
901 default:
902 OSMO_ASSERT(0);
903 }
904}
905
906static void pps_wait_pX_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
907{
908 struct pps_fsm_priv *atp = fi->priv;
909// uint32_t guard_time_ms = atr_fi_gt_ms(fi);
910 uint8_t byte;
911
912 switch (event) {
913 case ISO7816_E_RX_SINGLE:
914 byte = get_rx_byte_evt(fi->proc.parent, data);
915 LOGPFSML(fi, LOGL_DEBUG, "RX byte '%02x'\n", byte);
916 msgb_put_u8(atp->rx_cmd, byte);
917 switch (fi->state) {
918 case PPS_S_WAIT_PPSS:
919 if (byte == 0xff)
920 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPS0, 0, 0);
921 break;
922 case PPS_S_WAIT_PPS0:
923 atp->pps0_recv = byte;
924 if(atp->pps0_recv & (1 << 4)) {
925 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPS1, 0, 0);
926 break;
927 } else if (atp->pps0_recv & (1 << 5)) {
928 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPS2, 0, 0);
929 break;
930 } else if (atp->pps0_recv & (1 << 6)) {
931 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPS3, 0, 0);
932 break;
933 }
934 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PCK, 0, 0);
935 break;
936 case PPS_S_WAIT_PPS1:
937 if (atp->pps0_recv & (1 << 5)) {
938 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPS2, 0, 0);
939 break;
940 } else if (atp->pps0_recv & (1 << 6)) {
941 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPS3, 0, 0);
942 break;
943 }
944 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PCK, 0, 0);
945 break;
946 case PPS_S_WAIT_PPS2:
947 if (atp->pps0_recv & (1 << 6)) {
948 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPS3, 0, 0);
949 break;
950 }
951 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PCK, 0, 0);
952 break;
953 case PPS_S_WAIT_PPS3:
954 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PCK, 0, 0);
955 break;
956 case PPS_S_WAIT_PCK:
957 /* verify checksum if present */
958 if (fi->state == PPS_S_WAIT_PCK) {
959 uint8_t *pps_received = msgb_data(atp->rx_cmd);
960 uint8_t *pps_sent = msgb_data(atp->tx_cmd);
961
962 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_END, 0, 0);
963
964 /* pps was successful if response equals request
965 * rx buffer stays with the fsm, tx buffer gets handed back and freed
966 * by the cb */
967 if (msgb_length(atp->rx_cmd) == msgb_length(atp->tx_cmd) &&
968 !memcmp(pps_received, pps_sent, msgb_length(atp->rx_cmd))) {
969 osmo_fsm_inst_dispatch(fi->proc.parent,
970 ISO7816_E_PPS_DONE_IND, atp->tx_cmd);
971 } else {
972 osmo_fsm_inst_dispatch(fi->proc.parent,
973 ISO7816_E_PPS_FAILED_IND, atp->tx_cmd);
974 }
975 }
976 break;
977 default:
978 OSMO_ASSERT(0);
979 }
980 break;
981 case ISO7816_E_WTIME_EXP:
982 /* FIXME: timeout handling if no pps supported ? */
983 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_RX_ERR_IND, NULL);
984 break;
985 default:
986 OSMO_ASSERT(0);
987 }
988}
989
Harald Welte06348362019-05-19 00:45:17 +0200990
991static const struct osmo_fsm_state pps_states[] = {
Eric Wildad1edce2019-11-27 16:51:08 +0100992 [PPS_S_TX_PPS_REQ] = {
993 .name = "TX_PPS_REQ",
994 .in_event_mask = S(ISO7816_E_XCEIVE_PPS_CMD) |
995 S(ISO7816_E_WTIME_EXP),
996 .out_state_mask = S(PPS_S_TX_PPS_REQ) |
997 S(PPS_S_WAIT_PPSS),
998 .action = pps_s_tx_pps_req_action,
999 .onenter = pps_s_wait_ppss_onenter,
1000 },
Harald Welte06348362019-05-19 00:45:17 +02001001 [PPS_S_WAIT_PPSS] = {
1002 .name = "WAIT_PPSS",
Eric Wildad1edce2019-11-27 16:51:08 +01001003 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
1004 S(ISO7816_E_WTIME_EXP),
1005 .out_state_mask = S(PPS_S_WAIT_PPS0) |
1006 S(PPS_S_WAIT_PPSS),
1007 .action = pps_wait_pX_action,
Harald Welte06348362019-05-19 00:45:17 +02001008 },
1009 [PPS_S_WAIT_PPS0] = {
1010 .name = "WAIT_PPS0",
Eric Wildad1edce2019-11-27 16:51:08 +01001011 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
1012 S(ISO7816_E_WTIME_EXP),
1013 .out_state_mask = S(PPS_S_WAIT_PPS1) |
1014 S(PPS_S_WAIT_PPS2) |
1015 S(PPS_S_WAIT_PPS3) |
1016 S(PPS_S_WAIT_PCK),
1017 .action = pps_wait_pX_action,
Harald Welte06348362019-05-19 00:45:17 +02001018 },
1019 [PPS_S_WAIT_PPS1] = {
1020 .name = "WAIT_PPS1",
Eric Wildad1edce2019-11-27 16:51:08 +01001021 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
1022 S(ISO7816_E_WTIME_EXP),
1023 .out_state_mask = S(PPS_S_WAIT_PPS2) |
1024 S(PPS_S_WAIT_PPS3) |
1025 S(PPS_S_WAIT_PCK),
1026 .action = pps_wait_pX_action,
Harald Welte06348362019-05-19 00:45:17 +02001027 },
1028 [PPS_S_WAIT_PPS2] = {
1029 .name = "WAIT_PPS2",
Eric Wildad1edce2019-11-27 16:51:08 +01001030 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
1031 S(ISO7816_E_WTIME_EXP),
1032 .out_state_mask = S(PPS_S_WAIT_PPS3) |
1033 S(PPS_S_WAIT_PCK),
1034 .action = pps_wait_pX_action,
Harald Welte06348362019-05-19 00:45:17 +02001035 },
1036 [PPS_S_WAIT_PPS3] = {
1037 .name = "WAIT_PPS3",
Eric Wildad1edce2019-11-27 16:51:08 +01001038 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
1039 S(ISO7816_E_WTIME_EXP),
1040 .out_state_mask = S(PPS_S_WAIT_PCK),
1041 .action = pps_wait_pX_action,
Harald Welte06348362019-05-19 00:45:17 +02001042 },
1043 [PPS_S_WAIT_PCK] = {
1044 .name = "WAIT_PCK",
Eric Wildad1edce2019-11-27 16:51:08 +01001045 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
1046 S(ISO7816_E_WTIME_EXP),
1047 .out_state_mask = S(PPS_S_WAIT_END),
1048 .action = pps_wait_pX_action,
Harald Welte06348362019-05-19 00:45:17 +02001049 },
1050 [PPS_S_WAIT_END] = {
1051 .name = "WAIT_END",
Eric Wildad1edce2019-11-27 16:51:08 +01001052 .in_event_mask = 0,
1053 .out_state_mask = S(PPS_S_TX_PPS_REQ) |
1054 S(PPS_S_WAIT_PPSS),
Harald Welte06348362019-05-19 00:45:17 +02001055 },
1056};
1057
1058static struct osmo_fsm pps_fsm = {
1059 .name = "PPS",
1060 .states = pps_states,
1061 .num_states = ARRAY_SIZE(pps_states),
1062 .log_subsys = DPPS,
1063 .event_names = iso7816_3_event_names,
1064};
1065
1066/***********************************************************************
1067 * TPDU FSM
1068 ***********************************************************************/
1069
Harald Welte65087832019-10-01 09:16:49 +02001070/* In this FSM weu use the msgb for the TPDU as follows:
1071 * - 5-byte TPDU header is at msg->data
1072 * - COMMAND TPDU:
1073 * - command bytes are provided after the header at msg->l2h
1074 * - in case of incremental transmission, l3h points to next to-be-transmitted byte
1075 * - RESPONSE TPDU:
1076 * - any response bytes are stored after the header at msg->l2h
1077 */
1078
1079static inline struct osim_apdu_cmd_hdr *msgb_tpdu_hdr(struct msgb *msg) {
1080 return (struct osim_apdu_cmd_hdr *) msgb_data(msg);
1081}
1082
Harald Welte06348362019-05-19 00:45:17 +02001083struct tpdu_fsm_priv {
1084 struct msgb *tpdu;
Harald Welte65087832019-10-01 09:16:49 +02001085 bool is_command; /* is this a command TPDU (true) or a response (false) */
Harald Welte06348362019-05-19 00:45:17 +02001086};
1087
1088/* type-safe method to obtain iso7816_3_priv from fi */
1089static struct tpdu_fsm_priv *get_tpdu_fsm_priv(struct osmo_fsm_inst *fi)
1090{
1091 OSMO_ASSERT(fi);
1092 OSMO_ASSERT(fi->fsm == &tpdu_fsm);
1093 return (struct tpdu_fsm_priv *) fi->priv;
1094}
1095
1096
1097static void tpdu_s_init_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1098{
1099 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
1100 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1101 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1102 struct osim_apdu_cmd_hdr *tpduh;
1103
1104 switch (event) {
1105 case ISO7816_E_XCEIVE_TPDU_CMD:
1106 /* start transmission of a TPDU by sending the 5-byte header */
1107 tfp->tpdu = (struct msgb *)data;
1108 OSMO_ASSERT(msgb_length(tfp->tpdu) >= sizeof(*tpduh));
1109 tfp->tpdu->l2h = msgb_data(tfp->tpdu) + sizeof(*tpduh);
Harald Welte65087832019-10-01 09:16:49 +02001110 if (msgb_l2len(tfp->tpdu)) {
1111 tfp->is_command = true;
1112 tfp->tpdu->l3h = tfp->tpdu->l2h; /* next tx byte == first byte of body */
1113 } else
1114 tfp->is_command = false;
1115 tpduh = msgb_tpdu_hdr(tfp->tpdu);
1116 LOGPFSML(fi, LOGL_DEBUG, "Transmitting %s TPDU header %s via UART\n",
1117 tfp->is_command ? "COMMAND" : "RESPONSE",
Harald Welte06348362019-05-19 00:45:17 +02001118 osmo_hexdump_nospc((uint8_t *) tpduh, sizeof(*tpduh)));
1119 osmo_fsm_inst_state_chg(fi, TPDU_S_TX_HDR, 0, 0);
Harald Welte6603d952019-10-09 20:50:13 +02001120 card_uart_tx(ip->uart, (uint8_t *) tpduh, sizeof(*tpduh), true);
Harald Welte06348362019-05-19 00:45:17 +02001121 break;
1122 default:
1123 OSMO_ASSERT(0);
1124 }
1125}
1126
1127static void tpdu_s_tx_hdr_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1128{
1129 OSMO_ASSERT(fi->fsm == &tpdu_fsm);
1130 switch (event) {
1131 case ISO7816_E_TX_COMPL:
1132 /* Rx of single byte is already enabled by previous card_uart_tx() call */
1133 osmo_fsm_inst_state_chg(fi, TPDU_S_PROCEDURE, 0, 0);
1134 break;
1135 default:
1136 OSMO_ASSERT(0);
1137 }
1138}
1139
1140
1141
1142static void tpdu_s_procedure_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1143{
1144 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
Harald Welte65087832019-10-01 09:16:49 +02001145 struct osim_apdu_cmd_hdr *tpduh = msgb_tpdu_hdr(tfp->tpdu);
Harald Welte06348362019-05-19 00:45:17 +02001146 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1147 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1148 uint8_t byte;
1149
1150 switch (event) {
1151 case ISO7816_E_RX_SINGLE:
1152 byte = get_rx_byte_evt(fi->proc.parent, data);
1153 LOGPFSML(fi, LOGL_DEBUG, "Received 0x%02x from UART\n", byte);
1154 if (byte == 0x60) {
1155 /* NULL: wait for another procedure byte */
1156 osmo_fsm_inst_state_chg(fi, TPDU_S_PROCEDURE, 0, 0);
1157 } else if ((byte >= 0x60 && byte <= 0x6f) || (byte >= 0x90 && byte <= 0x9f)) {
1158 //msgb_apdu_sw(tfp->apdu) = byte << 8;
1159 msgb_put(tfp->tpdu, byte);
1160 /* receive second SW byte (SW2) */
1161 osmo_fsm_inst_state_chg(fi, TPDU_S_SW2, 0, 0);
1162 break;
1163 } else if (byte == tpduh->ins) {
Harald Welte65087832019-10-01 09:16:49 +02001164 if (tfp->is_command) {
Harald Welte06348362019-05-19 00:45:17 +02001165 /* transmit all remaining bytes */
Harald Welte6603d952019-10-09 20:50:13 +02001166 card_uart_tx(ip->uart, msgb_l2(tfp->tpdu), msgb_l2len(tfp->tpdu), true);
Harald Welte06348362019-05-19 00:45:17 +02001167 osmo_fsm_inst_state_chg(fi, TPDU_S_TX_REMAINING, 0, 0);
1168 } else {
1169 card_uart_set_rx_threshold(ip->uart, tpduh->p3);
1170 osmo_fsm_inst_state_chg(fi, TPDU_S_RX_REMAINING, 0, 0);
1171 }
1172 } else if (byte == (tpduh->ins ^ 0xFF)) {
Harald Welte65087832019-10-01 09:16:49 +02001173 /* transmit/recieve single byte then wait for proc */
1174 if (tfp->is_command) {
1175 /* transmit *next*, not first byte */
1176 OSMO_ASSERT(msgb_l3len(tfp->tpdu) >= 0);
Harald Welte6603d952019-10-09 20:50:13 +02001177 card_uart_tx(ip->uart, msgb_l3(tfp->tpdu), 1, false);
Harald Welte65087832019-10-01 09:16:49 +02001178 osmo_fsm_inst_state_chg(fi, TPDU_S_TX_SINGLE, 0, 0);
1179 } else {
1180 osmo_fsm_inst_state_chg(fi, TPDU_S_RX_SINGLE, 0, 0);
1181 }
Harald Welte06348362019-05-19 00:45:17 +02001182 } else
1183 OSMO_ASSERT(0);
1184 break;
1185 default:
1186 OSMO_ASSERT(0);
1187 }
1188}
1189
1190/* UART is transmitting remaining data; we wait for ISO7816_E_TX_COMPL */
1191static void tpdu_s_tx_remaining_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1192{
1193 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1194 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1195
1196 switch (event) {
1197 case ISO7816_E_TX_COMPL:
1198 card_uart_set_rx_threshold(ip->uart, 1);
1199 osmo_fsm_inst_state_chg(fi, TPDU_S_SW1, 0, 0);
1200 break;
1201 default:
1202 OSMO_ASSERT(0);
1203 }
1204}
1205
1206/* UART is transmitting single byte of data; we wait for ISO7816_E_TX_COMPL */
1207static void tpdu_s_tx_single_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1208{
Harald Welte65087832019-10-01 09:16:49 +02001209 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
1210
Harald Welte06348362019-05-19 00:45:17 +02001211 switch (event) {
1212 case ISO7816_E_TX_COMPL:
Harald Welte65087832019-10-01 09:16:49 +02001213 tfp->tpdu->l3h += 1;
1214 if (msgb_l3len(tfp->tpdu))
1215 osmo_fsm_inst_state_chg(fi, TPDU_S_PROCEDURE, 0, 0);
1216 else
1217 osmo_fsm_inst_state_chg(fi, TPDU_S_SW1, 0, 0);
Harald Welte06348362019-05-19 00:45:17 +02001218 break;
1219 default:
1220 OSMO_ASSERT(0);
1221 }
1222}
1223
1224/* UART is receiving remaining data; we wait for ISO7816_E_RX_COMPL */
1225static void tpdu_s_rx_remaining_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1226{
1227 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
Harald Welte65087832019-10-01 09:16:49 +02001228 struct osim_apdu_cmd_hdr *tpduh = msgb_tpdu_hdr(tfp->tpdu);
Harald Welte06348362019-05-19 00:45:17 +02001229 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1230 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1231 int rc;
1232
1233 switch (event) {
1234 case ISO7816_E_RX_COMPL:
1235 /* retrieve pending byte(s) */
1236 rc = card_uart_rx(ip->uart, msgb_l2(tfp->tpdu), tpduh->p3);
Harald Welte65087832019-10-01 09:16:49 +02001237 OSMO_ASSERT(rc > 0);
1238 msgb_put(tfp->tpdu, rc);
1239 if (msgb_l2len(tfp->tpdu) != tpduh->p3) {
1240 LOGPFSML(fi, LOGL_ERROR, "expected %u bytes; read %d\n", tpduh->p3,
1241 msgb_l2len(tfp->tpdu));
1242 }
Harald Welte06348362019-05-19 00:45:17 +02001243 card_uart_set_rx_threshold(ip->uart, 1);
1244 osmo_fsm_inst_state_chg(fi, TPDU_S_SW1, 0, 0);
1245 break;
1246 default:
1247 OSMO_ASSERT(0);
1248 }
1249}
1250
1251/* UART is receiving single byte of data; we wait for ISO7816_E_RX_SINGLE */
1252static void tpdu_s_rx_single_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1253{
1254 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
Harald Welte65087832019-10-01 09:16:49 +02001255 struct osim_apdu_cmd_hdr *tpduh = msgb_tpdu_hdr(tfp->tpdu);
Harald Welte06348362019-05-19 00:45:17 +02001256 uint8_t byte;
1257
1258 switch (event) {
1259 case ISO7816_E_RX_SINGLE:
1260 byte = get_rx_byte_evt(fi->proc.parent, data);
1261 LOGPFSML(fi, LOGL_DEBUG, "Received 0x%02x from UART\n", byte);
Harald Welte65087832019-10-01 09:16:49 +02001262 msgb_put_u8(tfp->tpdu, byte);
1263 /* determine if number of expected bytes received */
1264 if (msgb_l2len(tfp->tpdu) == tpduh->p3)
Harald Welte06348362019-05-19 00:45:17 +02001265 osmo_fsm_inst_state_chg(fi, TPDU_S_SW1, 0, 0);
Harald Welte65087832019-10-01 09:16:49 +02001266 else
Harald Welte06348362019-05-19 00:45:17 +02001267 osmo_fsm_inst_state_chg(fi, TPDU_S_PROCEDURE, 0, 0);
1268 break;
1269 default:
1270 OSMO_ASSERT(0);
1271 }
1272}
1273
1274static void tpdu_s_sw1_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1275{
1276 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
1277 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1278 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1279 uint8_t byte;
1280
1281 switch (event) {
1282 case ISO7816_E_RX_SINGLE:
1283 byte = get_rx_byte_evt(fi->proc.parent, data);
1284 LOGPFSML(fi, LOGL_DEBUG, "Received 0x%02x from UART\n", byte);
1285 /* record byte */
1286 //msgb_apdu_sw(tfp->apdu) = byte << 8;
1287 msgb_put_u8(tfp->tpdu, byte);
1288 card_uart_set_rx_threshold(ip->uart, 1);
1289 osmo_fsm_inst_state_chg(fi, TPDU_S_SW2, 0, 0);
1290 break;
1291 default:
1292 OSMO_ASSERT(0);
1293 }
1294}
1295
1296static void tpdu_s_sw2_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1297{
1298 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
1299 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1300 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1301 uint8_t byte;
1302
1303 switch (event) {
1304 case ISO7816_E_RX_SINGLE:
1305 byte = get_rx_byte_evt(fi->proc.parent, data);
1306 LOGPFSML(fi, LOGL_DEBUG, "Received 0x%02x from UART\n", byte);
1307 /* record SW2 byte */
1308 //msgb_apdu_sw(tfp->apdu) &= 0xFF00;
1309 //msgb_apdu_sw(tfp->apdu) |= byte;
1310 msgb_put_u8(tfp->tpdu, byte);
1311 osmo_fsm_inst_state_chg(fi, TPDU_S_DONE, 0, 0);
1312 /* Notify parent FSM */
1313 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_TPDU_DONE_IND, tfp->tpdu);
1314 break;
1315 default:
1316 OSMO_ASSERT(0);
1317 }
1318}
1319
1320static void tpdu_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1321{
1322 OSMO_ASSERT(fi->fsm == &tpdu_fsm);
1323
1324 switch (event) {
1325 case ISO7816_E_RX_ERR_IND:
1326 case ISO7816_E_TX_ERR_IND:
1327 /* FIXME: handle this in some different way */
1328 osmo_fsm_inst_state_chg(fi, TPDU_S_DONE, 0, 0);
1329 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_TPDU_DONE_IND, NULL);
1330 break;
1331 case ISO7816_E_TPDU_CLEAR_REQ:
1332 osmo_fsm_inst_state_chg(fi, TPDU_S_INIT, 0, 0);
1333 break;
1334 }
1335}
1336
1337static const struct osmo_fsm_state tpdu_states[] = {
1338 [TPDU_S_INIT] = {
1339 .name = "INIT",
1340 .in_event_mask = S(ISO7816_E_XCEIVE_TPDU_CMD) |
1341 S(ISO7816_E_TX_COMPL),
1342 .out_state_mask = S(TPDU_S_INIT) |
1343 S(TPDU_S_TX_HDR),
1344 .action = tpdu_s_init_action,
1345 },
1346 [TPDU_S_TX_HDR] = {
1347 .name = "TX_HDR",
1348 .in_event_mask = S(ISO7816_E_TX_COMPL),
1349 .out_state_mask = S(TPDU_S_INIT) |
1350 S(TPDU_S_PROCEDURE),
1351 .action = tpdu_s_tx_hdr_action,
1352 },
1353 [TPDU_S_PROCEDURE] = {
1354 .name = "PROCEDURE",
1355 .in_event_mask = S(ISO7816_E_RX_SINGLE),
1356 .out_state_mask = S(TPDU_S_INIT) |
1357 S(TPDU_S_PROCEDURE) |
1358 S(TPDU_S_RX_REMAINING) |
1359 S(TPDU_S_RX_SINGLE) |
1360 S(TPDU_S_TX_REMAINING) |
1361 S(TPDU_S_TX_SINGLE) |
1362 S(TPDU_S_SW2),
1363 .action = tpdu_s_procedure_action,
1364 },
1365 [TPDU_S_TX_REMAINING] = {
1366 .name = "TX_REMAINING",
1367 .in_event_mask = S(ISO7816_E_TX_COMPL),
1368 .out_state_mask = S(TPDU_S_INIT) |
1369 S(TPDU_S_SW1),
1370 .action = tpdu_s_tx_remaining_action,
1371 },
1372 [TPDU_S_TX_SINGLE] = {
1373 .name = "TX_SINGLE",
1374 .in_event_mask = S(ISO7816_E_TX_COMPL),
1375 .out_state_mask = S(TPDU_S_INIT) |
1376 S(TPDU_S_PROCEDURE),
1377 .action = tpdu_s_tx_single_action,
1378 },
1379 [TPDU_S_RX_REMAINING] = {
1380 .name = "RX_REMAINING",
1381 .in_event_mask = S(ISO7816_E_RX_COMPL),
1382 .out_state_mask = S(TPDU_S_INIT) |
1383 S(TPDU_S_SW1),
1384 .action = tpdu_s_rx_remaining_action,
1385 },
1386 [TPDU_S_RX_SINGLE] = {
1387 .name = "RX_SINGLE",
1388 .in_event_mask = S(ISO7816_E_RX_SINGLE),
1389 .out_state_mask = S(TPDU_S_INIT) |
1390 S(TPDU_S_PROCEDURE),
1391 .action = tpdu_s_rx_single_action,
1392 },
1393 [TPDU_S_SW1] = {
1394 .name = "SW1",
1395 .in_event_mask = S(ISO7816_E_RX_SINGLE),
1396 .out_state_mask = S(TPDU_S_INIT) |
1397 S(TPDU_S_SW2),
1398 .action = tpdu_s_sw1_action,
1399 },
1400 [TPDU_S_SW2] = {
1401 .name = "SW2",
1402 .in_event_mask = S(ISO7816_E_RX_SINGLE),
1403 .out_state_mask = S(TPDU_S_INIT) |
1404 S(TPDU_S_DONE),
1405 .action = tpdu_s_sw2_action,
1406 },
1407 [TPDU_S_DONE] = {
1408 .name = "DONE",
1409 .in_event_mask = 0,
1410 .out_state_mask = S(TPDU_S_INIT),
1411 .action = NULL,
1412 },
1413};
1414static struct osmo_fsm tpdu_fsm = {
1415 .name = "TPDU",
1416 .states = tpdu_states,
1417 .num_states = ARRAY_SIZE(tpdu_states),
1418 .allstate_event_mask = S(ISO7816_E_RX_ERR_IND) |
1419 S(ISO7816_E_TX_ERR_IND) |
1420 S(ISO7816_E_TPDU_CLEAR_REQ),
1421 .allstate_action = tpdu_allstate_action,
1422 .log_subsys = DTPDU,
1423 .event_names = iso7816_3_event_names,
1424};
1425
1426struct osmo_fsm_inst *iso7816_fsm_alloc(void *ctx, int log_level, const char *id,
1427 struct card_uart *cuart, iso7816_user_cb user_cb,
1428 void *user_priv)
1429{
1430 struct iso7816_3_priv *ip;
1431 struct osmo_fsm_inst *fi;
1432
1433 fi = osmo_fsm_inst_alloc(&iso7816_3_fsm, ctx, NULL, log_level, id);
1434 ip = talloc_zero(fi, struct iso7816_3_priv);
1435 if (!ip)
1436 goto out_fi;
1437 fi->priv = ip;
1438
1439 ip->uart = cuart;
1440 cuart->priv = fi;
1441 cuart->handle_event = tpdu_uart_notification;
1442
1443 ip->user_cb = user_cb;
1444 ip->user_priv = user_priv;
1445
1446 ip->atr_fi = osmo_fsm_inst_alloc_child(&atr_fsm, fi, ISO7816_E_SW_ERR_IND);
1447 if (!ip->atr_fi)
1448 goto out_fi;
1449 ip->atr_fi->priv = talloc_zero(ip->atr_fi, struct atr_fsm_priv);
1450 if (!ip->atr_fi->priv)
1451 goto out_atr;
1452
1453 ip->tpdu_fi = osmo_fsm_inst_alloc_child(&tpdu_fsm, fi, ISO7816_E_SW_ERR_IND);
1454 if (!ip->tpdu_fi)
1455 goto out_atr;
1456 ip->tpdu_fi->priv = talloc_zero(ip->tpdu_fi, struct tpdu_fsm_priv);
1457 if (!ip->tpdu_fi->priv)
1458 goto out_tpdu;
1459
Eric Wildad1edce2019-11-27 16:51:08 +01001460#if 1
Harald Welte06348362019-05-19 00:45:17 +02001461 ip->pps_fi = osmo_fsm_inst_alloc_child(&pps_fsm, fi, ISO7816_E_SW_ERR_IND);
1462 if (!ip->pps_fi)
1463 goto out_tpdu;
1464 ip->pps_fi->priv = talloc_zero(ip->pps_fi, struct pps_fsm_priv);
1465 if (!ip->pps_fi->priv)
1466 goto out_pps;
1467#endif
1468
1469 /* This ensures the 'onenter' function of the initial state is called */
1470 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
1471
1472 return fi;
1473
Eric Wildad1edce2019-11-27 16:51:08 +01001474#if 1
Harald Welte06348362019-05-19 00:45:17 +02001475out_pps:
1476 osmo_fsm_inst_free(ip->pps_fi);
1477#endif
1478out_tpdu:
1479 osmo_fsm_inst_free(ip->tpdu_fi);
1480out_atr:
1481 osmo_fsm_inst_free(ip->atr_fi);
1482out_fi:
1483 osmo_fsm_inst_free(fi);
1484 cuart->priv = NULL;
1485 return NULL;
1486}
1487
1488void *iso7816_fsm_get_user_priv(struct osmo_fsm_inst *fi)
1489{
1490 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
1491 return ip->user_priv;
1492}
1493
1494
1495static __attribute__((constructor)) void on_dso_load_iso7816(void)
1496{
1497 osmo_fsm_register(&iso7816_3_fsm);
1498 osmo_fsm_register(&atr_fsm);
1499 osmo_fsm_register(&tpdu_fsm);
1500 osmo_fsm_register(&pps_fsm);
1501}