blob: 44c81918c6c09694e6c2ef0c89d1e9a6ab626574 [file] [log] [blame]
Harald Welte06348362019-05-19 00:45:17 +02001/* ISO 7816-3 Finite State Machine (reader side)
2 *
3 * (C) 2019 by Harald Welte <laforge@gnumonks.org>
4 *
5 * inspired by earlier work
6 * (C) 2016-2017 by Harald Welte <hwelte@hmw-consulting.de>
7 * (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
22 */
23
24#include <string.h>
25
26#include <osmocom/core/utils.h>
27#include <osmocom/core/msgb.h>
28#include <osmocom/core/fsm.h>
29#include <osmocom/core/logging.h>
30#include <osmocom/sim/sim.h>
31
32#include "logging.h"
33#include "cuart.h"
34#include "iso7816_fsm.h"
35
36/* Section 8.2: the Answer-to-Reset (... a string of at most 32 bytes) */
37#define MAX_ATR_SIZE 32
38
39#define S(x) (1 << (x))
40
41/*! ISO 7816-3 states */
42enum iso7816_3_state {
43 ISO7816_S_RESET, /*!< in Reset */
44 ISO7816_S_WAIT_ATR, /*!< waiting for ATR to start */
45 ISO7816_S_IN_ATR, /*!< while we are receiving the ATR */
46 ISO7816_S_WAIT_TPDU, /*!< waiting for start of new TPDU */
47 ISO7816_S_IN_TPDU, /*!< inside a single TPDU */
Harald Welte06348362019-05-19 00:45:17 +020048 ISO7816_S_WAIT_PPS_RSP, /*!< waiting for start of the PPS response */
49 ISO7816_S_IN_PPS_RSP, /*!< while we are inside the PPS request */
50};
51
52/*! Answer-To-Reset (ATR) sub-states of ISO7816_S_IN_ATR
53 * @note defined in ISO/IEC 7816-3:2006(E) section 8
54 */
55enum atr_state {
56 ATR_S_WAIT_TS, /*!< initial byte */
57 ATR_S_WAIT_T0, /*!< format byte */
58 ATR_S_WAIT_TA, /*!< first sub-group interface byte */
59 ATR_S_WAIT_TB, /*!< second sub-group interface byte */
60 ATR_S_WAIT_TC, /*!< third sub-group interface byte */
61 ATR_S_WAIT_TD, /*!< fourth sub-group interface byte */
62 ATR_S_WAIT_HIST, /*!< historical byte */
63 ATR_S_WAIT_TCK, /*!< check byte */
64 ATR_S_DONE
65};
66
67/*! Protocol and Parameters Selection (PPS) sub-states of ISO7816_S_IN_PTS_REQ/ISO7816_S_IN_PTS_RSP
68 * @note defined in ISO/IEC 7816-3:2006(E) section 9
69 */
70enum pps_state {
Eric Wildad1edce2019-11-27 16:51:08 +010071 PPS_S_TX_PPS_REQ, /*!< tx pps request */
Harald Welte06348362019-05-19 00:45:17 +020072 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);
Eric Wildad1edce2019-11-27 16:51:08 +0100224 osmo_fsm_inst_state_chg(ip->pps_fi, PPS_S_TX_PPS_REQ, 0, 0);
Harald Welte06348362019-05-19 00:45:17 +0200225 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);
Eric Wild9e622dc2019-11-27 14:43:16 +0100232 struct msgb *msg;
Harald Welte06348362019-05-19 00:45:17 +0200233
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;
Eric Wild759a6462019-11-11 14:22:52 +0100241 case ISO7816_E_POWER_UP_IND:
242 break;
Eric Wild9e622dc2019-11-27 14:43:16 +0100243 case ISO7816_E_PPS_FAILED_IND:
244 msg = data;
245 /* notify user about PPS result */
246 ip->user_cb(fi, event, 0, msg);
247 break;
248 case ISO7816_E_TPDU_FAILED_IND:
249 msg = data;
250 /* hand finished TPDU to user */
251 ip->user_cb(fi, event, 0, msg);
252 break;
Harald Welte06348362019-05-19 00:45:17 +0200253 default:
254 OSMO_ASSERT(0);
255 }
256}
257
258static void iso7816_3_wait_atr_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
259{
260 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
261 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
262
263 switch (event) {
264 case ISO7816_E_RX_SINGLE:
265 osmo_fsm_inst_state_chg(fi, ISO7816_S_IN_ATR, 0, 0);
266 osmo_fsm_inst_dispatch(ip->atr_fi, event, data);
267 break;
Harald Welte1ac9ef92019-10-09 22:20:16 +0200268 case ISO7816_E_WTIME_EXP:
269 ip->user_cb(fi, event, 0, NULL);
270 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
271 break;
Harald Welte06348362019-05-19 00:45:17 +0200272 default:
273 OSMO_ASSERT(0);
274 }
275}
276
277static void iso7816_3_in_atr_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
278{
279 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
280 struct msgb *atr;
281 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
282
283 switch (event) {
284 case ISO7816_E_RX_SINGLE:
285 case ISO7816_E_RX_ERR_IND:
Harald Welte1ac9ef92019-10-09 22:20:16 +0200286 case ISO7816_E_WTIME_EXP:
Harald Welte06348362019-05-19 00:45:17 +0200287 /* simply pass this through to the child FSM for the ATR */
288 osmo_fsm_inst_dispatch(ip->atr_fi, event, data);
289 break;
290 case ISO7816_E_ATR_DONE_IND:
291 atr = data;
292 /* FIXME: verify ATR result: success / failure */
293 osmo_fsm_inst_state_chg(fi, ISO7816_S_WAIT_TPDU, 0, 0);
294 /* notify user about ATR */
295 ip->user_cb(fi, event, 0, atr);
296 break;
Harald Welte1ac9ef92019-10-09 22:20:16 +0200297 case ISO7816_E_ATR_ERR_IND:
Eric Wild91552312019-11-18 13:57:11 +0100298 atr = data;
Harald Welte1ac9ef92019-10-09 22:20:16 +0200299 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
300 ip->user_cb(fi, event, 0, atr);
301 break;
Harald Welte06348362019-05-19 00:45:17 +0200302 default:
303 OSMO_ASSERT(0);
304 }
305}
306
307static void iso7816_3_wait_tpdu_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
308{
309 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
310 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
Eric Wildfd0bace2019-11-27 18:33:09 +0100311 card_uart_ctrl(ip->uart, CUART_CTL_NO_RXTX, true);
Harald Welte06348362019-05-19 00:45:17 +0200312 /* reset the TPDU state machine */
313 osmo_fsm_inst_dispatch(ip->tpdu_fi, ISO7816_E_TPDU_CLEAR_REQ, NULL);
314}
315
316static void iso7816_3_wait_tpdu_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
317{
318 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
319 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
320
321 switch (event) {
322 case ISO7816_E_XCEIVE_TPDU_CMD:
323 /* "data" contains a msgb-wrapped TPDU */
324 osmo_fsm_inst_state_chg(fi, ISO7816_S_IN_TPDU, 0, 0);
325 /* pass on to sub-fsm */
326 osmo_fsm_inst_dispatch(ip->tpdu_fi, event, data);
327 break;
Eric Wildad1edce2019-11-27 16:51:08 +0100328 case ISO7816_E_XCEIVE_PPS_CMD:
329 osmo_fsm_inst_state_chg(fi, ISO7816_S_WAIT_PPS_RSP, 0, 0);
330 osmo_fsm_inst_state_chg(ip->pps_fi, PPS_S_TX_PPS_REQ, 0, 0);
331 osmo_fsm_inst_dispatch(ip->pps_fi, event, data);
332 break;
Harald Welte06348362019-05-19 00:45:17 +0200333 default:
334 OSMO_ASSERT(0);
335 }
336}
337
338static void iso7816_3_in_tpdu_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
339{
340 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
341 struct msgb *apdu;
342 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
343
344 switch (event) {
345 case ISO7816_E_RX_SINGLE:
346 case ISO7816_E_RX_COMPL:
347 case ISO7816_E_RX_ERR_IND:
348 case ISO7816_E_TX_COMPL:
349 case ISO7816_E_TX_ERR_IND:
350 /* simply pass this through to the child FSM for the ATR */
351 osmo_fsm_inst_dispatch(ip->tpdu_fi, event, data);
352 break;
353 case ISO7816_E_TPDU_DONE_IND:
354 apdu = data;
355 osmo_fsm_inst_state_chg(fi, ISO7816_S_WAIT_TPDU, 0, 0);
356 /* hand finished TPDU to user */
357 ip->user_cb(fi, event, 0, apdu);
358 break;
Harald Welte1ac9ef92019-10-09 22:20:16 +0200359 case ISO7816_E_WTIME_EXP:
360 /* FIXME: power off? */
361 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
362 break;
Harald Welte06348362019-05-19 00:45:17 +0200363 default:
364 OSMO_ASSERT(0);
365 }
366}
367
368static void iso7816_3_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
369{
370 OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
371
372 switch (event) {
Harald Welte06348362019-05-19 00:45:17 +0200373 case ISO7816_E_HW_ERR_IND:
374 case ISO7816_E_CARD_REMOVAL:
375 /* FIXME: power off? */
376 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
377 break;
378 case ISO7816_E_POWER_DN_IND:
379 case ISO7816_E_RESET_ACT_IND:
380 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
381 break;
382 case ISO7816_E_ABORT_REQ:
383 /* FIXME */
384 break;
385 default:
386 OSMO_ASSERT(0);
387 break;
388 }
389}
390
Eric Wildad1edce2019-11-27 16:51:08 +0100391
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",
Eric Wild9e622dc2019-11-27 14:43:16 +0100437 .in_event_mask = S(ISO7816_E_RESET_REL_IND) |
438 S(ISO7816_E_PPS_FAILED_IND)|
439 S(ISO7816_E_TPDU_FAILED_IND),
Harald Welte06348362019-05-19 00:45:17 +0200440 .out_state_mask = S(ISO7816_S_WAIT_ATR) |
441 S(ISO7816_S_RESET),
442 .action = iso7816_3_reset_action,
443 .onenter = iso7816_3_reset_onenter,
444 },
445 [ISO7816_S_WAIT_ATR] = {
446 .name = "WAIT_ATR",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200447 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
448 S(ISO7816_E_WTIME_EXP),
Harald Welte06348362019-05-19 00:45:17 +0200449 .out_state_mask = S(ISO7816_S_RESET) |
450 S(ISO7816_S_IN_ATR),
451 .action = iso7816_3_wait_atr_action,
452 },
453 [ISO7816_S_IN_ATR] = {
454 .name = "IN_ATR",
455 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
456 S(ISO7816_E_RX_ERR_IND) |
Harald Welte1ac9ef92019-10-09 22:20:16 +0200457 S(ISO7816_E_ATR_DONE_IND) |
458 S(ISO7816_E_ATR_ERR_IND) |
459 S(ISO7816_E_WTIME_EXP),
Harald Welte06348362019-05-19 00:45:17 +0200460 .out_state_mask = S(ISO7816_S_RESET) |
461 S(ISO7816_S_IN_ATR) |
462 S(ISO7816_S_WAIT_TPDU),
463 .action = iso7816_3_in_atr_action,
464 },
465 [ISO7816_S_WAIT_TPDU] = {
466 .name = "WAIT_TPDU",
Eric Wildad1edce2019-11-27 16:51:08 +0100467 .in_event_mask = S(ISO7816_E_XCEIVE_TPDU_CMD) |
468 S(ISO7816_E_XCEIVE_PPS_CMD),
Harald Welte06348362019-05-19 00:45:17 +0200469 .out_state_mask = S(ISO7816_S_RESET) |
470 S(ISO7816_S_WAIT_TPDU) |
471 S(ISO7816_S_IN_TPDU) |
Eric Wildad1edce2019-11-27 16:51:08 +0100472 S(ISO7816_S_WAIT_PPS_RSP),
Harald Welte06348362019-05-19 00:45:17 +0200473 .action = iso7816_3_wait_tpdu_action,
474 .onenter = iso7816_3_wait_tpdu_onenter,
475 },
476 [ISO7816_S_IN_TPDU] = {
477 .name = "IN_TPDU",
478 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
479 S(ISO7816_E_RX_COMPL) |
480 S(ISO7816_E_TX_COMPL) |
481 S(ISO7816_E_RX_ERR_IND) |
482 S(ISO7816_E_TX_ERR_IND) |
Harald Welte1ac9ef92019-10-09 22:20:16 +0200483 S(ISO7816_E_TPDU_DONE_IND) |
484 S(ISO7816_E_WTIME_EXP),
Harald Welte06348362019-05-19 00:45:17 +0200485 .out_state_mask = S(ISO7816_S_RESET) |
486 S(ISO7816_S_WAIT_TPDU) |
487 S(ISO7816_S_IN_TPDU),
488 .action = iso7816_3_in_tpdu_action,
489 },
Harald Welte06348362019-05-19 00:45:17 +0200490 [ISO7816_S_WAIT_PPS_RSP] = {
491 .name = "WAIT_PPS_RESP",
Eric Wildad1edce2019-11-27 16:51:08 +0100492 .in_event_mask = S(ISO7816_E_TX_COMPL) |
493 S(ISO7816_E_TX_ERR_IND) |
494 S(ISO7816_E_WTIME_EXP),
Harald Welte06348362019-05-19 00:45:17 +0200495 .out_state_mask = S(ISO7816_S_RESET) |
496 S(ISO7816_S_WAIT_TPDU) |
497 S(ISO7816_S_WAIT_PPS_RSP) |
498 S(ISO7816_S_IN_PPS_RSP),
Eric Wildad1edce2019-11-27 16:51:08 +0100499 .action = iso7816_3_s_wait_pps_rsp_action,
Harald Welte06348362019-05-19 00:45:17 +0200500 },
501 [ISO7816_S_IN_PPS_RSP] = {
502 .name = "IN_PPS_RESP",
Eric Wildad1edce2019-11-27 16:51:08 +0100503 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
504 S(ISO7816_E_RX_COMPL) |
505 S(ISO7816_E_RX_ERR_IND) |
506 S(ISO7816_E_PPS_DONE_IND) |
507 S(ISO7816_E_PPS_FAILED_IND) |
508 S(ISO7816_E_WTIME_EXP),
Harald Welte06348362019-05-19 00:45:17 +0200509 .out_state_mask = S(ISO7816_S_RESET) |
510 S(ISO7816_S_WAIT_TPDU) |
511 S(ISO7816_S_IN_PPS_RSP),
Eric Wildad1edce2019-11-27 16:51:08 +0100512 .action = iso7816_3_s_ins_pps_rsp_action,
Harald Welte06348362019-05-19 00:45:17 +0200513 },
514};
515static struct osmo_fsm iso7816_3_fsm = {
516 .name = "ISO7816-3",
517 .states = iso7816_3_states,
518 .num_states = ARRAY_SIZE(iso7816_3_states),
519 .log_subsys = DISO7816,
520 .event_names = iso7816_3_event_names,
521 .allstate_action = iso7816_3_allstate_action,
Harald Welte1ac9ef92019-10-09 22:20:16 +0200522 .allstate_event_mask = S(ISO7816_E_CARD_REMOVAL) |
Harald Welte06348362019-05-19 00:45:17 +0200523 S(ISO7816_E_POWER_DN_IND) |
524 S(ISO7816_E_RESET_ACT_IND) |
525 S(ISO7816_E_HW_ERR_IND) |
526 S(ISO7816_E_ABORT_REQ),
527};
528
529/***********************************************************************
530 * ATR FSM
531 ***********************************************************************/
532
533struct atr_fsm_priv {
534 uint8_t hist_len; /*!< store the number of expected historical bytes */
535 uint8_t y; /*!< last mask of the upcoming TA, TB, TC, TD interface bytes */
536 uint8_t i; /*!< interface byte subgroup number */
537 struct msgb *atr; /*!< ATR data */
538 uint8_t computed_checksum;
539 uint16_t protocol_support;
540};
541
542/* obtain the [software] guard time in milli-seconds from the atr fsm_inst */
543static uint32_t atr_fi_gt_ms(struct osmo_fsm_inst *fi)
544{
545 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
546 struct iso7816_3_priv *ip;
547
548 OSMO_ASSERT(fi->fsm == &atr_fsm);
549 OSMO_ASSERT(parent_fi);
550 ip = get_iso7816_3_priv(parent_fi);
551
552 return ip->guard_time_ms;
553}
554
555/* obtain the 'byte' parmeter of an ISO7816_E_RX event */
556static uint8_t get_rx_byte_evt(struct osmo_fsm_inst *fi, void *data)
557{
558 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
559 uint8_t byte = *(uint8_t *)data;
560
561 /* apply inverse convention */
562 if (ip->convention_convert)
563 byte = convention_convert_lut[byte];
564
565 return byte;
566}
567
568/* append a single byte to the ATR */
569static int atr_append_byte(struct osmo_fsm_inst *fi, uint8_t byte)
570{
571 struct atr_fsm_priv *atp = fi->priv;
572
573 if (!msgb_tailroom(atp->atr)) {
574 LOGPFSML(fi, LOGL_ERROR, "ATR overflow !?!");
575 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_SW_ERR_IND, NULL);
576 return -1;
577 }
578 msgb_put_u8(atp->atr, byte);
579 return 0;
580}
581
582static void atr_wait_ts_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
583{
584 struct atr_fsm_priv *atp = fi->priv;
585
586 /* reset state to its initial value */
587 atp->hist_len = 0;
588 atp->y = 0;
589 atp->i = 0;
590 if (!atp->atr)
591 atp->atr = msgb_alloc_c(fi, 33, "ATR"); /* TS + 32 chars */
592 else
593 msgb_reset(atp->atr);
594 atp->computed_checksum = 0;
595 atp->protocol_support = 0;
596}
597
598static void atr_wait_ts_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
599{
600 struct atr_fsm_priv *atp = fi->priv;
601 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
602 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
603 uint8_t byte;
604
605 switch (event) {
606 case ISO7816_E_RX_SINGLE:
607 OSMO_ASSERT(msgb_length(atp->atr) == 0);
608restart:
609 byte = get_rx_byte_evt(parent_fi, data);
610 LOGPFSML(fi, LOGL_DEBUG, "RX byte '%02x'\n", byte);
611 switch (byte) {
612 case 0x23:
613 /* direct convention used, but decoded using inverse
614 * convention (a parity error should also have occurred) */
615 /* fall-through */
616 case 0x30:
617 /* inverse convention used, but decoded using direct
618 * convention (a parity error should also have occurred) */
619 ip->convention_convert = !ip->convention_convert;
620 goto restart;
621 break;
622 case 0x3b: /* direct convention used and correctly decoded */
623 /* fall-through */
624 case 0x3f: /* inverse convention used and correctly decoded */
625 atr_append_byte(fi, byte);
626 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_T0, atr_fi_gt_ms(fi), T_GUARD);
627 break;
628 default:
629 LOGPFSML(fi, LOGL_ERROR, "Invalid TS received: 0x%02X\n", byte);
630 /* FIXME: somehow indiicate to user */
631 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_SW_ERR_IND, NULL);
632 break;
633 }
634 atp->i = 0; /* first interface byte sub-group is coming (T0 is kind of TD0) */
635 break;
Harald Welte1ac9ef92019-10-09 22:20:16 +0200636 case ISO7816_E_WTIME_EXP:
637 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_ATR_ERR_IND, NULL);
638 break;
Harald Welte06348362019-05-19 00:45:17 +0200639 default:
640 OSMO_ASSERT(0);
641 }
642}
643
644static void atr_wait_tX_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
645{
646 struct atr_fsm_priv *atp = fi->priv;
647 uint32_t guard_time_ms = atr_fi_gt_ms(fi);
648 uint8_t byte;
649
650 switch (event) {
651 case ISO7816_E_RX_SINGLE:
652 byte = get_rx_byte_evt(fi->proc.parent, data);
653 LOGPFSML(fi, LOGL_DEBUG, "RX byte '%02x'\n", byte);
654 atr_append_byte(fi, byte);
655 switch (fi->state) {
656 case ATR_S_WAIT_T0: /* see ISO/IEC 7816-3:2006 section 8.2.2 */
657 case ATR_S_WAIT_TD: /* see ISO/IEC 7816-3:2006 section 8.2.3 */
658 if (fi->state == ATR_S_WAIT_T0) {
659 /* save number of hist. bytes */
660 atp->hist_len = (byte & 0x0f);
661 } else {
662 /* remember supported protocol to know if TCK will be present */
663 atp->protocol_support |= (1<<(byte & 0x0f));
664 }
665 atp->y = (byte & 0xf0); /* remember incoming interface bytes */
666 atp->i++;
667 if (atp->y & 0x10) {
668 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_TA, guard_time_ms, T_GUARD);
669 break;
670 }
671 /* fall-through */
672 case ATR_S_WAIT_TA: /* see ISO/IEC 7816-3:2006 section 8.2.3 */
673 if (atp->y & 0x20) {
674 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_TB, guard_time_ms, T_GUARD);
675 break;
676 }
677 /* fall-through */
678 case ATR_S_WAIT_TB: /* see ISO/IEC 7816-3:2006 section 8.2.3 */
679 if (atp->y & 0x40) {
680 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_TC, guard_time_ms, T_GUARD);
681 break;
682 }
683 /* fall-through */
684 case ATR_S_WAIT_TC: /* see ISO/IEC 7816-3:2006 section 8.2.3 */
685 if (atp->y & 0x80) {
686 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_TD, guard_time_ms, T_GUARD);
687 break;
688 } else if (atp->hist_len) {
689 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_HIST, guard_time_ms, T_GUARD);
690 break;
691 }
692 /* fall-through */
693 case ATR_S_WAIT_HIST: /* see ISO/IEC 7816-3:2006 section 8.2.4 */
694 if (atp->hist_len)
695 atp->hist_len--;
696 if (atp->hist_len == 0) {
697 if (atp->protocol_support > 1) {
698 /* wait for check byte */
699 osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_TCK,
700 guard_time_ms, T_GUARD);
701 break;
Eric Wild70d212d2019-11-27 15:05:09 +0100702 } else {
703 /* no TCK present, ATR complete; notify parent */
704 osmo_fsm_inst_state_chg(fi, ATR_S_DONE, 0, 0);
705 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_ATR_DONE_IND, atp->atr);
Harald Welte06348362019-05-19 00:45:17 +0200706 }
707 } else {
708 break;
709 }
710 /* fall-through */
711 case ATR_S_WAIT_TCK: /* see ISO/IEC 7816-3:2006 section 8.2.5 */
712 /* verify checksum if present */
713 if (fi->state == ATR_S_WAIT_TCK) {
714 uint8_t ui;
715 uint8_t *atr = msgb_data(atp->atr);
716 LOGPFSML(fi, LOGL_INFO, "Complete ATR: %s\n", msgb_hexdump(atp->atr));
717 for (ui = 1; ui < msgb_length(atp->atr)-1; ui++) {
718 atp->computed_checksum ^= atr[ui];
719 }
720 if (atp->computed_checksum != byte) {
721 /* checkum error. report to user? */
722 LOGPFSML(fi, LOGL_ERROR,
723 "computed checksum %02x doesn't match TCK=%02x\n",
724 atp->computed_checksum, byte);
725 }
726 /* ATR complete; notify parent */
727 osmo_fsm_inst_state_chg(fi, ATR_S_DONE, 0, 0);
728 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_ATR_DONE_IND, atp->atr);
729 }
730 break;
731 default:
732 OSMO_ASSERT(0);
733 }
734 break;
Harald Welte1ac9ef92019-10-09 22:20:16 +0200735 case ISO7816_E_WTIME_EXP:
736 switch (fi->state) {
737 case ATR_S_WAIT_HIST:
738 case ATR_S_WAIT_TCK:
739 /* Some cards have an ATR with long indication of historical bytes */
740 /* FIXME: should we check the checksum? */
741 osmo_fsm_inst_state_chg(fi, ATR_S_DONE, 0, 0);
742 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_ATR_DONE_IND, atp->atr);
743 break;
744 default:
745 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_ATR_ERR_IND, NULL);
746 break;
747 }
748 break;
Harald Welte06348362019-05-19 00:45:17 +0200749 default:
750 OSMO_ASSERT(0);
751 }
752}
753
754static const struct osmo_fsm_state atr_states[] = {
755 [ATR_S_WAIT_TS] = {
756 .name = "WAIT_TS",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200757 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
758 S(ISO7816_E_WTIME_EXP),
Harald Welte06348362019-05-19 00:45:17 +0200759 .out_state_mask = S(ATR_S_WAIT_TS) |
760 S(ATR_S_WAIT_T0),
761 .action = atr_wait_ts_action,
762 .onenter = atr_wait_ts_onenter,
763 },
764 [ATR_S_WAIT_T0] = {
765 .name = "WAIT_T0",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200766 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
767 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200768 .out_state_mask = S(ATR_S_WAIT_TS) |
769 S(ATR_S_WAIT_TA) |
Harald Welte06348362019-05-19 00:45:17 +0200770 S(ATR_S_WAIT_TB) |
771 S(ATR_S_WAIT_TC) |
772 S(ATR_S_WAIT_TD) |
773 S(ATR_S_WAIT_HIST) |
774 S(ATR_S_WAIT_TCK) |
775 S(ATR_S_WAIT_T0),
776 .action = atr_wait_tX_action,
777 },
778 [ATR_S_WAIT_TA] = {
779 .name = "WAIT_TA",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200780 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
781 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200782 .out_state_mask = S(ATR_S_WAIT_TS) |
783 S(ATR_S_WAIT_TB) |
Harald Welte06348362019-05-19 00:45:17 +0200784 S(ATR_S_WAIT_TC) |
785 S(ATR_S_WAIT_TD) |
786 S(ATR_S_WAIT_HIST) |
787 S(ATR_S_WAIT_TCK) |
788 S(ATR_S_WAIT_T0),
789 .action = atr_wait_tX_action,
790 },
791 [ATR_S_WAIT_TB] = {
792 .name = "WAIT_TB",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200793 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
794 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200795 .out_state_mask = S(ATR_S_WAIT_TS) |
796 S(ATR_S_WAIT_TC) |
Harald Welte06348362019-05-19 00:45:17 +0200797 S(ATR_S_WAIT_TD) |
798 S(ATR_S_WAIT_HIST) |
799 S(ATR_S_WAIT_TCK) |
800 S(ATR_S_WAIT_T0),
801 .action = atr_wait_tX_action,
802 },
803 [ATR_S_WAIT_TC] = {
804 .name = "WAIT_TC",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200805 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
806 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200807 .out_state_mask = S(ATR_S_WAIT_TS) |
808 S(ATR_S_WAIT_TD) |
Harald Welte06348362019-05-19 00:45:17 +0200809 S(ATR_S_WAIT_HIST) |
810 S(ATR_S_WAIT_TCK) |
811 S(ATR_S_WAIT_T0),
812 .action = atr_wait_tX_action,
813 },
814 [ATR_S_WAIT_TD] = {
815 .name = "WAIT_TD",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200816 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
817 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200818 .out_state_mask = S(ATR_S_WAIT_TS) |
819 S(ATR_S_WAIT_TA) |
Harald Welte06348362019-05-19 00:45:17 +0200820 S(ATR_S_WAIT_TB) |
821 S(ATR_S_WAIT_TC) |
822 S(ATR_S_WAIT_TD) |
823 S(ATR_S_WAIT_HIST) |
824 S(ATR_S_WAIT_TCK) |
825 S(ATR_S_WAIT_T0),
826 .action = atr_wait_tX_action,
827 },
828 [ATR_S_WAIT_HIST] = {
829 .name = "WAIT_HIST",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200830 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
831 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200832 .out_state_mask = S(ATR_S_WAIT_TS) |
833 S(ATR_S_WAIT_TCK) |
Harald Welte1ac9ef92019-10-09 22:20:16 +0200834 S(ATR_S_WAIT_T0) |
835 S(ATR_S_DONE),
Harald Welte06348362019-05-19 00:45:17 +0200836 .action = atr_wait_tX_action,
837 },
838 [ATR_S_WAIT_TCK] = {
839 .name = "WAIT_TCK",
Harald Welte1ac9ef92019-10-09 22:20:16 +0200840 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
841 S(ISO7816_E_WTIME_EXP),
Harald Welte704d99a2019-10-09 21:39:27 +0200842 .out_state_mask = S(ATR_S_WAIT_TS) |
843 S(ATR_S_DONE),
Harald Welte06348362019-05-19 00:45:17 +0200844 .action = atr_wait_tX_action,
845 },
846 [ATR_S_DONE] = {
847 .name = "DONE",
848 .in_event_mask = 0,
Harald Welte704d99a2019-10-09 21:39:27 +0200849 .out_state_mask = S(ATR_S_WAIT_TS),
Harald Welte06348362019-05-19 00:45:17 +0200850 //.action = atr_done_action,
851 },
852
853};
854static struct osmo_fsm atr_fsm = {
855 .name = "ATR",
856 .states = atr_states,
857 .num_states = ARRAY_SIZE(atr_states),
858 .log_subsys = DATR,
859 .event_names = iso7816_3_event_names,
860};
861
862/***********************************************************************
863 * PPS FSM
864 ***********************************************************************/
Eric Wildad1edce2019-11-27 16:51:08 +0100865struct pps_fsm_priv {
866 struct msgb* tx_cmd;
867 struct msgb* rx_cmd;
868 uint8_t pps0_recv;
869};
870
871static void pps_s_wait_ppss_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
872{
873 struct pps_fsm_priv *atp = fi->priv;
874
875 if (!atp->rx_cmd)
Eric Wild9e622dc2019-11-27 14:43:16 +0100876 atp->rx_cmd = msgb_alloc_c(fi, 6, "PPSRSP"); /* at most 6 */
Eric Wildad1edce2019-11-27 16:51:08 +0100877 else
878 msgb_reset(atp->rx_cmd);
Eric Wild9e622dc2019-11-27 14:43:16 +0100879
880 /* notify in case card got pulled out */
Eric Wild759a6462019-11-11 14:22:52 +0100881 if (atp->tx_cmd && old_state != PPS_S_DONE){
Eric Wild9e622dc2019-11-27 14:43:16 +0100882 osmo_fsm_inst_dispatch(fi->proc.parent,
883 ISO7816_E_PPS_FAILED_IND, atp->tx_cmd);
884 atp->tx_cmd = 0;
885 }
Eric Wildad1edce2019-11-27 16:51:08 +0100886}
887
888static void pps_s_tx_pps_req_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
889{
890 struct pps_fsm_priv *atp = fi->priv;
Eric Wildad1edce2019-11-27 16:51:08 +0100891 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
892 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
893
Eric Wild9e622dc2019-11-27 14:43:16 +0100894 /* keep the buffer to compare it with the received response */
895 atp->tx_cmd = data;
896
Eric Wildad1edce2019-11-27 16:51:08 +0100897 switch (event) {
898 case ISO7816_E_XCEIVE_PPS_CMD:
899 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPSS, 0, 0);
900 card_uart_tx(ip->uart, msgb_data(data), msgb_length(data), true);
901 break;
902 default:
903 OSMO_ASSERT(0);
904 }
905}
906
907static void pps_wait_pX_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
908{
909 struct pps_fsm_priv *atp = fi->priv;
910// uint32_t guard_time_ms = atr_fi_gt_ms(fi);
911 uint8_t byte;
912
913 switch (event) {
914 case ISO7816_E_RX_SINGLE:
915 byte = get_rx_byte_evt(fi->proc.parent, data);
916 LOGPFSML(fi, LOGL_DEBUG, "RX byte '%02x'\n", byte);
917 msgb_put_u8(atp->rx_cmd, byte);
918 switch (fi->state) {
919 case PPS_S_WAIT_PPSS:
920 if (byte == 0xff)
921 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPS0, 0, 0);
922 break;
923 case PPS_S_WAIT_PPS0:
924 atp->pps0_recv = byte;
925 if(atp->pps0_recv & (1 << 4)) {
926 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPS1, 0, 0);
927 break;
928 } else if (atp->pps0_recv & (1 << 5)) {
929 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPS2, 0, 0);
930 break;
931 } else if (atp->pps0_recv & (1 << 6)) {
932 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPS3, 0, 0);
933 break;
934 }
935 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PCK, 0, 0);
936 break;
937 case PPS_S_WAIT_PPS1:
938 if (atp->pps0_recv & (1 << 5)) {
939 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPS2, 0, 0);
940 break;
941 } else if (atp->pps0_recv & (1 << 6)) {
942 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPS3, 0, 0);
943 break;
944 }
945 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PCK, 0, 0);
946 break;
947 case PPS_S_WAIT_PPS2:
948 if (atp->pps0_recv & (1 << 6)) {
949 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPS3, 0, 0);
950 break;
951 }
952 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PCK, 0, 0);
953 break;
954 case PPS_S_WAIT_PPS3:
955 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PCK, 0, 0);
956 break;
957 case PPS_S_WAIT_PCK:
958 /* verify checksum if present */
959 if (fi->state == PPS_S_WAIT_PCK) {
960 uint8_t *pps_received = msgb_data(atp->rx_cmd);
961 uint8_t *pps_sent = msgb_data(atp->tx_cmd);
962
963 osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_END, 0, 0);
964
965 /* pps was successful if response equals request
966 * rx buffer stays with the fsm, tx buffer gets handed back and freed
967 * by the cb */
968 if (msgb_length(atp->rx_cmd) == msgb_length(atp->tx_cmd) &&
969 !memcmp(pps_received, pps_sent, msgb_length(atp->rx_cmd))) {
970 osmo_fsm_inst_dispatch(fi->proc.parent,
971 ISO7816_E_PPS_DONE_IND, atp->tx_cmd);
972 } else {
973 osmo_fsm_inst_dispatch(fi->proc.parent,
974 ISO7816_E_PPS_FAILED_IND, atp->tx_cmd);
975 }
Eric Wild9e622dc2019-11-27 14:43:16 +0100976 /* ownership transfer */
977 atp->tx_cmd = 0;
Eric Wildad1edce2019-11-27 16:51:08 +0100978 }
979 break;
980 default:
981 OSMO_ASSERT(0);
982 }
983 break;
984 case ISO7816_E_WTIME_EXP:
985 /* FIXME: timeout handling if no pps supported ? */
986 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_RX_ERR_IND, NULL);
987 break;
988 default:
989 OSMO_ASSERT(0);
990 }
991}
992
Harald Welte06348362019-05-19 00:45:17 +0200993
994static const struct osmo_fsm_state pps_states[] = {
Eric Wildad1edce2019-11-27 16:51:08 +0100995 [PPS_S_TX_PPS_REQ] = {
996 .name = "TX_PPS_REQ",
997 .in_event_mask = S(ISO7816_E_XCEIVE_PPS_CMD) |
998 S(ISO7816_E_WTIME_EXP),
999 .out_state_mask = S(PPS_S_TX_PPS_REQ) |
1000 S(PPS_S_WAIT_PPSS),
1001 .action = pps_s_tx_pps_req_action,
1002 .onenter = pps_s_wait_ppss_onenter,
1003 },
Harald Welte06348362019-05-19 00:45:17 +02001004 [PPS_S_WAIT_PPSS] = {
1005 .name = "WAIT_PPSS",
Eric Wildad1edce2019-11-27 16:51:08 +01001006 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
1007 S(ISO7816_E_WTIME_EXP),
1008 .out_state_mask = S(PPS_S_WAIT_PPS0) |
1009 S(PPS_S_WAIT_PPSS),
1010 .action = pps_wait_pX_action,
Harald Welte06348362019-05-19 00:45:17 +02001011 },
1012 [PPS_S_WAIT_PPS0] = {
1013 .name = "WAIT_PPS0",
Eric Wildad1edce2019-11-27 16:51:08 +01001014 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
1015 S(ISO7816_E_WTIME_EXP),
1016 .out_state_mask = S(PPS_S_WAIT_PPS1) |
1017 S(PPS_S_WAIT_PPS2) |
1018 S(PPS_S_WAIT_PPS3) |
1019 S(PPS_S_WAIT_PCK),
1020 .action = pps_wait_pX_action,
Harald Welte06348362019-05-19 00:45:17 +02001021 },
1022 [PPS_S_WAIT_PPS1] = {
1023 .name = "WAIT_PPS1",
Eric Wildad1edce2019-11-27 16:51:08 +01001024 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
1025 S(ISO7816_E_WTIME_EXP),
1026 .out_state_mask = S(PPS_S_WAIT_PPS2) |
1027 S(PPS_S_WAIT_PPS3) |
1028 S(PPS_S_WAIT_PCK),
1029 .action = pps_wait_pX_action,
Harald Welte06348362019-05-19 00:45:17 +02001030 },
1031 [PPS_S_WAIT_PPS2] = {
1032 .name = "WAIT_PPS2",
Eric Wildad1edce2019-11-27 16:51:08 +01001033 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
1034 S(ISO7816_E_WTIME_EXP),
1035 .out_state_mask = S(PPS_S_WAIT_PPS3) |
1036 S(PPS_S_WAIT_PCK),
1037 .action = pps_wait_pX_action,
Harald Welte06348362019-05-19 00:45:17 +02001038 },
1039 [PPS_S_WAIT_PPS3] = {
1040 .name = "WAIT_PPS3",
Eric Wildad1edce2019-11-27 16:51:08 +01001041 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
1042 S(ISO7816_E_WTIME_EXP),
1043 .out_state_mask = S(PPS_S_WAIT_PCK),
1044 .action = pps_wait_pX_action,
Harald Welte06348362019-05-19 00:45:17 +02001045 },
1046 [PPS_S_WAIT_PCK] = {
1047 .name = "WAIT_PCK",
Eric Wildad1edce2019-11-27 16:51:08 +01001048 .in_event_mask = S(ISO7816_E_RX_SINGLE) |
1049 S(ISO7816_E_WTIME_EXP),
1050 .out_state_mask = S(PPS_S_WAIT_END),
1051 .action = pps_wait_pX_action,
Harald Welte06348362019-05-19 00:45:17 +02001052 },
1053 [PPS_S_WAIT_END] = {
1054 .name = "WAIT_END",
Eric Wildad1edce2019-11-27 16:51:08 +01001055 .in_event_mask = 0,
1056 .out_state_mask = S(PPS_S_TX_PPS_REQ) |
1057 S(PPS_S_WAIT_PPSS),
Harald Welte06348362019-05-19 00:45:17 +02001058 },
1059};
1060
1061static struct osmo_fsm pps_fsm = {
1062 .name = "PPS",
1063 .states = pps_states,
1064 .num_states = ARRAY_SIZE(pps_states),
1065 .log_subsys = DPPS,
1066 .event_names = iso7816_3_event_names,
1067};
1068
1069/***********************************************************************
1070 * TPDU FSM
1071 ***********************************************************************/
1072
Harald Welte65087832019-10-01 09:16:49 +02001073/* In this FSM weu use the msgb for the TPDU as follows:
1074 * - 5-byte TPDU header is at msg->data
1075 * - COMMAND TPDU:
1076 * - command bytes are provided after the header at msg->l2h
1077 * - in case of incremental transmission, l3h points to next to-be-transmitted byte
1078 * - RESPONSE TPDU:
1079 * - any response bytes are stored after the header at msg->l2h
1080 */
1081
1082static inline struct osim_apdu_cmd_hdr *msgb_tpdu_hdr(struct msgb *msg) {
1083 return (struct osim_apdu_cmd_hdr *) msgb_data(msg);
1084}
1085
Harald Welte06348362019-05-19 00:45:17 +02001086struct tpdu_fsm_priv {
1087 struct msgb *tpdu;
Harald Welte65087832019-10-01 09:16:49 +02001088 bool is_command; /* is this a command TPDU (true) or a response (false) */
Harald Welte06348362019-05-19 00:45:17 +02001089};
1090
1091/* type-safe method to obtain iso7816_3_priv from fi */
1092static struct tpdu_fsm_priv *get_tpdu_fsm_priv(struct osmo_fsm_inst *fi)
1093{
1094 OSMO_ASSERT(fi);
1095 OSMO_ASSERT(fi->fsm == &tpdu_fsm);
1096 return (struct tpdu_fsm_priv *) fi->priv;
1097}
1098
Eric Wild9e622dc2019-11-27 14:43:16 +01001099static void tpdu_s_init_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
1100{
1101 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
1102
1103 /* notify in case card got pulled out */
Eric Wild759a6462019-11-11 14:22:52 +01001104 if (tfp->tpdu && old_state != TPDU_S_DONE){
Eric Wild9e622dc2019-11-27 14:43:16 +01001105 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_TPDU_FAILED_IND, tfp->tpdu);
1106 tfp->tpdu = 0;
1107 }
1108}
Harald Welte06348362019-05-19 00:45:17 +02001109
1110static void tpdu_s_init_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1111{
1112 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
1113 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1114 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1115 struct osim_apdu_cmd_hdr *tpduh;
1116
1117 switch (event) {
1118 case ISO7816_E_XCEIVE_TPDU_CMD:
1119 /* start transmission of a TPDU by sending the 5-byte header */
1120 tfp->tpdu = (struct msgb *)data;
1121 OSMO_ASSERT(msgb_length(tfp->tpdu) >= sizeof(*tpduh));
1122 tfp->tpdu->l2h = msgb_data(tfp->tpdu) + sizeof(*tpduh);
Harald Welte65087832019-10-01 09:16:49 +02001123 if (msgb_l2len(tfp->tpdu)) {
1124 tfp->is_command = true;
1125 tfp->tpdu->l3h = tfp->tpdu->l2h; /* next tx byte == first byte of body */
1126 } else
1127 tfp->is_command = false;
1128 tpduh = msgb_tpdu_hdr(tfp->tpdu);
1129 LOGPFSML(fi, LOGL_DEBUG, "Transmitting %s TPDU header %s via UART\n",
1130 tfp->is_command ? "COMMAND" : "RESPONSE",
Harald Welte06348362019-05-19 00:45:17 +02001131 osmo_hexdump_nospc((uint8_t *) tpduh, sizeof(*tpduh)));
1132 osmo_fsm_inst_state_chg(fi, TPDU_S_TX_HDR, 0, 0);
Harald Welte6603d952019-10-09 20:50:13 +02001133 card_uart_tx(ip->uart, (uint8_t *) tpduh, sizeof(*tpduh), true);
Harald Welte06348362019-05-19 00:45:17 +02001134 break;
1135 default:
1136 OSMO_ASSERT(0);
1137 }
1138}
1139
Eric Wild9a2279c2019-11-27 18:30:18 +01001140#include <hal_gpio.h>
Harald Welte06348362019-05-19 00:45:17 +02001141static void tpdu_s_tx_hdr_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1142{
1143 OSMO_ASSERT(fi->fsm == &tpdu_fsm);
1144 switch (event) {
1145 case ISO7816_E_TX_COMPL:
1146 /* Rx of single byte is already enabled by previous card_uart_tx() call */
1147 osmo_fsm_inst_state_chg(fi, TPDU_S_PROCEDURE, 0, 0);
1148 break;
1149 default:
1150 OSMO_ASSERT(0);
1151 }
1152}
1153
1154
1155
1156static void tpdu_s_procedure_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1157{
1158 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
Harald Welte65087832019-10-01 09:16:49 +02001159 struct osim_apdu_cmd_hdr *tpduh = msgb_tpdu_hdr(tfp->tpdu);
Harald Welte06348362019-05-19 00:45:17 +02001160 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1161 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1162 uint8_t byte;
1163
1164 switch (event) {
1165 case ISO7816_E_RX_SINGLE:
1166 byte = get_rx_byte_evt(fi->proc.parent, data);
1167 LOGPFSML(fi, LOGL_DEBUG, "Received 0x%02x from UART\n", byte);
1168 if (byte == 0x60) {
1169 /* NULL: wait for another procedure byte */
1170 osmo_fsm_inst_state_chg(fi, TPDU_S_PROCEDURE, 0, 0);
1171 } else if ((byte >= 0x60 && byte <= 0x6f) || (byte >= 0x90 && byte <= 0x9f)) {
1172 //msgb_apdu_sw(tfp->apdu) = byte << 8;
1173 msgb_put(tfp->tpdu, byte);
1174 /* receive second SW byte (SW2) */
1175 osmo_fsm_inst_state_chg(fi, TPDU_S_SW2, 0, 0);
1176 break;
1177 } else if (byte == tpduh->ins) {
Harald Welte65087832019-10-01 09:16:49 +02001178 if (tfp->is_command) {
Harald Welte06348362019-05-19 00:45:17 +02001179 /* transmit all remaining bytes */
Eric Wild9a2279c2019-11-27 18:30:18 +01001180#if 0
1181// rx -> tx delay
1182 gpio_set_pin_level(PIN_PB12, true);
1183 delay_us(1);
1184 gpio_set_pin_level(PIN_PB12, false);
1185#endif
Harald Welte6603d952019-10-09 20:50:13 +02001186 card_uart_tx(ip->uart, msgb_l2(tfp->tpdu), msgb_l2len(tfp->tpdu), true);
Harald Welte06348362019-05-19 00:45:17 +02001187 osmo_fsm_inst_state_chg(fi, TPDU_S_TX_REMAINING, 0, 0);
1188 } else {
1189 card_uart_set_rx_threshold(ip->uart, tpduh->p3);
1190 osmo_fsm_inst_state_chg(fi, TPDU_S_RX_REMAINING, 0, 0);
1191 }
1192 } else if (byte == (tpduh->ins ^ 0xFF)) {
Harald Welte65087832019-10-01 09:16:49 +02001193 /* transmit/recieve single byte then wait for proc */
1194 if (tfp->is_command) {
1195 /* transmit *next*, not first byte */
1196 OSMO_ASSERT(msgb_l3len(tfp->tpdu) >= 0);
Harald Welte6603d952019-10-09 20:50:13 +02001197 card_uart_tx(ip->uart, msgb_l3(tfp->tpdu), 1, false);
Harald Welte65087832019-10-01 09:16:49 +02001198 osmo_fsm_inst_state_chg(fi, TPDU_S_TX_SINGLE, 0, 0);
1199 } else {
1200 osmo_fsm_inst_state_chg(fi, TPDU_S_RX_SINGLE, 0, 0);
1201 }
Harald Welte06348362019-05-19 00:45:17 +02001202 } else
1203 OSMO_ASSERT(0);
1204 break;
1205 default:
1206 OSMO_ASSERT(0);
1207 }
1208}
1209
1210/* UART is transmitting remaining data; we wait for ISO7816_E_TX_COMPL */
1211static void tpdu_s_tx_remaining_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1212{
1213 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1214 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1215
1216 switch (event) {
1217 case ISO7816_E_TX_COMPL:
1218 card_uart_set_rx_threshold(ip->uart, 1);
1219 osmo_fsm_inst_state_chg(fi, TPDU_S_SW1, 0, 0);
1220 break;
1221 default:
1222 OSMO_ASSERT(0);
1223 }
1224}
1225
1226/* UART is transmitting single byte of data; we wait for ISO7816_E_TX_COMPL */
1227static void tpdu_s_tx_single_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1228{
Harald Welte65087832019-10-01 09:16:49 +02001229 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
1230
Harald Welte06348362019-05-19 00:45:17 +02001231 switch (event) {
1232 case ISO7816_E_TX_COMPL:
Harald Welte65087832019-10-01 09:16:49 +02001233 tfp->tpdu->l3h += 1;
1234 if (msgb_l3len(tfp->tpdu))
1235 osmo_fsm_inst_state_chg(fi, TPDU_S_PROCEDURE, 0, 0);
1236 else
1237 osmo_fsm_inst_state_chg(fi, TPDU_S_SW1, 0, 0);
Harald Welte06348362019-05-19 00:45:17 +02001238 break;
1239 default:
1240 OSMO_ASSERT(0);
1241 }
1242}
1243
1244/* UART is receiving remaining data; we wait for ISO7816_E_RX_COMPL */
1245static void tpdu_s_rx_remaining_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1246{
1247 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
Harald Welte65087832019-10-01 09:16:49 +02001248 struct osim_apdu_cmd_hdr *tpduh = msgb_tpdu_hdr(tfp->tpdu);
Harald Welte06348362019-05-19 00:45:17 +02001249 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1250 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1251 int rc;
1252
1253 switch (event) {
1254 case ISO7816_E_RX_COMPL:
1255 /* retrieve pending byte(s) */
1256 rc = card_uart_rx(ip->uart, msgb_l2(tfp->tpdu), tpduh->p3);
Harald Welte65087832019-10-01 09:16:49 +02001257 OSMO_ASSERT(rc > 0);
1258 msgb_put(tfp->tpdu, rc);
1259 if (msgb_l2len(tfp->tpdu) != tpduh->p3) {
1260 LOGPFSML(fi, LOGL_ERROR, "expected %u bytes; read %d\n", tpduh->p3,
1261 msgb_l2len(tfp->tpdu));
1262 }
Harald Welte06348362019-05-19 00:45:17 +02001263 card_uart_set_rx_threshold(ip->uart, 1);
1264 osmo_fsm_inst_state_chg(fi, TPDU_S_SW1, 0, 0);
1265 break;
1266 default:
1267 OSMO_ASSERT(0);
1268 }
1269}
1270
1271/* UART is receiving single byte of data; we wait for ISO7816_E_RX_SINGLE */
1272static void tpdu_s_rx_single_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1273{
1274 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
Harald Welte65087832019-10-01 09:16:49 +02001275 struct osim_apdu_cmd_hdr *tpduh = msgb_tpdu_hdr(tfp->tpdu);
Harald Welte06348362019-05-19 00:45:17 +02001276 uint8_t byte;
1277
1278 switch (event) {
1279 case ISO7816_E_RX_SINGLE:
1280 byte = get_rx_byte_evt(fi->proc.parent, data);
1281 LOGPFSML(fi, LOGL_DEBUG, "Received 0x%02x from UART\n", byte);
Harald Welte65087832019-10-01 09:16:49 +02001282 msgb_put_u8(tfp->tpdu, byte);
1283 /* determine if number of expected bytes received */
1284 if (msgb_l2len(tfp->tpdu) == tpduh->p3)
Harald Welte06348362019-05-19 00:45:17 +02001285 osmo_fsm_inst_state_chg(fi, TPDU_S_SW1, 0, 0);
Harald Welte65087832019-10-01 09:16:49 +02001286 else
Harald Welte06348362019-05-19 00:45:17 +02001287 osmo_fsm_inst_state_chg(fi, TPDU_S_PROCEDURE, 0, 0);
1288 break;
1289 default:
1290 OSMO_ASSERT(0);
1291 }
1292}
1293
1294static void tpdu_s_sw1_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1295{
1296 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
1297 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1298 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1299 uint8_t byte;
1300
1301 switch (event) {
1302 case ISO7816_E_RX_SINGLE:
1303 byte = get_rx_byte_evt(fi->proc.parent, data);
1304 LOGPFSML(fi, LOGL_DEBUG, "Received 0x%02x from UART\n", byte);
1305 /* record byte */
1306 //msgb_apdu_sw(tfp->apdu) = byte << 8;
1307 msgb_put_u8(tfp->tpdu, byte);
1308 card_uart_set_rx_threshold(ip->uart, 1);
1309 osmo_fsm_inst_state_chg(fi, TPDU_S_SW2, 0, 0);
1310 break;
1311 default:
1312 OSMO_ASSERT(0);
1313 }
1314}
1315
1316static void tpdu_s_sw2_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1317{
1318 struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
1319 struct osmo_fsm_inst *parent_fi = fi->proc.parent;
1320 struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
1321 uint8_t byte;
1322
1323 switch (event) {
1324 case ISO7816_E_RX_SINGLE:
1325 byte = get_rx_byte_evt(fi->proc.parent, data);
1326 LOGPFSML(fi, LOGL_DEBUG, "Received 0x%02x from UART\n", byte);
1327 /* record SW2 byte */
1328 //msgb_apdu_sw(tfp->apdu) &= 0xFF00;
1329 //msgb_apdu_sw(tfp->apdu) |= byte;
1330 msgb_put_u8(tfp->tpdu, byte);
1331 osmo_fsm_inst_state_chg(fi, TPDU_S_DONE, 0, 0);
1332 /* Notify parent FSM */
1333 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_TPDU_DONE_IND, tfp->tpdu);
Eric Wild9e622dc2019-11-27 14:43:16 +01001334
1335 /* ownership transfer */
1336 tfp->tpdu = 0;
Harald Welte06348362019-05-19 00:45:17 +02001337 break;
1338 default:
1339 OSMO_ASSERT(0);
1340 }
1341}
1342
1343static void tpdu_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1344{
1345 OSMO_ASSERT(fi->fsm == &tpdu_fsm);
1346
1347 switch (event) {
1348 case ISO7816_E_RX_ERR_IND:
1349 case ISO7816_E_TX_ERR_IND:
1350 /* FIXME: handle this in some different way */
1351 osmo_fsm_inst_state_chg(fi, TPDU_S_DONE, 0, 0);
1352 osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_TPDU_DONE_IND, NULL);
1353 break;
1354 case ISO7816_E_TPDU_CLEAR_REQ:
1355 osmo_fsm_inst_state_chg(fi, TPDU_S_INIT, 0, 0);
1356 break;
1357 }
1358}
1359
1360static const struct osmo_fsm_state tpdu_states[] = {
1361 [TPDU_S_INIT] = {
1362 .name = "INIT",
1363 .in_event_mask = S(ISO7816_E_XCEIVE_TPDU_CMD) |
1364 S(ISO7816_E_TX_COMPL),
1365 .out_state_mask = S(TPDU_S_INIT) |
1366 S(TPDU_S_TX_HDR),
1367 .action = tpdu_s_init_action,
Eric Wild9e622dc2019-11-27 14:43:16 +01001368 .onenter = tpdu_s_init_onenter,
Harald Welte06348362019-05-19 00:45:17 +02001369 },
1370 [TPDU_S_TX_HDR] = {
1371 .name = "TX_HDR",
1372 .in_event_mask = S(ISO7816_E_TX_COMPL),
1373 .out_state_mask = S(TPDU_S_INIT) |
1374 S(TPDU_S_PROCEDURE),
1375 .action = tpdu_s_tx_hdr_action,
1376 },
1377 [TPDU_S_PROCEDURE] = {
1378 .name = "PROCEDURE",
1379 .in_event_mask = S(ISO7816_E_RX_SINGLE),
1380 .out_state_mask = S(TPDU_S_INIT) |
1381 S(TPDU_S_PROCEDURE) |
1382 S(TPDU_S_RX_REMAINING) |
1383 S(TPDU_S_RX_SINGLE) |
1384 S(TPDU_S_TX_REMAINING) |
1385 S(TPDU_S_TX_SINGLE) |
1386 S(TPDU_S_SW2),
1387 .action = tpdu_s_procedure_action,
1388 },
1389 [TPDU_S_TX_REMAINING] = {
1390 .name = "TX_REMAINING",
1391 .in_event_mask = S(ISO7816_E_TX_COMPL),
1392 .out_state_mask = S(TPDU_S_INIT) |
1393 S(TPDU_S_SW1),
1394 .action = tpdu_s_tx_remaining_action,
1395 },
1396 [TPDU_S_TX_SINGLE] = {
1397 .name = "TX_SINGLE",
1398 .in_event_mask = S(ISO7816_E_TX_COMPL),
1399 .out_state_mask = S(TPDU_S_INIT) |
1400 S(TPDU_S_PROCEDURE),
1401 .action = tpdu_s_tx_single_action,
1402 },
1403 [TPDU_S_RX_REMAINING] = {
1404 .name = "RX_REMAINING",
1405 .in_event_mask = S(ISO7816_E_RX_COMPL),
1406 .out_state_mask = S(TPDU_S_INIT) |
1407 S(TPDU_S_SW1),
1408 .action = tpdu_s_rx_remaining_action,
1409 },
1410 [TPDU_S_RX_SINGLE] = {
1411 .name = "RX_SINGLE",
1412 .in_event_mask = S(ISO7816_E_RX_SINGLE),
1413 .out_state_mask = S(TPDU_S_INIT) |
1414 S(TPDU_S_PROCEDURE),
1415 .action = tpdu_s_rx_single_action,
1416 },
1417 [TPDU_S_SW1] = {
1418 .name = "SW1",
1419 .in_event_mask = S(ISO7816_E_RX_SINGLE),
1420 .out_state_mask = S(TPDU_S_INIT) |
1421 S(TPDU_S_SW2),
1422 .action = tpdu_s_sw1_action,
1423 },
1424 [TPDU_S_SW2] = {
1425 .name = "SW2",
1426 .in_event_mask = S(ISO7816_E_RX_SINGLE),
1427 .out_state_mask = S(TPDU_S_INIT) |
1428 S(TPDU_S_DONE),
1429 .action = tpdu_s_sw2_action,
1430 },
1431 [TPDU_S_DONE] = {
1432 .name = "DONE",
1433 .in_event_mask = 0,
1434 .out_state_mask = S(TPDU_S_INIT),
1435 .action = NULL,
1436 },
1437};
1438static struct osmo_fsm tpdu_fsm = {
1439 .name = "TPDU",
1440 .states = tpdu_states,
1441 .num_states = ARRAY_SIZE(tpdu_states),
1442 .allstate_event_mask = S(ISO7816_E_RX_ERR_IND) |
1443 S(ISO7816_E_TX_ERR_IND) |
1444 S(ISO7816_E_TPDU_CLEAR_REQ),
1445 .allstate_action = tpdu_allstate_action,
1446 .log_subsys = DTPDU,
1447 .event_names = iso7816_3_event_names,
1448};
1449
1450struct osmo_fsm_inst *iso7816_fsm_alloc(void *ctx, int log_level, const char *id,
1451 struct card_uart *cuart, iso7816_user_cb user_cb,
1452 void *user_priv)
1453{
1454 struct iso7816_3_priv *ip;
1455 struct osmo_fsm_inst *fi;
1456
1457 fi = osmo_fsm_inst_alloc(&iso7816_3_fsm, ctx, NULL, log_level, id);
1458 ip = talloc_zero(fi, struct iso7816_3_priv);
1459 if (!ip)
1460 goto out_fi;
1461 fi->priv = ip;
1462
1463 ip->uart = cuart;
1464 cuart->priv = fi;
1465 cuart->handle_event = tpdu_uart_notification;
1466
1467 ip->user_cb = user_cb;
1468 ip->user_priv = user_priv;
1469
1470 ip->atr_fi = osmo_fsm_inst_alloc_child(&atr_fsm, fi, ISO7816_E_SW_ERR_IND);
1471 if (!ip->atr_fi)
1472 goto out_fi;
1473 ip->atr_fi->priv = talloc_zero(ip->atr_fi, struct atr_fsm_priv);
1474 if (!ip->atr_fi->priv)
1475 goto out_atr;
1476
1477 ip->tpdu_fi = osmo_fsm_inst_alloc_child(&tpdu_fsm, fi, ISO7816_E_SW_ERR_IND);
1478 if (!ip->tpdu_fi)
1479 goto out_atr;
1480 ip->tpdu_fi->priv = talloc_zero(ip->tpdu_fi, struct tpdu_fsm_priv);
1481 if (!ip->tpdu_fi->priv)
1482 goto out_tpdu;
1483
Eric Wildad1edce2019-11-27 16:51:08 +01001484#if 1
Harald Welte06348362019-05-19 00:45:17 +02001485 ip->pps_fi = osmo_fsm_inst_alloc_child(&pps_fsm, fi, ISO7816_E_SW_ERR_IND);
1486 if (!ip->pps_fi)
1487 goto out_tpdu;
1488 ip->pps_fi->priv = talloc_zero(ip->pps_fi, struct pps_fsm_priv);
1489 if (!ip->pps_fi->priv)
1490 goto out_pps;
1491#endif
1492
1493 /* This ensures the 'onenter' function of the initial state is called */
1494 osmo_fsm_inst_state_chg(fi, ISO7816_S_RESET, 0, 0);
1495
1496 return fi;
1497
Eric Wildad1edce2019-11-27 16:51:08 +01001498#if 1
Harald Welte06348362019-05-19 00:45:17 +02001499out_pps:
1500 osmo_fsm_inst_free(ip->pps_fi);
1501#endif
1502out_tpdu:
1503 osmo_fsm_inst_free(ip->tpdu_fi);
1504out_atr:
1505 osmo_fsm_inst_free(ip->atr_fi);
1506out_fi:
1507 osmo_fsm_inst_free(fi);
1508 cuart->priv = NULL;
1509 return NULL;
1510}
1511
1512void *iso7816_fsm_get_user_priv(struct osmo_fsm_inst *fi)
1513{
1514 struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
1515 return ip->user_priv;
1516}
1517
1518
1519static __attribute__((constructor)) void on_dso_load_iso7816(void)
1520{
1521 osmo_fsm_register(&iso7816_3_fsm);
1522 osmo_fsm_register(&atr_fsm);
1523 osmo_fsm_register(&tpdu_fsm);
1524 osmo_fsm_register(&pps_fsm);
1525}