blob: 21378e0e6eaeb78f63ae8f96f52a0d0c468310a2 [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 {
72 PPS_S_WAIT_PPSS, /*!< initial byte */
73 PPS_S_WAIT_PPS0, /*!< format byte */
74 PPS_S_WAIT_PPS1, /*!< first parameter byte */
75 PPS_S_WAIT_PPS2, /*!< second parameter byte */
76 PPS_S_WAIT_PPS3, /*!< third parameter byte */
77 PPS_S_WAIT_PCK, /*!< check byte */
78 PPS_S_WAIT_END, /*!< all done */
79 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
222 /* go back to initial state in child FSMs */
223 osmo_fsm_inst_state_chg(ip->atr_fi, ATR_S_WAIT_TS, 0, 0);
224 //osmo_fsm_inst_state_chg(ip->pps_fi, PPS_S_WAIT_PPSS, 0, 0);
225 osmo_fsm_inst_state_chg(ip->tpdu_fi, TPDU_S_INIT, 0, 0);
226}
227
228static void iso7816_3_reset_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
229{
230 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
231 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
232
233 switch (event) {
234 case ISO7816_E_RESET_REL_IND:
235 /* TOOD: this should happen before reset is released */
236 card_uart_ctrl(ip->uart, CUART_CTL_RX, true);
237 osmo_fsm_inst_state_chg_ms(fi, ISO7816_S_WAIT_ATR,
238 fi_cycles2ms(fi, 40000), T_WAIT_ATR);
239 break;
240 default:
241 OSMO_ASSERT(0);
242 }
243}
244
245static void iso7816_3_wait_atr_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
246{
247 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
248 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
249
250 switch (event) {
251 case ISO7816_E_RX_SINGLE:
252 osmo_fsm_inst_state_chg(fi, ISO7816_S_IN_ATR, 0, 0);
253 osmo_fsm_inst_dispatch(ip->atr_fi, event, data);
254 break;
Harald Welte1ac9ef92019-10-09 22:20:16 +0200255 case ISO7816_E_WTIME_EXP:
256 ip->user_cb(fi, event, 0, NULL);
257 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
258 break;
Harald Welte06348362019-05-19 00:45:17 +0200259 default:
260 OSMO_ASSERT(0);
261 }
262}
263
264static void iso7816_3_in_atr_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
265{
266 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
267 struct msgb *atr;
268 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
269
270 switch (event) {
271 case ISO7816_E_RX_SINGLE:
272 case ISO7816_E_RX_ERR_IND:
Harald Welte1ac9ef92019-10-09 22:20:16 +0200273 case ISO7816_E_WTIME_EXP:
Harald Welte06348362019-05-19 00:45:17 +0200274 /* simply pass this through to the child FSM for the ATR */
275 osmo_fsm_inst_dispatch(ip->atr_fi, event, data);
276 break;
277 case ISO7816_E_ATR_DONE_IND:
278 atr = data;
279 /* FIXME: verify ATR result: success / failure */
280 osmo_fsm_inst_state_chg(fi, ISO7816_S_WAIT_TPDU, 0, 0);
281 /* notify user about ATR */
282 ip->user_cb(fi, event, 0, atr);
283 break;
Harald Welte1ac9ef92019-10-09 22:20:16 +0200284 case ISO7816_E_ATR_ERR_IND:
285 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
286 ip->user_cb(fi, event, 0, atr);
287 break;
Harald Welte06348362019-05-19 00:45:17 +0200288 default:
289 OSMO_ASSERT(0);
290 }
291}
292
293static void iso7816_3_wait_tpdu_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
294{
295 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
296 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
Harald Weltebe86f852019-10-09 22:25:48 +0200297 card_uart_ctrl(ip->uart, CUART_CTL_RX, false);
Harald Welte06348362019-05-19 00:45:17 +0200298 /* reset the TPDU state machine */
299 osmo_fsm_inst_dispatch(ip->tpdu_fi, ISO7816_E_TPDU_CLEAR_REQ, NULL);
300}
301
302static void iso7816_3_wait_tpdu_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
303{
304 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
305 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
306
307 switch (event) {
308 case ISO7816_E_XCEIVE_TPDU_CMD:
309 /* "data" contains a msgb-wrapped TPDU */
310 osmo_fsm_inst_state_chg(fi, ISO7816_S_IN_TPDU, 0, 0);
311 /* pass on to sub-fsm */
312 osmo_fsm_inst_dispatch(ip->tpdu_fi, event, data);
313 break;
314 default:
315 OSMO_ASSERT(0);
316 }
317}
318
319static void iso7816_3_in_tpdu_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
320{
321 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
322 struct msgb *apdu;
323 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
324
325 switch (event) {
326 case ISO7816_E_RX_SINGLE:
327 case ISO7816_E_RX_COMPL:
328 case ISO7816_E_RX_ERR_IND:
329 case ISO7816_E_TX_COMPL:
330 case ISO7816_E_TX_ERR_IND:
331 /* simply pass this through to the child FSM for the ATR */
332 osmo_fsm_inst_dispatch(ip->tpdu_fi, event, data);
333 break;
334 case ISO7816_E_TPDU_DONE_IND:
335 apdu = data;
336 osmo_fsm_inst_state_chg(fi, ISO7816_S_WAIT_TPDU, 0, 0);
337 /* hand finished TPDU to user */
338 ip->user_cb(fi, event, 0, apdu);
339 break;
Harald Welte1ac9ef92019-10-09 22:20:16 +0200340 case ISO7816_E_WTIME_EXP:
341 /* FIXME: power off? */
342 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
343 break;
Harald Welte06348362019-05-19 00:45:17 +0200344 default:
345 OSMO_ASSERT(0);
346 }
347}
348
349static void iso7816_3_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
350{
351 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
352
353 switch (event) {
Harald Welte06348362019-05-19 00:45:17 +0200354 case ISO7816_E_HW_ERR_IND:
355 case ISO7816_E_CARD_REMOVAL:
356 /* FIXME: power off? */
357 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
358 break;
359 case ISO7816_E_POWER_DN_IND:
360 case ISO7816_E_RESET_ACT_IND:
361 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
362 break;
363 case ISO7816_E_ABORT_REQ:
364 /* FIXME */
365 break;
366 default:
367 OSMO_ASSERT(0);
368 break;
369 }
370}
371
372static const struct osmo_fsm_state iso7816_3_states[] = {
373 [ISO7816_S_RESET] = {
374 .name = "RESET",
375 .in_event_mask = S(ISO7816_E_RESET_REL_IND),
376 .out_state_mask = S(ISO7816_S_WAIT_ATR) |
377 S(ISO7816_S_RESET),
378 .action = iso7816_3_reset_action,
379 .onenter = iso7816_3_reset_onenter,
380 },
381 [ISO7816_S_WAIT_ATR] = {
382 .name = "WAIT_ATR",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200383 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
384 S(ISO7816_E_WTIME_EXP),
Harald Welte06348362019-05-19 00:45:17 +0200385 .out_state_mask = S(ISO7816_S_RESET) |
386 S(ISO7816_S_IN_ATR),
387 .action = iso7816_3_wait_atr_action,
388 },
389 [ISO7816_S_IN_ATR] = {
390 .name = "IN_ATR",
391 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
392 S(ISO7816_E_RX_ERR_IND) |
Harald Welte1ac9ef92019-10-09 22:20:16 +0200393 S(ISO7816_E_ATR_DONE_IND) |
394 S(ISO7816_E_ATR_ERR_IND) |
395 S(ISO7816_E_WTIME_EXP),
Harald Welte06348362019-05-19 00:45:17 +0200396 .out_state_mask = S(ISO7816_S_RESET) |
397 S(ISO7816_S_IN_ATR) |
398 S(ISO7816_S_WAIT_TPDU),
399 .action = iso7816_3_in_atr_action,
400 },
401 [ISO7816_S_WAIT_TPDU] = {
402 .name = "WAIT_TPDU",
403 .in_event_mask = S(ISO7816_E_XCEIVE_TPDU_CMD),
404 .out_state_mask = S(ISO7816_S_RESET) |
405 S(ISO7816_S_WAIT_TPDU) |
406 S(ISO7816_S_IN_TPDU) |
407 S(ISO7816_S_IN_PPS_REQ),
408 .action = iso7816_3_wait_tpdu_action,
409 .onenter = iso7816_3_wait_tpdu_onenter,
410 },
411 [ISO7816_S_IN_TPDU] = {
412 .name = "IN_TPDU",
413 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
414 S(ISO7816_E_RX_COMPL) |
415 S(ISO7816_E_TX_COMPL) |
416 S(ISO7816_E_RX_ERR_IND) |
417 S(ISO7816_E_TX_ERR_IND) |
Harald Welte1ac9ef92019-10-09 22:20:16 +0200418 S(ISO7816_E_TPDU_DONE_IND) |
419 S(ISO7816_E_WTIME_EXP),
Harald Welte06348362019-05-19 00:45:17 +0200420 .out_state_mask = S(ISO7816_S_RESET) |
421 S(ISO7816_S_WAIT_TPDU) |
422 S(ISO7816_S_IN_TPDU),
423 .action = iso7816_3_in_tpdu_action,
424 },
425 [ISO7816_S_IN_PPS_REQ] = {
426 .name = "IN_PPS_REQ",
427 .in_event_mask = 0, /* FIXME */
428 .out_state_mask = S(ISO7816_S_RESET) |
429 S(ISO7816_S_WAIT_TPDU) |
430 S(ISO7816_S_IN_PPS_REQ) |
431 S(ISO7816_S_WAIT_PPS_RSP),
432 },
433 [ISO7816_S_WAIT_PPS_RSP] = {
434 .name = "WAIT_PPS_RESP",
435 .in_event_mask = 0, /* FIXME */
436 .out_state_mask = S(ISO7816_S_RESET) |
437 S(ISO7816_S_WAIT_TPDU) |
438 S(ISO7816_S_WAIT_PPS_RSP) |
439 S(ISO7816_S_IN_PPS_RSP),
440 },
441 [ISO7816_S_IN_PPS_RSP] = {
442 .name = "IN_PPS_RESP",
443 .in_event_mask = 0, /* FIXME */
444 .out_state_mask = S(ISO7816_S_RESET) |
445 S(ISO7816_S_WAIT_TPDU) |
446 S(ISO7816_S_IN_PPS_RSP),
447 },
448};
449static struct osmo_fsm iso7816_3_fsm = {
450 .name = "ISO7816-3",
451 .states = iso7816_3_states,
452 .num_states = ARRAY_SIZE(iso7816_3_states),
453 .log_subsys = DISO7816,
454 .event_names = iso7816_3_event_names,
455 .allstate_action = iso7816_3_allstate_action,
Harald Welte1ac9ef92019-10-09 22:20:16 +0200456 .allstate_event_mask = S(ISO7816_E_CARD_REMOVAL) |
Harald Welte06348362019-05-19 00:45:17 +0200457 S(ISO7816_E_POWER_DN_IND) |
458 S(ISO7816_E_RESET_ACT_IND) |
459 S(ISO7816_E_HW_ERR_IND) |
460 S(ISO7816_E_ABORT_REQ),
461};
462
463/***********************************************************************
464 * ATR FSM
465 ***********************************************************************/
466
467struct atr_fsm_priv {
468 uint8_t hist_len; /*!< store the number of expected historical bytes */
469 uint8_t y; /*!< last mask of the upcoming TA, TB, TC, TD interface bytes */
470 uint8_t i; /*!< interface byte subgroup number */
471 struct msgb *atr; /*!< ATR data */
472 uint8_t computed_checksum;
473 uint16_t protocol_support;
474};
475
476/* obtain the [software] guard time in milli-seconds from the atr fsm_inst */
477static uint32_t atr_fi_gt_ms(struct osmo_fsm_inst *fi)
478{
479 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
480 struct iso7816_3_priv *ip;
481
482 OSMO_ASSERT(fi->fsm == &atr_fsm);
483 OSMO_ASSERT(parent_fi);
484 ip = get_iso7816_3_priv(parent_fi);
485
486 return ip->guard_time_ms;
487}
488
489/* obtain the 'byte' parmeter of an ISO7816_E_RX event */
490static uint8_t get_rx_byte_evt(struct osmo_fsm_inst *fi, void *data)
491{
492 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
493 uint8_t byte = *(uint8_t *)data;
494
495 /* apply inverse convention */
496 if (ip->convention_convert)
497 byte = convention_convert_lut[byte];
498
499 return byte;
500}
501
502/* append a single byte to the ATR */
503static int atr_append_byte(struct osmo_fsm_inst *fi, uint8_t byte)
504{
505 struct atr_fsm_priv *atp = fi->priv;
506
507 if (!msgb_tailroom(atp->atr)) {
508 LOGPFSML(fi, LOGL_ERROR, "ATR overflow !?!");
509 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_SW_ERR_IND, NULL);
510 return -1;
511 }
512 msgb_put_u8(atp->atr, byte);
513 return 0;
514}
515
516static void atr_wait_ts_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
517{
518 struct atr_fsm_priv *atp = fi->priv;
519
520 /* reset state to its initial value */
521 atp->hist_len = 0;
522 atp->y = 0;
523 atp->i = 0;
524 if (!atp->atr)
525 atp->atr = msgb_alloc_c(fi, 33, "ATR"); /* TS + 32 chars */
526 else
527 msgb_reset(atp->atr);
528 atp->computed_checksum = 0;
529 atp->protocol_support = 0;
530}
531
532static void atr_wait_ts_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
533{
534 struct atr_fsm_priv *atp = fi->priv;
535 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
536 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
537 uint8_t byte;
538
539 switch (event) {
540 case ISO7816_E_RX_SINGLE:
541 OSMO_ASSERT(msgb_length(atp->atr) == 0);
542restart:
543 byte = get_rx_byte_evt(parent_fi, data);
544 LOGPFSML(fi, LOGL_DEBUG, "RX byte '%02x'\n", byte);
545 switch (byte) {
546 case 0x23:
547 /* direct convention used, but decoded using inverse
548 * convention (a parity error should also have occurred) */
549 /* fall-through */
550 case 0x30:
551 /* inverse convention used, but decoded using direct
552 * convention (a parity error should also have occurred) */
553 ip->convention_convert = !ip->convention_convert;
554 goto restart;
555 break;
556 case 0x3b: /* direct convention used and correctly decoded */
557 /* fall-through */
558 case 0x3f: /* inverse convention used and correctly decoded */
559 atr_append_byte(fi, byte);
560 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_T0, atr_fi_gt_ms(fi), T_GUARD);
561 break;
562 default:
563 LOGPFSML(fi, LOGL_ERROR, "Invalid TS received: 0x%02X\n", byte);
564 /* FIXME: somehow indiicate to user */
565 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_SW_ERR_IND, NULL);
566 break;
567 }
568 atp->i = 0; /* first interface byte sub-group is coming (T0 is kind of TD0) */
569 break;
Harald Welte1ac9ef92019-10-09 22:20:16 +0200570 case ISO7816_E_WTIME_EXP:
571 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_ATR_ERR_IND, NULL);
572 break;
Harald Welte06348362019-05-19 00:45:17 +0200573 default:
574 OSMO_ASSERT(0);
575 }
576}
577
578static void atr_wait_tX_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
579{
580 struct atr_fsm_priv *atp = fi->priv;
581 uint32_t guard_time_ms = atr_fi_gt_ms(fi);
582 uint8_t byte;
583
584 switch (event) {
585 case ISO7816_E_RX_SINGLE:
586 byte = get_rx_byte_evt(fi->proc.parent, data);
587 LOGPFSML(fi, LOGL_DEBUG, "RX byte '%02x'\n", byte);
588 atr_append_byte(fi, byte);
589 switch (fi->state) {
590 case ATR_S_WAIT_T0: /* see ISO/IEC 7816-3:2006 section 8.2.2 */
591 case ATR_S_WAIT_TD: /* see ISO/IEC 7816-3:2006 section 8.2.3 */
592 if (fi->state == ATR_S_WAIT_T0) {
593 /* save number of hist. bytes */
594 atp->hist_len = (byte & 0x0f);
595 } else {
596 /* remember supported protocol to know if TCK will be present */
597 atp->protocol_support |= (1<<(byte & 0x0f));
598 }
599 atp->y = (byte & 0xf0); /* remember incoming interface bytes */
600 atp->i++;
601 if (atp->y & 0x10) {
602 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_TA, guard_time_ms, T_GUARD);
603 break;
604 }
605 /* fall-through */
606 case ATR_S_WAIT_TA: /* see ISO/IEC 7816-3:2006 section 8.2.3 */
607 if (atp->y & 0x20) {
608 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_TB, guard_time_ms, T_GUARD);
609 break;
610 }
611 /* fall-through */
612 case ATR_S_WAIT_TB: /* see ISO/IEC 7816-3:2006 section 8.2.3 */
613 if (atp->y & 0x40) {
614 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_TC, guard_time_ms, T_GUARD);
615 break;
616 }
617 /* fall-through */
618 case ATR_S_WAIT_TC: /* see ISO/IEC 7816-3:2006 section 8.2.3 */
619 if (atp->y & 0x80) {
620 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_TD, guard_time_ms, T_GUARD);
621 break;
622 } else if (atp->hist_len) {
623 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_HIST, guard_time_ms, T_GUARD);
624 break;
625 }
626 /* fall-through */
627 case ATR_S_WAIT_HIST: /* see ISO/IEC 7816-3:2006 section 8.2.4 */
628 if (atp->hist_len)
629 atp->hist_len--;
630 if (atp->hist_len == 0) {
631 if (atp->protocol_support > 1) {
632 /* wait for check byte */
633 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_TCK,
634 guard_time_ms, T_GUARD);
635 break;
636 }
637 } else {
638 break;
639 }
640 /* fall-through */
641 case ATR_S_WAIT_TCK: /* see ISO/IEC 7816-3:2006 section 8.2.5 */
642 /* verify checksum if present */
643 if (fi->state == ATR_S_WAIT_TCK) {
644 uint8_t ui;
645 uint8_t *atr = msgb_data(atp->atr);
646 LOGPFSML(fi, LOGL_INFO, "Complete ATR: %s\n", msgb_hexdump(atp->atr));
647 for (ui = 1; ui < msgb_length(atp->atr)-1; ui++) {
648 atp->computed_checksum ^= atr[ui];
649 }
650 if (atp->computed_checksum != byte) {
651 /* checkum error. report to user? */
652 LOGPFSML(fi, LOGL_ERROR,
653 "computed checksum %02x doesn't match TCK=%02x\n",
654 atp->computed_checksum, byte);
655 }
656 /* ATR complete; notify parent */
657 osmo_fsm_inst_state_chg(fi, ATR_S_DONE, 0, 0);
658 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_ATR_DONE_IND, atp->atr);
659 }
660 break;
661 default:
662 OSMO_ASSERT(0);
663 }
664 break;
Harald Welte1ac9ef92019-10-09 22:20:16 +0200665 case ISO7816_E_WTIME_EXP:
666 switch (fi->state) {
667 case ATR_S_WAIT_HIST:
668 case ATR_S_WAIT_TCK:
669 /* Some cards have an ATR with long indication of historical bytes */
670 /* FIXME: should we check the checksum? */
671 osmo_fsm_inst_state_chg(fi, ATR_S_DONE, 0, 0);
672 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_ATR_DONE_IND, atp->atr);
673 break;
674 default:
675 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_ATR_ERR_IND, NULL);
676 break;
677 }
678 break;
Harald Welte06348362019-05-19 00:45:17 +0200679 default:
680 OSMO_ASSERT(0);
681 }
682}
683
684static const struct osmo_fsm_state atr_states[] = {
685 [ATR_S_WAIT_TS] = {
686 .name = "WAIT_TS",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200687 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
688 S(ISO7816_E_WTIME_EXP),
Harald Welte06348362019-05-19 00:45:17 +0200689 .out_state_mask = S(ATR_S_WAIT_TS) |
690 S(ATR_S_WAIT_T0),
691 .action = atr_wait_ts_action,
692 .onenter = atr_wait_ts_onenter,
693 },
694 [ATR_S_WAIT_T0] = {
695 .name = "WAIT_T0",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200696 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
697 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200698 .out_state_mask = S(ATR_S_WAIT_TS) |
699 S(ATR_S_WAIT_TA) |
Harald Welte06348362019-05-19 00:45:17 +0200700 S(ATR_S_WAIT_TB) |
701 S(ATR_S_WAIT_TC) |
702 S(ATR_S_WAIT_TD) |
703 S(ATR_S_WAIT_HIST) |
704 S(ATR_S_WAIT_TCK) |
705 S(ATR_S_WAIT_T0),
706 .action = atr_wait_tX_action,
707 },
708 [ATR_S_WAIT_TA] = {
709 .name = "WAIT_TA",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200710 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
711 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200712 .out_state_mask = S(ATR_S_WAIT_TS) |
713 S(ATR_S_WAIT_TB) |
Harald Welte06348362019-05-19 00:45:17 +0200714 S(ATR_S_WAIT_TC) |
715 S(ATR_S_WAIT_TD) |
716 S(ATR_S_WAIT_HIST) |
717 S(ATR_S_WAIT_TCK) |
718 S(ATR_S_WAIT_T0),
719 .action = atr_wait_tX_action,
720 },
721 [ATR_S_WAIT_TB] = {
722 .name = "WAIT_TB",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200723 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
724 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200725 .out_state_mask = S(ATR_S_WAIT_TS) |
726 S(ATR_S_WAIT_TC) |
Harald Welte06348362019-05-19 00:45:17 +0200727 S(ATR_S_WAIT_TD) |
728 S(ATR_S_WAIT_HIST) |
729 S(ATR_S_WAIT_TCK) |
730 S(ATR_S_WAIT_T0),
731 .action = atr_wait_tX_action,
732 },
733 [ATR_S_WAIT_TC] = {
734 .name = "WAIT_TC",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200735 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
736 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200737 .out_state_mask = S(ATR_S_WAIT_TS) |
738 S(ATR_S_WAIT_TD) |
Harald Welte06348362019-05-19 00:45:17 +0200739 S(ATR_S_WAIT_HIST) |
740 S(ATR_S_WAIT_TCK) |
741 S(ATR_S_WAIT_T0),
742 .action = atr_wait_tX_action,
743 },
744 [ATR_S_WAIT_TD] = {
745 .name = "WAIT_TD",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200746 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
747 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200748 .out_state_mask = S(ATR_S_WAIT_TS) |
749 S(ATR_S_WAIT_TA) |
Harald Welte06348362019-05-19 00:45:17 +0200750 S(ATR_S_WAIT_TB) |
751 S(ATR_S_WAIT_TC) |
752 S(ATR_S_WAIT_TD) |
753 S(ATR_S_WAIT_HIST) |
754 S(ATR_S_WAIT_TCK) |
755 S(ATR_S_WAIT_T0),
756 .action = atr_wait_tX_action,
757 },
758 [ATR_S_WAIT_HIST] = {
759 .name = "WAIT_HIST",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200760 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
761 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200762 .out_state_mask = S(ATR_S_WAIT_TS) |
763 S(ATR_S_WAIT_TCK) |
Harald Welte1ac9ef92019-10-09 22:20:16 +0200764 S(ATR_S_WAIT_T0) |
765 S(ATR_S_DONE),
Harald Welte06348362019-05-19 00:45:17 +0200766 .action = atr_wait_tX_action,
767 },
768 [ATR_S_WAIT_TCK] = {
769 .name = "WAIT_TCK",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200770 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
771 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200772 .out_state_mask = S(ATR_S_WAIT_TS) |
773 S(ATR_S_DONE),
Harald Welte06348362019-05-19 00:45:17 +0200774 .action = atr_wait_tX_action,
775 },
776 [ATR_S_DONE] = {
777 .name = "DONE",
778 .in_event_mask = 0,
Harald Welte704d99a2019-10-09 21:39:27 +0200779 .out_state_mask = S(ATR_S_WAIT_TS),
Harald Welte06348362019-05-19 00:45:17 +0200780 //.action = atr_done_action,
781 },
782
783};
784static struct osmo_fsm atr_fsm = {
785 .name = "ATR",
786 .states = atr_states,
787 .num_states = ARRAY_SIZE(atr_states),
788 .log_subsys = DATR,
789 .event_names = iso7816_3_event_names,
790};
791
792/***********************************************************************
793 * PPS FSM
794 ***********************************************************************/
795
796static const struct osmo_fsm_state pps_states[] = {
797 [PPS_S_WAIT_PPSS] = {
798 .name = "WAIT_PPSS",
799 },
800 [PPS_S_WAIT_PPS0] = {
801 .name = "WAIT_PPS0",
802 },
803 [PPS_S_WAIT_PPS1] = {
804 .name = "WAIT_PPS1",
805 },
806 [PPS_S_WAIT_PPS2] = {
807 .name = "WAIT_PPS2",
808 },
809 [PPS_S_WAIT_PPS3] = {
810 .name = "WAIT_PPS3",
811 },
812 [PPS_S_WAIT_PCK] = {
813 .name = "WAIT_PCK",
814 },
815 [PPS_S_WAIT_END] = {
816 .name = "WAIT_END",
817 },
818};
819
820static struct osmo_fsm pps_fsm = {
821 .name = "PPS",
822 .states = pps_states,
823 .num_states = ARRAY_SIZE(pps_states),
824 .log_subsys = DPPS,
825 .event_names = iso7816_3_event_names,
826};
827
828/***********************************************************************
829 * TPDU FSM
830 ***********************************************************************/
831
Harald Welte65087832019-10-01 09:16:49 +0200832/* In this FSM weu use the msgb for the TPDU as follows:
833 * - 5-byte TPDU header is at msg->data
834 * - COMMAND TPDU:
835 * - command bytes are provided after the header at msg->l2h
836 * - in case of incremental transmission, l3h points to next to-be-transmitted byte
837 * - RESPONSE TPDU:
838 * - any response bytes are stored after the header at msg->l2h
839 */
840
841static inline struct osim_apdu_cmd_hdr *msgb_tpdu_hdr(struct msgb *msg) {
842 return (struct osim_apdu_cmd_hdr *) msgb_data(msg);
843}
844
Harald Welte06348362019-05-19 00:45:17 +0200845struct tpdu_fsm_priv {
846 struct msgb *tpdu;
Harald Welte65087832019-10-01 09:16:49 +0200847 bool is_command; /* is this a command TPDU (true) or a response (false) */
Harald Welte06348362019-05-19 00:45:17 +0200848};
849
850/* type-safe method to obtain iso7816_3_priv from fi */
851static struct tpdu_fsm_priv *get_tpdu_fsm_priv(struct osmo_fsm_inst *fi)
852{
853 OSMO_ASSERT(fi);
854 OSMO_ASSERT(fi->fsm == &tpdu_fsm);
855 return (struct tpdu_fsm_priv *) fi->priv;
856}
857
858
859static void tpdu_s_init_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
860{
861 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
862 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
863 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
864 struct osim_apdu_cmd_hdr *tpduh;
865
866 switch (event) {
867 case ISO7816_E_XCEIVE_TPDU_CMD:
868 /* start transmission of a TPDU by sending the 5-byte header */
869 tfp->tpdu = (struct msgb *)data;
870 OSMO_ASSERT(msgb_length(tfp->tpdu) >= sizeof(*tpduh));
871 tfp->tpdu->l2h = msgb_data(tfp->tpdu) + sizeof(*tpduh);
Harald Welte65087832019-10-01 09:16:49 +0200872 if (msgb_l2len(tfp->tpdu)) {
873 tfp->is_command = true;
874 tfp->tpdu->l3h = tfp->tpdu->l2h; /* next tx byte == first byte of body */
875 } else
876 tfp->is_command = false;
877 tpduh = msgb_tpdu_hdr(tfp->tpdu);
878 LOGPFSML(fi, LOGL_DEBUG, "Transmitting %s TPDU header %s via UART\n",
879 tfp->is_command ? "COMMAND" : "RESPONSE",
Harald Welte06348362019-05-19 00:45:17 +0200880 osmo_hexdump_nospc((uint8_t *) tpduh, sizeof(*tpduh)));
881 osmo_fsm_inst_state_chg(fi, TPDU_S_TX_HDR, 0, 0);
Harald Welte6603d952019-10-09 20:50:13 +0200882 card_uart_tx(ip->uart, (uint8_t *) tpduh, sizeof(*tpduh), true);
Harald Welte06348362019-05-19 00:45:17 +0200883 break;
884 default:
885 OSMO_ASSERT(0);
886 }
887}
888
889static void tpdu_s_tx_hdr_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
890{
891 OSMO_ASSERT(fi->fsm == &tpdu_fsm);
892 switch (event) {
893 case ISO7816_E_TX_COMPL:
894 /* Rx of single byte is already enabled by previous card_uart_tx() call */
895 osmo_fsm_inst_state_chg(fi, TPDU_S_PROCEDURE, 0, 0);
896 break;
897 default:
898 OSMO_ASSERT(0);
899 }
900}
901
902
903
904static void tpdu_s_procedure_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
905{
906 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
Harald Welte65087832019-10-01 09:16:49 +0200907 struct osim_apdu_cmd_hdr *tpduh = msgb_tpdu_hdr(tfp->tpdu);
Harald Welte06348362019-05-19 00:45:17 +0200908 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
909 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_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, "Received 0x%02x from UART\n", byte);
916 if (byte == 0x60) {
917 /* NULL: wait for another procedure byte */
918 osmo_fsm_inst_state_chg(fi, TPDU_S_PROCEDURE, 0, 0);
919 } else if ((byte >= 0x60 && byte <= 0x6f) || (byte >= 0x90 && byte <= 0x9f)) {
920 //msgb_apdu_sw(tfp->apdu) = byte << 8;
921 msgb_put(tfp->tpdu, byte);
922 /* receive second SW byte (SW2) */
923 osmo_fsm_inst_state_chg(fi, TPDU_S_SW2, 0, 0);
924 break;
925 } else if (byte == tpduh->ins) {
Harald Welte65087832019-10-01 09:16:49 +0200926 if (tfp->is_command) {
Harald Welte06348362019-05-19 00:45:17 +0200927 /* transmit all remaining bytes */
Harald Welte6603d952019-10-09 20:50:13 +0200928 card_uart_tx(ip->uart, msgb_l2(tfp->tpdu), msgb_l2len(tfp->tpdu), true);
Harald Welte06348362019-05-19 00:45:17 +0200929 osmo_fsm_inst_state_chg(fi, TPDU_S_TX_REMAINING, 0, 0);
930 } else {
931 card_uart_set_rx_threshold(ip->uart, tpduh->p3);
932 osmo_fsm_inst_state_chg(fi, TPDU_S_RX_REMAINING, 0, 0);
933 }
934 } else if (byte == (tpduh->ins ^ 0xFF)) {
Harald Welte65087832019-10-01 09:16:49 +0200935 /* transmit/recieve single byte then wait for proc */
936 if (tfp->is_command) {
937 /* transmit *next*, not first byte */
938 OSMO_ASSERT(msgb_l3len(tfp->tpdu) >= 0);
Harald Welte6603d952019-10-09 20:50:13 +0200939 card_uart_tx(ip->uart, msgb_l3(tfp->tpdu), 1, false);
Harald Welte65087832019-10-01 09:16:49 +0200940 osmo_fsm_inst_state_chg(fi, TPDU_S_TX_SINGLE, 0, 0);
941 } else {
942 osmo_fsm_inst_state_chg(fi, TPDU_S_RX_SINGLE, 0, 0);
943 }
Harald Welte06348362019-05-19 00:45:17 +0200944 } else
945 OSMO_ASSERT(0);
946 break;
947 default:
948 OSMO_ASSERT(0);
949 }
950}
951
952/* UART is transmitting remaining data; we wait for ISO7816_E_TX_COMPL */
953static void tpdu_s_tx_remaining_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
954{
955 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
956 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
957
958 switch (event) {
959 case ISO7816_E_TX_COMPL:
960 card_uart_set_rx_threshold(ip->uart, 1);
961 osmo_fsm_inst_state_chg(fi, TPDU_S_SW1, 0, 0);
962 break;
963 default:
964 OSMO_ASSERT(0);
965 }
966}
967
968/* UART is transmitting single byte of data; we wait for ISO7816_E_TX_COMPL */
969static void tpdu_s_tx_single_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
970{
Harald Welte65087832019-10-01 09:16:49 +0200971 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
972
Harald Welte06348362019-05-19 00:45:17 +0200973 switch (event) {
974 case ISO7816_E_TX_COMPL:
Harald Welte65087832019-10-01 09:16:49 +0200975 tfp->tpdu->l3h += 1;
976 if (msgb_l3len(tfp->tpdu))
977 osmo_fsm_inst_state_chg(fi, TPDU_S_PROCEDURE, 0, 0);
978 else
979 osmo_fsm_inst_state_chg(fi, TPDU_S_SW1, 0, 0);
Harald Welte06348362019-05-19 00:45:17 +0200980 break;
981 default:
982 OSMO_ASSERT(0);
983 }
984}
985
986/* UART is receiving remaining data; we wait for ISO7816_E_RX_COMPL */
987static void tpdu_s_rx_remaining_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
988{
989 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
Harald Welte65087832019-10-01 09:16:49 +0200990 struct osim_apdu_cmd_hdr *tpduh = msgb_tpdu_hdr(tfp->tpdu);
Harald Welte06348362019-05-19 00:45:17 +0200991 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
992 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
993 int rc;
994
995 switch (event) {
996 case ISO7816_E_RX_COMPL:
997 /* retrieve pending byte(s) */
998 rc = card_uart_rx(ip->uart, msgb_l2(tfp->tpdu), tpduh->p3);
Harald Welte65087832019-10-01 09:16:49 +0200999 OSMO_ASSERT(rc > 0);
1000 msgb_put(tfp->tpdu, rc);
1001 if (msgb_l2len(tfp->tpdu) != tpduh->p3) {
1002 LOGPFSML(fi, LOGL_ERROR, "expected %u bytes; read %d\n", tpduh->p3,
1003 msgb_l2len(tfp->tpdu));
1004 }
Harald Welte06348362019-05-19 00:45:17 +02001005 card_uart_set_rx_threshold(ip->uart, 1);
1006 osmo_fsm_inst_state_chg(fi, TPDU_S_SW1, 0, 0);
1007 break;
1008 default:
1009 OSMO_ASSERT(0);
1010 }
1011}
1012
1013/* UART is receiving single byte of data; we wait for ISO7816_E_RX_SINGLE */
1014static void tpdu_s_rx_single_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1015{
1016 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
Harald Welte65087832019-10-01 09:16:49 +02001017 struct osim_apdu_cmd_hdr *tpduh = msgb_tpdu_hdr(tfp->tpdu);
Harald Welte06348362019-05-19 00:45:17 +02001018 uint8_t byte;
1019
1020 switch (event) {
1021 case ISO7816_E_RX_SINGLE:
1022 byte = get_rx_byte_evt(fi->proc.parent, data);
1023 LOGPFSML(fi, LOGL_DEBUG, "Received 0x%02x from UART\n", byte);
Harald Welte65087832019-10-01 09:16:49 +02001024 msgb_put_u8(tfp->tpdu, byte);
1025 /* determine if number of expected bytes received */
1026 if (msgb_l2len(tfp->tpdu) == tpduh->p3)
Harald Welte06348362019-05-19 00:45:17 +02001027 osmo_fsm_inst_state_chg(fi, TPDU_S_SW1, 0, 0);
Harald Welte65087832019-10-01 09:16:49 +02001028 else
Harald Welte06348362019-05-19 00:45:17 +02001029 osmo_fsm_inst_state_chg(fi, TPDU_S_PROCEDURE, 0, 0);
1030 break;
1031 default:
1032 OSMO_ASSERT(0);
1033 }
1034}
1035
1036static void tpdu_s_sw1_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1037{
1038 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
1039 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1040 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1041 uint8_t byte;
1042
1043 switch (event) {
1044 case ISO7816_E_RX_SINGLE:
1045 byte = get_rx_byte_evt(fi->proc.parent, data);
1046 LOGPFSML(fi, LOGL_DEBUG, "Received 0x%02x from UART\n", byte);
1047 /* record byte */
1048 //msgb_apdu_sw(tfp->apdu) = byte << 8;
1049 msgb_put_u8(tfp->tpdu, byte);
1050 card_uart_set_rx_threshold(ip->uart, 1);
1051 osmo_fsm_inst_state_chg(fi, TPDU_S_SW2, 0, 0);
1052 break;
1053 default:
1054 OSMO_ASSERT(0);
1055 }
1056}
1057
1058static void tpdu_s_sw2_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1059{
1060 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
1061 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1062 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1063 uint8_t byte;
1064
1065 switch (event) {
1066 case ISO7816_E_RX_SINGLE:
1067 byte = get_rx_byte_evt(fi->proc.parent, data);
1068 LOGPFSML(fi, LOGL_DEBUG, "Received 0x%02x from UART\n", byte);
1069 /* record SW2 byte */
1070 //msgb_apdu_sw(tfp->apdu) &= 0xFF00;
1071 //msgb_apdu_sw(tfp->apdu) |= byte;
1072 msgb_put_u8(tfp->tpdu, byte);
1073 osmo_fsm_inst_state_chg(fi, TPDU_S_DONE, 0, 0);
1074 /* Notify parent FSM */
1075 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_TPDU_DONE_IND, tfp->tpdu);
1076 break;
1077 default:
1078 OSMO_ASSERT(0);
1079 }
1080}
1081
1082static void tpdu_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1083{
1084 OSMO_ASSERT(fi->fsm == &tpdu_fsm);
1085
1086 switch (event) {
1087 case ISO7816_E_RX_ERR_IND:
1088 case ISO7816_E_TX_ERR_IND:
1089 /* FIXME: handle this in some different way */
1090 osmo_fsm_inst_state_chg(fi, TPDU_S_DONE, 0, 0);
1091 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_TPDU_DONE_IND, NULL);
1092 break;
1093 case ISO7816_E_TPDU_CLEAR_REQ:
1094 osmo_fsm_inst_state_chg(fi, TPDU_S_INIT, 0, 0);
1095 break;
1096 }
1097}
1098
1099static const struct osmo_fsm_state tpdu_states[] = {
1100 [TPDU_S_INIT] = {
1101 .name = "INIT",
1102 .in_event_mask = S(ISO7816_E_XCEIVE_TPDU_CMD) |
1103 S(ISO7816_E_TX_COMPL),
1104 .out_state_mask = S(TPDU_S_INIT) |
1105 S(TPDU_S_TX_HDR),
1106 .action = tpdu_s_init_action,
1107 },
1108 [TPDU_S_TX_HDR] = {
1109 .name = "TX_HDR",
1110 .in_event_mask = S(ISO7816_E_TX_COMPL),
1111 .out_state_mask = S(TPDU_S_INIT) |
1112 S(TPDU_S_PROCEDURE),
1113 .action = tpdu_s_tx_hdr_action,
1114 },
1115 [TPDU_S_PROCEDURE] = {
1116 .name = "PROCEDURE",
1117 .in_event_mask = S(ISO7816_E_RX_SINGLE),
1118 .out_state_mask = S(TPDU_S_INIT) |
1119 S(TPDU_S_PROCEDURE) |
1120 S(TPDU_S_RX_REMAINING) |
1121 S(TPDU_S_RX_SINGLE) |
1122 S(TPDU_S_TX_REMAINING) |
1123 S(TPDU_S_TX_SINGLE) |
1124 S(TPDU_S_SW2),
1125 .action = tpdu_s_procedure_action,
1126 },
1127 [TPDU_S_TX_REMAINING] = {
1128 .name = "TX_REMAINING",
1129 .in_event_mask = S(ISO7816_E_TX_COMPL),
1130 .out_state_mask = S(TPDU_S_INIT) |
1131 S(TPDU_S_SW1),
1132 .action = tpdu_s_tx_remaining_action,
1133 },
1134 [TPDU_S_TX_SINGLE] = {
1135 .name = "TX_SINGLE",
1136 .in_event_mask = S(ISO7816_E_TX_COMPL),
1137 .out_state_mask = S(TPDU_S_INIT) |
1138 S(TPDU_S_PROCEDURE),
1139 .action = tpdu_s_tx_single_action,
1140 },
1141 [TPDU_S_RX_REMAINING] = {
1142 .name = "RX_REMAINING",
1143 .in_event_mask = S(ISO7816_E_RX_COMPL),
1144 .out_state_mask = S(TPDU_S_INIT) |
1145 S(TPDU_S_SW1),
1146 .action = tpdu_s_rx_remaining_action,
1147 },
1148 [TPDU_S_RX_SINGLE] = {
1149 .name = "RX_SINGLE",
1150 .in_event_mask = S(ISO7816_E_RX_SINGLE),
1151 .out_state_mask = S(TPDU_S_INIT) |
1152 S(TPDU_S_PROCEDURE),
1153 .action = tpdu_s_rx_single_action,
1154 },
1155 [TPDU_S_SW1] = {
1156 .name = "SW1",
1157 .in_event_mask = S(ISO7816_E_RX_SINGLE),
1158 .out_state_mask = S(TPDU_S_INIT) |
1159 S(TPDU_S_SW2),
1160 .action = tpdu_s_sw1_action,
1161 },
1162 [TPDU_S_SW2] = {
1163 .name = "SW2",
1164 .in_event_mask = S(ISO7816_E_RX_SINGLE),
1165 .out_state_mask = S(TPDU_S_INIT) |
1166 S(TPDU_S_DONE),
1167 .action = tpdu_s_sw2_action,
1168 },
1169 [TPDU_S_DONE] = {
1170 .name = "DONE",
1171 .in_event_mask = 0,
1172 .out_state_mask = S(TPDU_S_INIT),
1173 .action = NULL,
1174 },
1175};
1176static struct osmo_fsm tpdu_fsm = {
1177 .name = "TPDU",
1178 .states = tpdu_states,
1179 .num_states = ARRAY_SIZE(tpdu_states),
1180 .allstate_event_mask = S(ISO7816_E_RX_ERR_IND) |
1181 S(ISO7816_E_TX_ERR_IND) |
1182 S(ISO7816_E_TPDU_CLEAR_REQ),
1183 .allstate_action = tpdu_allstate_action,
1184 .log_subsys = DTPDU,
1185 .event_names = iso7816_3_event_names,
1186};
1187
1188struct osmo_fsm_inst *iso7816_fsm_alloc(void *ctx, int log_level, const char *id,
1189 struct card_uart *cuart, iso7816_user_cb user_cb,
1190 void *user_priv)
1191{
1192 struct iso7816_3_priv *ip;
1193 struct osmo_fsm_inst *fi;
1194
1195 fi = osmo_fsm_inst_alloc(&iso7816_3_fsm, ctx, NULL, log_level, id);
1196 ip = talloc_zero(fi, struct iso7816_3_priv);
1197 if (!ip)
1198 goto out_fi;
1199 fi->priv = ip;
1200
1201 ip->uart = cuart;
1202 cuart->priv = fi;
1203 cuart->handle_event = tpdu_uart_notification;
1204
1205 ip->user_cb = user_cb;
1206 ip->user_priv = user_priv;
1207
1208 ip->atr_fi = osmo_fsm_inst_alloc_child(&atr_fsm, fi, ISO7816_E_SW_ERR_IND);
1209 if (!ip->atr_fi)
1210 goto out_fi;
1211 ip->atr_fi->priv = talloc_zero(ip->atr_fi, struct atr_fsm_priv);
1212 if (!ip->atr_fi->priv)
1213 goto out_atr;
1214
1215 ip->tpdu_fi = osmo_fsm_inst_alloc_child(&tpdu_fsm, fi, ISO7816_E_SW_ERR_IND);
1216 if (!ip->tpdu_fi)
1217 goto out_atr;
1218 ip->tpdu_fi->priv = talloc_zero(ip->tpdu_fi, struct tpdu_fsm_priv);
1219 if (!ip->tpdu_fi->priv)
1220 goto out_tpdu;
1221
1222#if 0
1223 ip->pps_fi = osmo_fsm_inst_alloc_child(&pps_fsm, fi, ISO7816_E_SW_ERR_IND);
1224 if (!ip->pps_fi)
1225 goto out_tpdu;
1226 ip->pps_fi->priv = talloc_zero(ip->pps_fi, struct pps_fsm_priv);
1227 if (!ip->pps_fi->priv)
1228 goto out_pps;
1229#endif
1230
1231 /* This ensures the 'onenter' function of the initial state is called */
1232 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
1233
1234 return fi;
1235
1236#if 0
1237out_pps:
1238 osmo_fsm_inst_free(ip->pps_fi);
1239#endif
1240out_tpdu:
1241 osmo_fsm_inst_free(ip->tpdu_fi);
1242out_atr:
1243 osmo_fsm_inst_free(ip->atr_fi);
1244out_fi:
1245 osmo_fsm_inst_free(fi);
1246 cuart->priv = NULL;
1247 return NULL;
1248}
1249
1250void *iso7816_fsm_get_user_priv(struct osmo_fsm_inst *fi)
1251{
1252 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
1253 return ip->user_priv;
1254}
1255
1256
1257static __attribute__((constructor)) void on_dso_load_iso7816(void)
1258{
1259 osmo_fsm_register(&iso7816_3_fsm);
1260 osmo_fsm_register(&atr_fsm);
1261 osmo_fsm_register(&tpdu_fsm);
1262 osmo_fsm_register(&pps_fsm);
1263}