| /* Minimal test program for the ISO7816-3 FSM |
| * expects a Smart Card attached to a UART reachable as /dev/ttyXXX |
| * |
| * (C) 2019-2020 by Harald Welte <laforge@gnumonks.org> |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA |
| */ |
| |
| #include <unistd.h> |
| #include <stdio.h> |
| #include <errno.h> |
| #include <signal.h> |
| #include <osmocom/core/utils.h> |
| #include <osmocom/core/logging.h> |
| #include <osmocom/core/application.h> |
| #include <osmocom/core/msgb.h> |
| #include <osmocom/sim/sim.h> |
| |
| #include "logging.h" |
| #include "cuart.h" |
| #include "iso7816_fsm.h" |
| |
| static struct card_uart g_cuart; |
| |
| enum test_state { |
| ST_WAIT_ATR, |
| ST_ATR_DONE, |
| ST_IN_TPDU, |
| }; |
| static enum test_state g_tstate = ST_WAIT_ATR; |
| |
| static void fsm_user_cb(struct osmo_fsm_inst *fi, int event, int cause, void *data) |
| { |
| printf("Handle FSM User Event %d: cause=%d, data=%p\n", event, cause, data); |
| switch (event) { |
| case ISO7816_E_ATR_DONE_IND: |
| g_tstate = ST_ATR_DONE; |
| break; |
| case ISO7816_E_TPDU_DONE_IND: |
| printf("======= TPDU: %s\n", msgb_hexdump(data)); |
| msgb_free(data); |
| g_tstate = ST_ATR_DONE; |
| default: |
| break; |
| } |
| } |
| |
| static void *g_tall_ctx; |
| |
| static void signal_handler(int signal) |
| { |
| switch (signal) { |
| case SIGUSR1: |
| talloc_report_full(g_tall_ctx, stderr); |
| break; |
| } |
| } |
| |
| int main(int argc, char **argv) |
| { |
| struct osmo_fsm_inst *fi; |
| uint8_t atr[64]; |
| int rc; |
| |
| g_tall_ctx = talloc_named_const(NULL, 0, "main"); |
| msgb_talloc_ctx_init(g_tall_ctx, 0); |
| osmo_init_logging2(g_tall_ctx, &log_info); |
| osmo_fsm_log_addr(false); |
| |
| signal(SIGUSR1, &signal_handler); |
| |
| if (argc < 2) { |
| fprintf(stderr, "You must specify the UART tty device as argument\n"); |
| exit(2); |
| } |
| |
| printf("Opening UART device %s\n", argv[1]); |
| |
| rc = card_uart_open(&g_cuart, "tty", argv[1]); |
| if (rc < 0) { |
| perror("opening UART"); |
| exit(1); |
| } |
| |
| fi = iso7816_fsm_alloc(NULL, LOGL_DEBUG, "SIM0", &g_cuart, fsm_user_cb, NULL); |
| OSMO_ASSERT(fi); |
| |
| /* activate reset, then power up */ |
| card_uart_ctrl(&g_cuart, CUART_CTL_RST, true); |
| card_uart_ctrl(&g_cuart, CUART_CTL_POWER_1V8, true); |
| osmo_fsm_inst_dispatch(fi, ISO7816_E_POWER_UP_IND, NULL); |
| |
| /* activate clock */ |
| card_uart_ctrl(&g_cuart, CUART_CTL_CLOCK, true); |
| |
| /* wait some time and release reset */ |
| usleep(10000); |
| card_uart_ctrl(&g_cuart, CUART_CTL_RST, false); |
| osmo_fsm_inst_dispatch(fi, ISO7816_E_RESET_REL_IND, NULL); |
| |
| /* process any events in polling mode for initial change */ |
| osmo_select_main(1); |
| |
| struct msgb *apdu; |
| while (1) { |
| /* check if the new state requires us to do something */ |
| switch (g_tstate) { |
| case ST_ATR_DONE: |
| apdu = msgb_alloc(512, "TPDU"); |
| msgb_put_u8(apdu, 0x00); |
| msgb_put_u8(apdu, 0xa4); |
| msgb_put_u8(apdu, 0x00); |
| msgb_put_u8(apdu, 0x04); |
| msgb_put_u8(apdu, 0x02); |
| msgb_put_u8(apdu, 0x2f); |
| msgb_put_u8(apdu, 0x00); |
| osmo_fsm_inst_dispatch(fi, ISO7816_E_XCEIVE_TPDU_CMD, apdu); |
| g_tstate = ST_IN_TPDU; |
| break; |
| default: |
| break; |
| } |
| osmo_select_main(0); |
| } |
| |
| exit(0); |
| } |