48 Commits

Author SHA1 Message Date
Kévin Redon
b149ea3039 cardem: ignore set ATR
the PPS procedure with baud rate change has not been tested.
by keeping the default ATR instead of applying the ATR sent by
the host software, no other baud rate choice is offered.

Change-Id: Ibf7c6b83d2cf68172c7aa25116d838e24a95d5fe
2019-09-24 17:48:33 +02:00
Kévin Redon
6b0afb3761 cardem: fix TPDU state check
this change allows to initialize the TPDU state while in
ISO_S_WAIT_TPDU, before actually entering ISO_S_TPDU

Change-Id: I505d3add32a43de31499b800bc53442f99f65931
2019-09-24 17:45:16 +02:00
Kévin Redon
90abc09cf3 cardem: ensure VCC_PHONE is floating
this change is mainly relevant for the SIMtrace board, but also
affects the others.
First we ensure VCC_PHONE is not forwarded to VCC_SIM because the
card could affect the signal (card could draw too much current or
feed back current in).
next we disable VCC_SIM. the card slot does not need to be
powered, and the FPF2019 leaks current back to VCC_PHONE, even
with forwarding disabled (the reverse current protection only
kicks in when VCC_PHONE is briefly shorted to ground, but still
leaks 0.6V).
enable the ADC channels normally used to measure VCC, even if
not used. the dedicated ADC pins leak current when left
unconfigured. enabling them puts them in high impedance.

Change-Id: If1487c1c191838aaa08b654e49cd31c7180ffc19
2019-07-18 18:50:58 +02:00
Kévin Redon
76c2eebae2 cardem: use USART timeout for waiting time
the reset/ATR handling has been heavily updated/fixed.
instead of using the timer counter peripheral to handle
the waiting time and corresponding timeout, the USART peripheral
internal timeout mechanism is used.
this is particularly important for the SIMtrace board since the
clock signal is not connected to the timer counter.
thus this change adds card emulation support for SIMtrace boards.

Fi and Di have been properly rename to F and D since the "i"
stands only for an "indicated" value, not the actual value.
this does not change the USB protocol (the variable have just been
renamed).
additional variables store more information about the card
capabilities

NOTE: it has only be tested for the SIMtrace board

Change-Id: Ibcb2c8cace9137695adf5fb3de43566f7cfb93b5
2019-07-18 16:10:34 +02:00
Kévin Redon
e3d516745d make: only compile source for corresponding app
since simtrace supports multiple application, but currently not
at the same time, the feature support is not app specific

Change-Id: I98ff92450cc2a247b294d2e15df171f3fe7c5156
2019-06-13 17:30:41 +02:00
Kévin Redon
0cbe9a4fb6 cardem: currently simtrace does not support cardem
the SIMtrace board does not support the current card emulation
application because this uses a timer counter to handle the
timeouts, but on the SIMtrace board this is not connected to the
CLK signal

Change-Id: Idd09ea534179f0ede705573e1373dbd045c9828a
2019-06-13 17:17:43 +02:00
Kévin Redon
1a88fd8066 use simplest ATR
this is the shortest and simplest ATR possible according to the
ISO 7816-3 spec.
it does not offer any non-default parameters (F, D, WI, ...)

Change-Id: I4ff41b5120bcadca652296f9d3691f7606be2bd2
2019-05-15 00:23:31 +02:00
Kévin Redon
73d4d49b83 minor: ignore usbstring binary
Change-Id: I18fc3179f8b7f3f1272d26853007876156fc1e03
2019-05-14 23:56:07 +02:00
Kévin Redon
558f25237e make sim switch board specific
the simtrace board uses a bus switch not used on qmod and owhw to
switch the SIM between physical and virtual

Change-Id: Ieaf2ed4761fc3e04f33f9aac5c04a768c9a6f71e
2019-05-14 23:39:42 +02:00
Kévin Redon
7fd7674577 minor add comments
this is just to better understand the flow

Change-Id: I045286836176da729cc8c863866d6f6aa3836592
2019-05-14 23:32:55 +02:00
Kévin Redon
7a060da30f rename PIN_PHONE_IO to PIN_USIM1_IO
this matches the naming scheme used for USIM2

Change-Id: I486b14260faec897e8c8698c4b7987bf36492497
2019-05-14 23:23:47 +02:00
Kévin Redon
5b2ade08dd better detect VCC and nRST changes
monitoring the state changes of the VCC and nRST lines is required
to correctly detect warm and cold reset

Change-Id: I72099956332724f84226e1495fdc5a5b1a034695
2019-05-14 23:20:26 +02:00
Kévin Redon
6470d999b7 add ISO 7816-3 library to remsim project
Change-Id: I99f3fecbc00d2379c3a6dc457b047c6fee41c292
2019-05-14 21:56:45 +02:00
Kévin Redon
46a1f167f7 add library providing ISO 7816-3 utilities
this will become part of libosmocore since it it common to smart
card related projects (such as osmo-ccid-firmware)

Change-Id: I3d4c65d137fc4555fcb256443feadd1c695de73d
2019-05-14 21:50:45 +02:00
Kévin Redon
0954e3b283 minor : fix typo in comment
Change-Id: Ie310143fe713a51fa1adf8bf7599374282341f2e
2019-05-14 21:26:48 +02:00
Kévin Redon
c2a3836777 minor: improve debug output
Change-Id: Ibfc22b95c0be3ac78bd50a40e31cc7d8546d81d9
2019-02-07 18:20:20 +01:00
Kévin Redon
a2b2df235a remsim: use simplest ATR
this ATR does not encode any data and uses all defaults.
the lower default speed is also better handled by the hardware.
handling faster speeds is upcoming.

Change-Id: I5a4f2f94bea1a15aedbef5a6f2f49344387dc11d
2019-02-07 18:01:23 +01:00
Kévin Redon
af7544aa9d minor: move USB debug output from info to debug level
else it's too nosy while debugging other components, not often
used, and break the flow since it does not and a line.

Change-Id: I8920ff7c33b4c9fb174bb31a29334a63fcbede43
2019-02-07 17:58:26 +01:00
Kévin Redon
f6f507ab3c minor: make debug output only verbose in info level
the longer output is to fast and often incomplete.
the shorter version is enough to view the progress when not
debugging.

Change-Id: I97bb84da68d1f3bc14fb7c05400edf1748f55460
2019-02-07 17:55:28 +01:00
Kévin Redon
844c6608cf minor: use same LED pattern for cardem as other opplications
Change-Id: I5608c3312b648c0d59f79338ef1f97b6fe08f5b9
2019-02-07 17:53:18 +01:00
Kévin Redon
8ed780ec35 minor: updated copyright years
Change-Id: I9254b1ddf6436b5a4964b9124a36ae17bfc22886
2019-02-07 17:52:08 +01:00
Kévin Redon
ad3414fdf7 minor: fix spacing
Change-Id: I2f3127c7b276c9726fd0242e3e29be22f9d6255c
2019-02-07 17:42:29 +01:00
Kévin Redon
2fdcf3b38d cardem: add more debug information for TPDU state
this just adds the name of the TPDU state on top of the state number.

the ISO state is cleaned up accordingly

Change-Id: Id5104a2c3579dedb092c179748e9ed525673841c
2018-10-25 10:42:33 +02:00
Kévin Redon
7e5cda5732 remsim: fix TPDU response size transmission
the TDPU response data size can be up to 256.
this length cannot be stored in a uint8_t, which would cause the
length to become 0, no data being send, and the reader reset the
card because of misbehaviour of the card (i.e. no/malformed
response leading to the timeout of the waiting time).

Change-Id: Iae7671085aaa3115a02d82530dd7a0e7e2d4155e
2018-10-21 12:29:26 +00:00
Kévin Redon
032fc5f844 remsim: update copyright
Change-Id: Ibcf093877ee53f8446c97bfa50c8370ceda24c53
2018-10-21 12:29:10 +00:00
Kévin Redon
b1f99c909c remsim: add already parsed USB path argument info
Change-Id: I03de93ebb92b1d1b5004cbe865cdf1fa0b2b23ac
2018-10-21 12:29:10 +00:00
Martin Hauke
53b4e593aa Fix compiler warning: no-return-in-nonvoid-function simtrace2_usb.c
RPM post-build-checks found some issue and marks these as error:
[   61s] I: Program returns random data in a function
[   61s] E: simtrace2 no-return-in-nonvoid-function simtrace2_usb.c:88

Change-Id: Id16fb7fc4f13176b2b6443af02a5848d8fcfb069
2018-10-13 22:14:06 +00:00
Harald Welte
dc85fbc3e1 libusb_util.c: Avoid gcc warning about strncpy()
What we're doing is actually legal: We copy the full size of the
destination array, and then overwrite the last byte with NUL.  However,
gcc isn't smart enough to see that:

libusb_util.c:162:5: warning: ‘strncpy’ specified bound 20 equals destination size [-Wstringop-truncation]
     strncpy(out[out_idx].path, path, sizeof(out[out_idx].path));
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Let's copy one byte less to make it happy.

Change-Id: I30ddacdc73e5245c7c38b92d1e94e39b13fae7d3
2018-10-12 15:15:08 +02:00
Harald Welte
66ffb6d493 debian/control: Add dependency to libpcsclite-dev
The host utilities use libpcsclite, and the missing build dependency
causes build failures in our nightly OBS builds since commit
faf1e88e48 was merged:

[  131s] cc -o simtrace2-remsim simtrace2-remsim.o apdu_dispatch.o simtrace2-discovery.o libusb_util.o -Wl,-z,relro `pkg-config --libs libusb-1.0 libosmocore` -pthread `pkg-config --libs libosmosim libpcsclite`
[  131s] Package libpcsclite was not found in the pkg-config search path.
[  131s] Perhaps you should add the directory containing `libpcsclite.pc'
[  131s] to the PKG_CONFIG_PATH environment variable
[  131s] No package 'libpcsclite' found

Change-Id: I29adfc629e5e4ffd0bf8b9035ef9138fe7693d96
2018-09-23 16:59:23 +02:00
Kévin Redon
5b5d24ebf3 owhw: set the right simtrace USB ID in usb2udp
Change-Id: I0b54c2eb98b3fad1e2afaf9b81fbe4518b01fbda
2018-09-08 08:22:56 +02:00
Kévin Redon
faf1e88e48 host: clean library dependencies
remsim also needs libpcsclite
`pkg-config --libs libosmocore` and -losmocore are duplicates
`pkg-config --libs libosmosim` is equivalent to -losmosim
pthread it needed (by most applications) for static compilation
LDFLAGS+= allows static compilation when running
LDFLAGS="-static" make

Change-Id: Ic7bd6f2be074d6f652d4f84f4996c8588ea5f851
2018-09-06 23:15:44 +02:00
Kévin Redon
64f69fc4ac owhw: add missing function board_main_top
the board_main_top function was not defined, causing a hard fault
when initializing the board

Change-Id: Ib92003416648822c4115472992850c592bc4047a
2018-09-06 22:52:45 +02:00
Kévin Redon
6303c39a00 owhw: add missing function board_exec_dbg_cmd
the board_exec_dbg_cmd function was not defined, causing a hard
fault on user input

Change-Id: I3ecc1f7bdb2484f5a67c36163d33ebc065e4e709
2018-09-06 22:51:32 +02:00
Kévin Redon
ad0958e9e3 minor: update copyright
Change-Id: Iafcd029be9b3f8cf2e90f08d5e9802912d6a59b1
2018-09-06 22:49:56 +02:00
Kévin Redon
4f3a0356a4 minor: fix typo in comment
Change-Id: I3edb50abe93bc8574c9c1f25b34f75dab2e8f0ce
2018-09-06 22:48:11 +02:00
Kévin Redon
7d5d011095 minor: add checks on configurations and functions
these checks prevent out of bounds access and running
unset function pointers.

Change-Id: Ida889d40b898fc1ab8b885800431833570fdaafe
2018-09-06 22:47:01 +02:00
Kévin Redon
1dbcf62295 qmod: add LED user control
this is used during board testing

Change-Id: I4ccd787f6e307f523821725de158e3c6f1508ee2
2018-09-04 16:15:15 +02:00
Kévin Redon
e5f891a825 EEPROM: fix Wformat compile warning
Change-Id: I86434a46a75f2acc30e20c33edab6dd3f87e052b
2018-09-04 13:31:26 +02:00
Kévin Redon
a6bd7178b5 qmod: output EEPROM data only on debug level, and add completion output
the EEPROM byte output was causing data loss on the serial output,
resulting is automatic tests failing.
instead an end text will be output to detect the end of the procedure.

Change-Id: Ib8d3cbd01d0e34432d424355f4fafb24bc5273a1
2018-09-03 21:11:44 +02:00
Kévin Redon
ba15387b09 DFU: fix Wformat compile warning
Change-Id: I8c422d8a709f8311c40d37e1f1f01dcd3a199b6f
2018-09-03 21:11:44 +02:00
Kévin Redon
c171112994 stdio: fix detection of malformated format strings
the error code returned by vsnprintf was ignored,
resulting in printing the string from a previous print.

Change-Id: I8506b05d56da55d1357a1234917adf341b46e1db
2018-09-03 21:10:58 +02:00
Kévin Redon
29200c6223 stdio: add void 'l' format string qualifier
Wformat requires uint32_t to be used in format string with the 'l'
qualifier (l = long = at least 32 bits).
this qualifier was not handled before.
since on ARM 32-bit int == long we can simply ignore it (stdio
already does not support 64-bit data).

Change-Id: Ib506a66f68712c6b3eeb5129a39abf47ec86a2a7
2018-08-28 19:43:37 +02:00
Kévin Redon
80d9476602 UART: switch baud rate to 921600 bps
the higher baud rate allows for more debugging (without dropping
data) and is well supported by USB for UART adapters (this
standard baud rate is 8 x 115200).
the closest matching integer value is calculated for UART CR.
no floating point calculation can be used since this would
increase the size of the resulting binary by ~ 2kB (for the
softfp). this is not possible for the DFU since it already is
close to the maximum size of 16 kB.

Change-Id: I82b74f697342d580ccb79ada4715f35f4e8cca86
2018-08-28 19:19:10 +02:00
Kévin Redon
e2b0f971e5 set main clock for using UART at 921600 bps
UART baud rate is main clock (MCK) divided by CR*16.
The MCK values are chosen >= 48 MHz and <= 64 MHz to have a near
integer value CR for a baud rate of 921600 bps.
The end MCK frequency between simtrace and qmod differ slightly
but are close to 58 MHz.

Change-Id: Iaa4a97fc68494c93b9d128503515d88049de506c
2018-08-28 19:13:13 +02:00
Harald Welte
e07640c35a tag debian release 0.5.1
Change-Id: Id6559b1019353815eea9f6653b6560e9a8aab23a
2018-08-26 11:51:13 +02:00
Harald Welte
82b628524f simtrace2-sniff: Fix build with released libosmocore versions
There's still no released libosmocore defining the GSMTAP_TYPE_SIM
sub-types (Change-Id: I5bd0dff5a4a90cfe96d9c4f3dec6657e1d85bf7a
dated Jul 26, 2018).

Let's make sure users don't need an unreleased version of the library
if it's only about a few #defines that we can just copy here for
backwards compatibility.

Change-Id: I2fd9e14873711d60f194bb404420bbfbb0a00f48
2018-08-26 11:43:12 +02:00
Harald Welte
cb78b55c26 Revert "debian/control: Depend on libosmocore >= 0.12.1"
This reverts commit 77ff745cca.

libosmocore 0.12.1 is not recent enough, I misread the 'gitk' output.

Change-Id: I87a8e5bbb4aea0c991abe5372f840d76f17378eb
2018-08-26 11:43:11 +02:00
Harald Welte
77ff745cca debian/control: Depend on libosmocore >= 0.12.1
Only this version includes the GSMTAP_SIM_ATR and GSMTAP_SIM_APDU
definitions.

Change-Id: I988cad56aed755af416fc7f23822dcf0229dbb7d
2018-08-26 10:52:46 +02:00
38 changed files with 1048 additions and 267 deletions

1
.gitignore vendored
View File

@@ -21,3 +21,4 @@ host/simtrace2-list
host/simtrace2-remsim host/simtrace2-remsim
host/simtrace2-remsim-usb2udp host/simtrace2-remsim-usb2udp
usb_strings_generated.h usb_strings_generated.h
firmware/usbstring/usbstring

View File

@@ -25,7 +25,7 @@ export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH"
export LD_LIBRARY_PATH="$inst/lib" export LD_LIBRARY_PATH="$inst/lib"
BUILDS="" BUILDS=""
BUILDS+="simtrace/dfu simtrace/cardem simtrace/trace " # simtrace/triple_play BUILDS+="simtrace/dfu simtrace/trace simtrace/cardem "
BUILDS+="qmod/dfu qmod/cardem " BUILDS+="qmod/dfu qmod/cardem "
BUILDS+="owhw/dfu owhw/cardem " BUILDS+="owhw/dfu owhw/cardem "

8
debian/changelog vendored
View File

@@ -1,4 +1,10 @@
simtrace2 (0.5) UNRELEASED; urgency=medium simtrace2 (0.5.1) unstable; urgency=medium
* Backwards-compatibility with older (released, non-master) libosmocore
-- Harald Welte <lafore@gnumonks.org> Sun, 26 Aug 2018 11:50:36 +0200
simtrace2 (0.5) unstable; urgency=medium
* Initial debian package release. * Initial debian package release.

1
debian/control vendored
View File

@@ -4,6 +4,7 @@ Section: devel
Priority: optional Priority: optional
Build-Depends: debhelper (>= 9), Build-Depends: debhelper (>= 9),
libosmocore-dev, libosmocore-dev,
libpcsclite-dev,
libnewlib-arm-none-eabi, libnewlib-arm-none-eabi,
libusb-1.0-0-dev, libusb-1.0-0-dev,
gcc-arm-none-eabi gcc-arm-none-eabi

View File

@@ -100,7 +100,7 @@ C_LIBUSB_DFU = dfu.c dfu_desc.c dfu_driver.c
C_LIBCOMMON = string.c stdio.c fputs.c usb_buf.c ringbuffer.c pseudo_talloc.c host_communication.c C_LIBCOMMON = string.c stdio.c fputs.c usb_buf.c ringbuffer.c pseudo_talloc.c host_communication.c
C_BOARD = $(notdir $(wildcard libboard/common/source/*.c)) C_BOARD = $(notdir $(wildcard libboard/common/source/*.c))
C_BOARD += $(notdir $(wildcard libboard/$(BOARD)/source/*.c)) C_BOARD += $(notdir $(wildcard libboard/$(BOARD)/source/*.c))
C_APPLEVEL = $(notdir $(wildcard apps/$(APP)/*.c)) C_APPLEVEL = $(notdir $(wildcard apps/$(APP)/*.c))
@@ -228,7 +228,7 @@ program:
SERIAL ?= /dev/ttyUSB0 SERIAL ?= /dev/ttyUSB0
log: log:
stty -F $(SERIAL) 115200 stty -F $(SERIAL) 921600
lsof $(SERIAL) && echo "log is already opened" || ( sed -u "s/\r//" $(SERIAL) | ts ) lsof $(SERIAL) && echo "log is already opened" || ( sed -u "s/\r//" $(SERIAL) | ts )
clean: clean:

View File

@@ -1,3 +1,3 @@
C_FILES += $(C_LIBUSB_RT) C_FILES += $(C_LIBUSB_RT)
C_FILES += card_emu.c cciddriver.c iso7816_4.c iso7816_fidi.c mitm.c mode_cardemu.c mode_ccid.c simtrace_iso7816.c sniffer.c tc_etu.c usb.c C_FILES += card_emu.c iso7816_3.c iso7816_4.c mode_cardemu.c simtrace_iso7816.c usb.c

View File

@@ -1,6 +1,7 @@
/* SIMtrace 2 firmware card emulation application /* SIMtrace 2 firmware card emulation application
* *
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de> * (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
* (C) 2018-2019, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -101,7 +102,11 @@ static volatile enum confNum simtrace_config = CFG_NUM_CCID;
void USBDDriverCallbacks_ConfigurationChanged(uint8_t cfgnum) void USBDDriverCallbacks_ConfigurationChanged(uint8_t cfgnum)
{ {
TRACE_INFO_WP("cfgChanged%d ", cfgnum); TRACE_INFO_WP("cfgChanged%d ", cfgnum);
simtrace_config = cfgnum; if (cfgnum < ARRAY_SIZE(config_func_ptrs)) {
simtrace_config = cfgnum;
} else {
TRACE_ERROR("trying to set out of bounds config %u\r\n", cfgnum);
}
} }
void USART1_IrqHandler(void) void USART1_IrqHandler(void)
@@ -125,9 +130,8 @@ static void check_exec_dbg_cmd(void)
return; return;
ch = UART_GetChar(); ch = UART_GetChar();
/* We must echo the character to make python fdexpect happy, whcih we use in factory testing */ /* We must echo the character to make python fdexpect happy, which we use in factory testing */
fputc(ch, stdout); fputc(ch, stdout);
board_exec_dbg_cmd(ch); board_exec_dbg_cmd(ch);
} }
@@ -142,7 +146,8 @@ extern int main(void)
unsigned int i = 0; unsigned int i = 0;
led_init(); led_init();
led_blink(LED_RED, BLINK_3O_5F); led_blink(LED_RED, BLINK_ALWAYS_ON);
led_blink(LED_GREEN, BLINK_ALWAYS_ON);
/* Enable watchdog for 2000ms, with no window */ /* Enable watchdog for 2000ms, with no window */
WDT_Enable(WDT, WDT_MR_WDRSTEN | WDT_MR_WDDBGHLT | WDT_MR_WDIDLEHLT | WDT_Enable(WDT, WDT_MR_WDRSTEN | WDT_MR_WDDBGHLT | WDT_MR_WDIDLEHLT |
@@ -154,7 +159,8 @@ extern int main(void)
printf("\n\r\n\r" printf("\n\r\n\r"
"=============================================================================\n\r" "=============================================================================\n\r"
"SIMtrace2 firmware " GIT_VERSION " (C) 2010-2016 by Harald Welte\n\r" "SIMtrace2 firmware " GIT_VERSION "\n\r"
"(C) 2010-2017 by Harald Welte, 2018-2019 by Kevin Redon\n\r"
"=============================================================================\n\r"); "=============================================================================\n\r");
#if (TRACE_LEVEL >= TRACE_LEVEL_INFO) #if (TRACE_LEVEL >= TRACE_LEVEL_INFO)
@@ -204,7 +210,9 @@ extern int main(void)
} }
TRACE_INFO("calling init of config %u...\n\r", simtrace_config); TRACE_INFO("calling init of config %u...\n\r", simtrace_config);
config_func_ptrs[simtrace_config].init(); if (config_func_ptrs[simtrace_config].init) {
config_func_ptrs[simtrace_config].init();
}
last_simtrace_config = simtrace_config; last_simtrace_config = simtrace_config;
TRACE_INFO("entering main loop...\n\r"); TRACE_INFO("entering main loop...\n\r");
@@ -232,11 +240,17 @@ extern int main(void)
if (last_simtrace_config != simtrace_config) { if (last_simtrace_config != simtrace_config) {
TRACE_INFO("USB config chg %u -> %u\n\r", TRACE_INFO("USB config chg %u -> %u\n\r",
last_simtrace_config, simtrace_config); last_simtrace_config, simtrace_config);
config_func_ptrs[last_simtrace_config].exit(); if (config_func_ptrs[last_simtrace_config].exit) {
config_func_ptrs[simtrace_config].init(); config_func_ptrs[last_simtrace_config].exit();
}
if (config_func_ptrs[simtrace_config].init) {
config_func_ptrs[simtrace_config].init();
}
last_simtrace_config = simtrace_config; last_simtrace_config = simtrace_config;
} else { } else {
config_func_ptrs[simtrace_config].run(); if (config_func_ptrs[simtrace_config].run) {
config_func_ptrs[simtrace_config].run();
}
} }
} }
} }

View File

@@ -1,7 +1,7 @@
/* SIMtrace 2 firmware USB DFU bootloader /* SIMtrace 2 firmware USB DFU bootloader
* *
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de> * (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
* (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de> * (C) 2018-2019 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -66,7 +66,11 @@ int USBDFU_handle_dnload(uint8_t altif, unsigned int offset,
WDT_Restart(WDT); WDT_Restart(WDT);
} }
printf("dnload(altif=%u, offset=%u, len=%u)\n\r", altif, offset, len); #if TRACE_LEVEL >= TRACE_LEVEL_INFO
TRACE_INFO("dnload(altif=%u, offset=%u, len=%u)\n\r", altif, offset, len);
#else
printf("DL off=%u\n\r", offset);
#endif
#ifdef PINS_LEDS #ifdef PINS_LEDS
PIO_Clear(&pinsLeds[LED_NUM_RED]); PIO_Clear(&pinsLeds[LED_NUM_RED]);
@@ -248,7 +252,8 @@ extern int main(void)
printf("\n\r\n\r" printf("\n\r\n\r"
"=============================================================================\n\r" "=============================================================================\n\r"
"DFU bootloader %s for board %s (C) 2010-2017 by Harald Welte\n\r" "DFU bootloader %s for board %s\n\r"
"(C) 2010-2017 by Harald Welte, 2018-2019 by Kevin Redon\n\r"
"=============================================================================\n\r", "=============================================================================\n\r",
manifest_revision, manifest_board); manifest_revision, manifest_board);
@@ -256,7 +261,7 @@ extern int main(void)
TRACE_INFO("Serial Nr. %08x-%08x-%08x-%08x\n\r", TRACE_INFO("Serial Nr. %08x-%08x-%08x-%08x\n\r",
g_unique_id[0], g_unique_id[1], g_unique_id[0], g_unique_id[1],
g_unique_id[2], g_unique_id[3]); g_unique_id[2], g_unique_id[3]);
TRACE_INFO("Reset Cause: 0x%x\n\r", reset_cause); TRACE_INFO("Reset Cause: 0x%lx\n\r", reset_cause);
#if (TRACE_LEVEL >= TRACE_LEVEL_INFO) #if (TRACE_LEVEL >= TRACE_LEVEL_INFO)
/* Find out why we are in the DFU bootloader, and not the main application */ /* Find out why we are in the DFU bootloader, and not the main application */

View File

@@ -1,3 +1,3 @@
C_FILES += $(C_LIBUSB_RT) C_FILES += $(C_LIBUSB_RT)
C_FILES += card_emu.c cciddriver.c iso7816_4.c iso7816_fidi.c mitm.c mode_cardemu.c mode_ccid.c simtrace_iso7816.c sniffer.c tc_etu.c usb.c C_FILES += iso7816_4.c iso7816_fidi.c simtrace_iso7816.c sniffer.c usb.c

View File

@@ -251,7 +251,7 @@ static void GetDescriptor(
switch (type) { switch (type) {
case USBGenericDescriptor_DEVICE: case USBGenericDescriptor_DEVICE:
TRACE_INFO_WP("Dev "); TRACE_DEBUG_WP("Dev ");
/* Adjust length and send descriptor */ /* Adjust length and send descriptor */
@@ -263,7 +263,7 @@ static void GetDescriptor(
break; break;
case USBGenericDescriptor_CONFIGURATION: case USBGenericDescriptor_CONFIGURATION:
TRACE_INFO_WP("Cfg "); TRACE_DEBUG_WP("Cfg ");
/* Adjust length and send descriptor */ /* Adjust length and send descriptor */
@@ -280,7 +280,7 @@ static void GetDescriptor(
break; break;
case USBGenericDescriptor_DEVICEQUALIFIER: case USBGenericDescriptor_DEVICEQUALIFIER:
TRACE_INFO_WP("Qua "); TRACE_DEBUG_WP("Qua ");
/* Check if descriptor exists */ /* Check if descriptor exists */
@@ -301,7 +301,7 @@ static void GetDescriptor(
break; break;
case USBGenericDescriptor_OTHERSPEEDCONFIGURATION: case USBGenericDescriptor_OTHERSPEEDCONFIGURATION:
TRACE_INFO_WP("OSC "); TRACE_DEBUG_WP("OSC ");
/* Check if descriptor exists */ /* Check if descriptor exists */
@@ -327,7 +327,7 @@ static void GetDescriptor(
break; break;
case USBGenericDescriptor_STRING: case USBGenericDescriptor_STRING:
TRACE_INFO_WP("Str%d ", indexRDesc); TRACE_DEBUG_WP("Str%d ", indexRDesc);
/* Check if descriptor exists */ /* Check if descriptor exists */
@@ -504,13 +504,13 @@ void USBDDriver_RequestHandler(
uint32_t length; uint32_t length;
uint32_t address; uint32_t address;
TRACE_INFO_WP("Std "); TRACE_DEBUG_WP("Std ");
/* Check request code */ /* Check request code */
switch (USBGenericRequest_GetRequest(pRequest)) { switch (USBGenericRequest_GetRequest(pRequest)) {
case USBGenericRequest_GETDESCRIPTOR: case USBGenericRequest_GETDESCRIPTOR:
TRACE_INFO_WP("gDesc "); TRACE_DEBUG_WP("gDesc ");
/* Send the requested descriptor */ /* Send the requested descriptor */
type = USBGetDescriptorRequest_GetDescriptorType(pRequest); type = USBGetDescriptorRequest_GetDescriptorType(pRequest);
@@ -520,7 +520,7 @@ void USBDDriver_RequestHandler(
break; break;
case USBGenericRequest_SETADDRESS: case USBGenericRequest_SETADDRESS:
TRACE_INFO_WP("sAddr "); TRACE_DEBUG_WP("sAddr ");
/* Sends a zero-length packet and then set the device address */ /* Sends a zero-length packet and then set the device address */
address = USBSetAddressRequest_GetAddress(pRequest); address = USBSetAddressRequest_GetAddress(pRequest);
@@ -528,7 +528,7 @@ void USBDDriver_RequestHandler(
break; break;
case USBGenericRequest_SETCONFIGURATION: case USBGenericRequest_SETCONFIGURATION:
TRACE_INFO_WP("sCfg "); TRACE_DEBUG_WP("sCfg ");
/* Set the requested configuration */ /* Set the requested configuration */
cfgnum = USBSetConfigurationRequest_GetConfiguration(pRequest); cfgnum = USBSetConfigurationRequest_GetConfiguration(pRequest);
@@ -536,27 +536,27 @@ void USBDDriver_RequestHandler(
break; break;
case USBGenericRequest_GETCONFIGURATION: case USBGenericRequest_GETCONFIGURATION:
TRACE_INFO_WP("gCfg "); TRACE_DEBUG_WP("gCfg ");
/* Send the current configuration number */ /* Send the current configuration number */
GetConfiguration(pDriver); GetConfiguration(pDriver);
break; break;
case USBGenericRequest_GETSTATUS: case USBGenericRequest_GETSTATUS:
TRACE_INFO_WP("gSta "); TRACE_DEBUG_WP("gSta ");
/* Check who is the recipient */ /* Check who is the recipient */
switch (USBGenericRequest_GetRecipient(pRequest)) { switch (USBGenericRequest_GetRecipient(pRequest)) {
case USBGenericRequest_DEVICE: case USBGenericRequest_DEVICE:
TRACE_INFO_WP("Dev "); TRACE_DEBUG_WP("Dev ");
/* Send the device status */ /* Send the device status */
GetDeviceStatus(pDriver); GetDeviceStatus(pDriver);
break; break;
case USBGenericRequest_ENDPOINT: case USBGenericRequest_ENDPOINT:
TRACE_INFO_WP("Ept "); TRACE_DEBUG_WP("Ept ");
/* Send the endpoint status */ /* Send the endpoint status */
eptnum = USBGenericRequest_GetEndpointNumber(pRequest); eptnum = USBGenericRequest_GetEndpointNumber(pRequest);
@@ -572,13 +572,13 @@ void USBDDriver_RequestHandler(
break; break;
case USBGenericRequest_CLEARFEATURE: case USBGenericRequest_CLEARFEATURE:
TRACE_INFO_WP("cFeat "); TRACE_DEBUG_WP("cFeat ");
/* Check which is the requested feature */ /* Check which is the requested feature */
switch (USBFeatureRequest_GetFeatureSelector(pRequest)) { switch (USBFeatureRequest_GetFeatureSelector(pRequest)) {
case USBFeatureRequest_ENDPOINTHALT: case USBFeatureRequest_ENDPOINTHALT:
TRACE_INFO_WP("Hlt "); TRACE_DEBUG_WP("Hlt ");
/* Unhalt endpoint and send a zero-length packet */ /* Unhalt endpoint and send a zero-length packet */
USBD_Unhalt(USBGenericRequest_GetEndpointNumber(pRequest)); USBD_Unhalt(USBGenericRequest_GetEndpointNumber(pRequest));
@@ -586,7 +586,7 @@ void USBDDriver_RequestHandler(
break; break;
case USBFeatureRequest_DEVICEREMOTEWAKEUP: case USBFeatureRequest_DEVICEREMOTEWAKEUP:
TRACE_INFO_WP("RmWU "); TRACE_DEBUG_WP("RmWU ");
/* Disable remote wake-up and send a zero-length packet */ /* Disable remote wake-up and send a zero-length packet */
pDriver->isRemoteWakeUpEnabled = 0; pDriver->isRemoteWakeUpEnabled = 0;
@@ -602,13 +602,13 @@ void USBDDriver_RequestHandler(
break; break;
case USBGenericRequest_SETFEATURE: case USBGenericRequest_SETFEATURE:
TRACE_INFO_WP("sFeat "); TRACE_DEBUG_WP("sFeat ");
/* Check which is the selected feature */ /* Check which is the selected feature */
switch (USBFeatureRequest_GetFeatureSelector(pRequest)) { switch (USBFeatureRequest_GetFeatureSelector(pRequest)) {
case USBFeatureRequest_DEVICEREMOTEWAKEUP: case USBFeatureRequest_DEVICEREMOTEWAKEUP:
TRACE_INFO_WP("RmWU "); TRACE_DEBUG_WP("RmWU ");
/* Enable remote wake-up and send a ZLP */ /* Enable remote wake-up and send a ZLP */
pDriver->isRemoteWakeUpEnabled = 1; pDriver->isRemoteWakeUpEnabled = 1;
@@ -616,25 +616,25 @@ void USBDDriver_RequestHandler(
break; break;
case USBFeatureRequest_ENDPOINTHALT: case USBFeatureRequest_ENDPOINTHALT:
TRACE_INFO_WP("Halt "); TRACE_DEBUG_WP("Halt ");
/* Halt endpoint */ /* Halt endpoint */
USBD_Halt(USBGenericRequest_GetEndpointNumber(pRequest)); USBD_Halt(USBGenericRequest_GetEndpointNumber(pRequest));
USBD_Write(0, 0, 0, 0, 0); USBD_Write(0, 0, 0, 0, 0);
break; break;
case USBFeatureRequest_OTG_B_HNP_ENABLE: case USBFeatureRequest_OTG_B_HNP_ENABLE:
TRACE_INFO_WP("OTG_B_HNP_ENABLE "); TRACE_DEBUG_WP("OTG_B_HNP_ENABLE ");
pDriver->otg_features_supported |= pDriver->otg_features_supported |=
1<<USBFeatureRequest_OTG_B_HNP_ENABLE; 1<<USBFeatureRequest_OTG_B_HNP_ENABLE;
USBD_Write(0, 0, 0, 0, 0); USBD_Write(0, 0, 0, 0, 0);
break; break;
case USBFeatureRequest_OTG_A_HNP_SUPPORT: case USBFeatureRequest_OTG_A_HNP_SUPPORT:
TRACE_INFO_WP("OTG_A_HNP_SUPPORT "); TRACE_DEBUG_WP("OTG_A_HNP_SUPPORT ");
pDriver->otg_features_supported |= pDriver->otg_features_supported |=
1<<USBFeatureRequest_OTG_A_HNP_SUPPORT; 1<<USBFeatureRequest_OTG_A_HNP_SUPPORT;
USBD_Write(0, 0, 0, 0, 0); USBD_Write(0, 0, 0, 0, 0);
break; break;
case USBFeatureRequest_OTG_A_ALT_HNP_SUPPORT: case USBFeatureRequest_OTG_A_ALT_HNP_SUPPORT:
TRACE_INFO_WP("OTG_A_ALT_HNP_SUPPORT "); TRACE_DEBUG_WP("OTG_A_ALT_HNP_SUPPORT ");
pDriver->otg_features_supported |= pDriver->otg_features_supported |=
1<<USBFeatureRequest_OTG_A_ALT_HNP_SUPPORT; 1<<USBFeatureRequest_OTG_A_ALT_HNP_SUPPORT;
USBD_Write(0, 0, 0, 0, 0); USBD_Write(0, 0, 0, 0, 0);
@@ -649,7 +649,7 @@ void USBDDriver_RequestHandler(
break; break;
case USBGenericRequest_SETINTERFACE: case USBGenericRequest_SETINTERFACE:
TRACE_INFO_WP("sInterface "); TRACE_DEBUG_WP("sInterface ");
infnum = USBInterfaceRequest_GetInterface(pRequest); infnum = USBInterfaceRequest_GetInterface(pRequest);
setting = USBInterfaceRequest_GetAlternateSetting(pRequest); setting = USBInterfaceRequest_GetAlternateSetting(pRequest);
@@ -657,7 +657,7 @@ void USBDDriver_RequestHandler(
break; break;
case USBGenericRequest_GETINTERFACE: case USBGenericRequest_GETINTERFACE:
TRACE_INFO_WP("gInterface "); TRACE_DEBUG_WP("gInterface ");
infnum = USBInterfaceRequest_GetInterface(pRequest); infnum = USBInterfaceRequest_GetInterface(pRequest);
GetInterface(pDriver, infnum); GetInterface(pDriver, infnum);

View File

@@ -1,4 +1,7 @@
/* SIMtrace 2 common board pin definitions /* SIMtrace 2 common board pin definitions
*
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
* (C) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -53,8 +56,6 @@
/** Core definition */ /** Core definition */
#define cortexm3 #define cortexm3
#define BOARD_MCK 48000000
#define PIO_LED_RED PIO_PA17 #define PIO_LED_RED PIO_PA17
#define PIO_LED_GREEN PIO_PA18 #define PIO_LED_GREEN PIO_PA18
@@ -79,8 +80,8 @@
#define PINS_UART { PIO_PA9A_URXD0|PIO_PA10A_UTXD0, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT} #define PINS_UART { PIO_PA9A_URXD0|PIO_PA10A_UTXD0, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
/** UART0 */ /** UART0 */
/** Console baudrate always using 115200. */ /** Console baud rate in bps */
#define CONSOLE_BAUDRATE 115200 #define CONSOLE_BAUDRATE 921600
/** UART peripheral used by the console (UART0). */ /** UART peripheral used by the console (UART0). */
#define CONSOLE_UART UART0 #define CONSOLE_UART UART0
/** UART peripheral ID used by the console (UART0). */ /** UART peripheral ID used by the console (UART0). */

View File

@@ -14,5 +14,13 @@
*/ */
#pragma once #pragma once
/** switch card lines to use physical or emulated card
* @param[in] nr card interface number (i.e. slot)
* @param[in] physical which physical interface to switch to (e.g. 0: physical, 1: virtual)
* @return 0 on success, negative else
*/
int sim_switch_use_physical(unsigned int nr, int physical); int sim_switch_use_physical(unsigned int nr, int physical);
/** initialise card switching capabilities
* @return number of switchable card interfaces
*/
int sim_switch_init(void); int sim_switch_init(void);

View File

@@ -2,6 +2,7 @@
* ATMEL Microcontroller Software Support * ATMEL Microcontroller Software Support
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* Copyright (c) 2009, Atmel Corporation * Copyright (c) 2009, Atmel Corporation
* Copyright (c) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
* *
* All rights reserved. * All rights reserved.
* *
@@ -46,39 +47,39 @@
#define BOARD_OSCOUNT (CKGR_MOR_MOSCXTST(0x8)) #define BOARD_OSCOUNT (CKGR_MOR_MOSCXTST(0x8))
#define BOARD_MCKR (PMC_MCKR_PRES_CLK | PMC_MCKR_CSS_PLLA_CLK) #define BOARD_MCKR (PMC_MCKR_PRES_CLK | PMC_MCKR_CSS_PLLA_CLK)
#if (BOARD_MCK == 48000000) /** configure PLL to generate main clock based on main oscillator frequency */
#if (BOARD_MAINOSC == 18432000) #if (BOARD_MAINOSC == 12000000) && (BOARD_MCK == 48000000)
/* Clock settings at 48MHz for 18 MHz crystal */
#define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \
| CKGR_PLLAR_MULA(13-1) \
| CKGR_PLLAR_PLLACOUNT(0x1) \
| CKGR_PLLAR_DIVA(5))
#elif (BOARD_MAINOSC == 12000000)
/* QMod has 12 MHz clock, so multply by 8 (96 MHz) and divide by 2 */
#define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \ #define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \
| CKGR_PLLAR_MULA(8-1) \ | CKGR_PLLAR_MULA(8-1) \
| CKGR_PLLAR_PLLACOUNT(0x1) \ | CKGR_PLLAR_PLLACOUNT(0x1) \
| CKGR_PLLAR_DIVA(2)) | CKGR_PLLAR_DIVA(2))
#else #elif (BOARD_MAINOSC == 12000000) && (BOARD_MCK == 58000000)
#error "Please define PLLA config for your MAINOSC frequency"
#endif /* MAINOSC */
#elif (BOARD_MCK == 64000000)
#if (BOARD_MAINOSC == 18432000)
/* Clock settings at 64MHz for 18 MHz crystal: 64.512 MHz */
#define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \ #define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \
| CKGR_PLLAR_MULA(7-1) \ | CKGR_PLLAR_MULA(29-1) \
| CKGR_PLLAR_PLLACOUNT(0x1) \ | CKGR_PLLAR_PLLACOUNT(0x1) \
| CKGR_PLLAR_DIVA(2)) | CKGR_PLLAR_DIVA(6))
#elif (BOARD_MAINOSC == 12000000) #elif (BOARD_MAINOSC == 12000000) && (BOARD_MCK == 60000000)
/* QMod has 12 MHz clock, so multply by 10 / div by 2: 60 MHz */
#define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \ #define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \
| CKGR_PLLAR_MULA(10-1) \ | CKGR_PLLAR_MULA(10-1) \
| CKGR_PLLAR_PLLACOUNT(0x1) \ | CKGR_PLLAR_PLLACOUNT(0x1) \
| CKGR_PLLAR_DIVA(2)) | CKGR_PLLAR_DIVA(2))
#error "Please define PLLA config for your MAINOSC frequency" #elif (BOARD_MAINOSC == 18432000) && (BOARD_MCK == 47923200)
#endif /* MAINOSC */ #define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \
| CKGR_PLLAR_MULA(13-1) \
| CKGR_PLLAR_PLLACOUNT(0x1) \
| CKGR_PLLAR_DIVA(5))
#elif (BOARD_MAINOSC == 18432000) && (BOARD_MCK == 58982400)
#define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \
| CKGR_PLLAR_MULA(16-1) \
| CKGR_PLLAR_PLLACOUNT(0x1) \
| CKGR_PLLAR_DIVA(5))
#elif (BOARD_MAINOSC == 18432000) && (BOARD_MCK == 64512000)
#define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \
| CKGR_PLLAR_MULA(7-1) \
| CKGR_PLLAR_PLLACOUNT(0x1) \
| CKGR_PLLAR_DIVA(2))
#else #else
#error "No PLL settings for current BOARD_MCK." #error "Please define PLLA config for your BOARD_MCK/MAINOSC frequency"
#endif #endif
#if (BOARD_MAINOSC == 12000000) #if (BOARD_MAINOSC == 12000000)

View File

@@ -85,7 +85,12 @@ extern void UART_Configure( uint32_t baudrate, uint32_t masterClock)
/* Configure baudrate */ /* Configure baudrate */
/* Asynchronous, no oversampling */ /* Asynchronous, no oversampling */
pUart->UART_BRGR = (masterClock / baudrate) / 16; //pUart->UART_BRGR = (masterClock / baudrate) / 16;
if ((masterClock / baudrate) % 16 >= 7) {
pUart->UART_BRGR = ( masterClock / baudrate) / 16 + 1;
} else {
pUart->UART_BRGR = ( masterClock / baudrate) / 16 + 0;
}
/* Disable PDC channel */ /* Disable PDC channel */
pUart->UART_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTDIS; pUart->UART_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTDIS;

View File

@@ -1,6 +1,7 @@
/* OWHW board definition /* OWHW board definition
* *
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de> * (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
* (C) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -25,7 +26,10 @@
/** Board definition */ /** Board definition */
#define owhw #define owhw
/** oscillator used as main clock source (in Hz) */
#define BOARD_MAINOSC 18432000 #define BOARD_MAINOSC 18432000
/** desired main clock frequency (in Hz, based on BOARD_MAINOSC) */
#define BOARD_MCK 58982400 // 18.432 * 16 / 5
/* USIM 2 interface (USART) */ /* USIM 2 interface (USART) */
#define PIN_USIM2_CLK {PIO_PA2, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT} #define PIN_USIM2_CLK {PIO_PA2, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}

View File

@@ -1,6 +1,7 @@
/* Card simulator specific functions /* Card simulator specific functions
* *
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de> * (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
* (C) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -20,9 +21,35 @@
#include "chip.h" #include "chip.h"
#include "board.h" #include "board.h"
#include "utils.h" #include "utils.h"
#include "usb_buf.h"
static const Pin pins_cardsim[] = PINS_CARDSIM; static const Pin pins_cardsim[] = PINS_CARDSIM;
void board_exec_dbg_cmd(int ch)
{
switch (ch) {
case '?':
printf("\t?\thelp\n\r");
printf("\tR\treset SAM3\n\r");
break;
case 'R':
printf("Asking NVIC to reset us\n\r");
USBD_Disconnect();
NVIC_SystemReset();
break;
default:
printf("Unknown command '%c'\n\r", ch);
break;
}
}
void board_main_top(void)
{
#ifndef APPLICATION_dfu
usb_buf_init();
#endif
}
void cardsim_set_simpres(uint8_t slot, int present) void cardsim_set_simpres(uint8_t slot, int present)
{ {
if (slot > 1) if (slot > 1)

View File

@@ -28,7 +28,10 @@
/** Board definition */ /** Board definition */
#define qmod #define qmod
/** oscillator used as main clock source (in Hz) */
#define BOARD_MAINOSC 12000000 #define BOARD_MAINOSC 12000000
/** desired main clock frequency (in Hz, based on BOARD_MAINOSC) */
#define BOARD_MCK 58000000 // 18.432 * 29 / 6
/* USIM 2 interface (USART) */ /* USIM 2 interface (USART) */
#define PIN_USIM2_CLK {PIO_PA2, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT} #define PIN_USIM2_CLK {PIO_PA2, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
@@ -92,4 +95,7 @@
#define CARDEMU_SECOND_UART #define CARDEMU_SECOND_UART
#define DETECT_VCC_BY_ADC #define DETECT_VCC_BY_ADC
/** sysmoQMOD only supports card emulation */
#ifdef APPLICATION_cardem
#define HAVE_CARDEM #define HAVE_CARDEM
#endif

View File

@@ -1,6 +1,7 @@
/* sysmocom quad-modem sysmoQMOD application code /* sysmocom quad-modem sysmoQMOD application code
* *
* (C) 2016-2017 by Harald Welte <hwelte@hmw-consulting.de> * (C) 2016-2017 by Harald Welte <hwelte@hmw-consulting.de>
* (C) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -19,6 +20,7 @@
#include "board.h" #include "board.h"
#include "simtrace.h" #include "simtrace.h"
#include "utils.h" #include "utils.h"
#include "led.h"
#include "wwan_led.h" #include "wwan_led.h"
#include "wwan_perst.h" #include "wwan_perst.h"
#include "sim_switch.h" #include "sim_switch.h"
@@ -90,11 +92,12 @@ static int write_hub_eeprom(void)
TRACE_INFO("Verifying EEPROM...\n\r"); TRACE_INFO("Verifying EEPROM...\n\r");
for (i = 0; i < ARRAY_SIZE(__eeprom_bin); i++) { for (i = 0; i < ARRAY_SIZE(__eeprom_bin); i++) {
int byte = eeprom_read_byte(0x50, i); int byte = eeprom_read_byte(0x50, i);
TRACE_INFO("0x%02x: %02x\n\r", i, byte); TRACE_DEBUG("0x%02x: %02x\n\r", i, byte);
if (byte != __eeprom_bin[i]) if (byte != __eeprom_bin[i])
TRACE_ERROR("Byte %u is wrong, expected 0x%02x, found 0x%02x\n\r", TRACE_ERROR("Byte %u is wrong, expected 0x%02x, found 0x%02x\n\r",
i, __eeprom_bin[i], byte); i, __eeprom_bin[i], byte);
} }
TRACE_INFO("EEPROM written\n\r");
/* FIXME: Release PIN_PRTPWR_OVERRIDE after we know the hub is /* FIXME: Release PIN_PRTPWR_OVERRIDE after we know the hub is
* again powering us up */ * again powering us up */
@@ -119,6 +122,7 @@ static int erase_hub_eeprom(void)
return 1; return 1;
} }
} }
TRACE_INFO("EEPROM erased\n\r");
return 0; return 0;
} }
@@ -184,6 +188,10 @@ void board_exec_dbg_cmd(int ch)
case '?': case '?':
printf("\t?\thelp\n\r"); printf("\t?\thelp\n\r");
printf("\tR\treset SAM3\n\r"); printf("\tR\treset SAM3\n\r");
printf("\tl\tswitch off LED 1\n\r");
printf("\tL\tswitch off LED 1\n\r");
printf("\tg\tswitch off LED 2\n\r");
printf("\tG\tswitch off LED 2\n\r");
if (qmod_sam3_is_12()) { if (qmod_sam3_is_12()) {
printf("\tE\tprogram EEPROM\n\r"); printf("\tE\tprogram EEPROM\n\r");
printf("\te\tErase EEPROM\n\r"); printf("\te\tErase EEPROM\n\r");
@@ -207,6 +215,22 @@ void board_exec_dbg_cmd(int ch)
USBD_Disconnect(); USBD_Disconnect();
NVIC_SystemReset(); NVIC_SystemReset();
break; break;
case 'l':
led_blink(LED_GREEN, BLINK_ALWAYS_OFF);
printf("LED 1 switched off\n\r");
break;
case 'L':
led_blink(LED_GREEN, BLINK_ALWAYS_ON);
printf("LED 1 switched on\n\r");
break;
case 'g':
led_blink(LED_RED, BLINK_ALWAYS_OFF);
printf("LED 2 switched off\n\r");
break;
case 'G':
led_blink(LED_RED, BLINK_ALWAYS_ON);
printf("LED 2 switched on\n\r");
break;
case 'X': case 'X':
printf("Clearing _SIMTRACExx_RST -> SIMTRACExx_RST high (inactive)\n\r"); printf("Clearing _SIMTRACExx_RST -> SIMTRACExx_RST high (inactive)\n\r");
PIO_Clear(&pin_peer_rst); PIO_Clear(&pin_peer_rst);

View File

@@ -0,0 +1,90 @@
/* Code to switch between local (physical) and remote (emulated) SIM
*
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
*
* 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 "board.h"
#include "trace.h"
#include "led.h"
#include "sim_switch.h"
#ifdef PIN_SIM_SWITCH1
static const Pin pin_conn_usim1 = {PIO_PA20, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT};
#endif
#ifdef PIN_SIM_SWITCH2
static const Pin pin_conn_usim2 = {PIO_PA28, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT};
#endif
static int initialized = 0;
int sim_switch_use_physical(unsigned int nr, int physical)
{
const Pin *pin;
enum led led;
if (!initialized) {
TRACE_ERROR("Somebody forgot to call sim_switch_init()\r\n");
sim_switch_init();
}
TRACE_INFO("Modem %d: %s SIM\n\r", nr,
physical ? "physical" : "virtual");
switch (nr) {
#ifdef PIN_SIM_SWITCH1
case 0:
pin = &pin_conn_usim1;
led = LED_USIM1;
break;
#endif
#ifdef PIN_SIM_SWITCH2
case 1:
pin = &pin_conn_usim2;
led = LED_USIM2;
break;
#endif
default:
TRACE_ERROR("Invalid SIM%u\n\r", nr);
return -1;
}
if (physical) {
TRACE_INFO("%u: Use local/physical SIM\r\n", nr);
PIO_Clear(pin);
led_blink(led, BLINK_ALWAYS_ON);
} else {
TRACE_INFO("%u: Use remote/emulated SIM\r\n", nr);
PIO_Set(pin);
led_blink(led, BLINK_ALWAYS_OFF);
}
return 0;
}
int sim_switch_init(void)
{
int num_switch = 0;
#ifdef PIN_SIM_SWITCH1
PIO_Configure(&pin_conn_usim1, 1);
num_switch++;
#endif
#ifdef PIN_SIM_SWITCH2
PIO_Configure(&pin_conn_usim2, 1);
num_switch++;
#endif
initialized = 1;
return num_switch;
}

View File

@@ -26,8 +26,10 @@
/* Board definition */ /* Board definition */
#define simtrace #define simtrace
/* Board main oscillator frequency (in Hz) */ /** oscillator used as main clock source (in Hz) */
#define BOARD_MAINOSC 18432000 #define BOARD_MAINOSC 18432000
/** desired main clock frequency (in Hz, based on BOARD_MAINOSC) */
#define BOARD_MCK 58982400 // 18.432 * 16 / 5
/** Pin configuration **/ /** Pin configuration **/
/* Button to force bootloader start (shorted to ground when pressed */ /* Button to force bootloader start (shorted to ground when pressed */
@@ -57,15 +59,15 @@
/** Phone connection **/ /** Phone connection **/
/* Phone USIM slot 1 VCC pin (VCC_PHONE in schematic) */ /* Phone USIM slot 1 VCC pin (VCC_PHONE in schematic) */
#define PIN_USIM1_VCC {PIO_PA25, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT} #define PIN_USIM1_VCC {PIO_PA25, PIOA, ID_PIOA, PIO_INPUT, PIO_IT_EDGE | PIO_DEGLITCH }
/* Phone USIM slot 1 RST pin (active low; RST_PHONE in schematic) */ /* Phone USIM slot 1 RST pin (active low; RST_PHONE in schematic) */
#define PIN_USIM1_nRST {PIO_PA24, PIOA, ID_PIOA, PIO_INPUT, PIO_IT_RISE_EDGE | PIO_DEGLITCH } #define PIN_USIM1_nRST {PIO_PA24, PIOA, ID_PIOA, PIO_INPUT, PIO_IT_EDGE | PIO_DEGLITCH }
/* Phone I/O data signal input/output (I/O_PHONE in schematic) */ /* Phone I/O data signal input/output (I/O_PHONE in schematic) */
#define PIN_PHONE_IO {PIO_PA22A_TXD1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT} #define PIN_USIM1_IO {PIO_PA22A_TXD1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
/* Phone CLK clock input (CLK_PHONE in schematic) */ /* Phone CLK clock input (CLK_PHONE in schematic) */
#define PIN_PHONE_CLK {PIO_PA23A_SCK1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT} #define PIN_PHONE_CLK {PIO_PA23A_SCK1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
/* Pin used for phone USIM slot 1 communication */ /* Pin used for phone USIM slot 1 communication */
#define PINS_USIM1 PIN_PHONE_IO, PIN_PHONE_CLK, PIN_PHONE_CLK_INPUT, PIN_USIM1_VCC, PIN_PHONE_IO_INPUT, PIN_USIM1_nRST #define PINS_USIM1 PIN_USIM1_IO, PIN_PHONE_CLK, PIN_PHONE_CLK_INPUT, PIN_USIM1_VCC, PIN_PHONE_IO_INPUT, PIN_USIM1_nRST
/* Phone I/O data signal input/output (unused USART RX input; connected to I/O_PHONE in schematic) */ /* Phone I/O data signal input/output (unused USART RX input; connected to I/O_PHONE in schematic) */
#define PIN_PHONE_IO_INPUT {PIO_PA21A_RXD1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT} #define PIN_PHONE_IO_INPUT {PIO_PA21A_RXD1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
/* Pin used as clock input (to measure the ETU duration; connected to CLK_PHONE in schematic) */ /* Pin used as clock input (to measure the ETU duration; connected to CLK_PHONE in schematic) */
@@ -103,6 +105,14 @@
/* ISO7816-communication related pins */ /* ISO7816-communication related pins */
#define PINS_ISO7816 PIN_SIM_IO, PIN_SIM_CLK, PIN_ISO7816_RSTMC // SIM_PWEN_PIN, PIN_SIM_IO2, PIN_SIM_CLK2 #define PINS_ISO7816 PIN_SIM_IO, PIN_SIM_CLK, PIN_ISO7816_RSTMC // SIM_PWEN_PIN, PIN_SIM_IO2, PIN_SIM_CLK2
/** card emulation configuration */
/* Disable power converter 4.5-6V to 3.3V (active high) */
#define PIN_SIM_PWEN_CARDEMU {SIM_PWEN, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
/* Disable power switch to forward VCC_PHONE to VCC_SIM (active high) */
#define PIN_VCC_FWD_CARDEMU {VCC_FWD, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
/* Disable power to SIM */
#define PINS_PWR_CARDEMU PIN_SIM_PWEN_CARDEMU, PIN_VCC_FWD_CARDEMU
/** External SPI flash interface **/ /** External SPI flash interface **/
/* SPI MISO pin definition */ /* SPI MISO pin definition */
#define PIN_SPI_MISO {PIO_PA12A_MISO, PIOA, PIOA, PIO_PERIPH_A, PIO_PULLUP} #define PIN_SPI_MISO {PIO_PA12A_MISO, PIOA, PIOA, PIO_PERIPH_A, PIO_PULLUP}
@@ -136,10 +146,18 @@
/** Supported modes */ /** Supported modes */
/* SIMtrace board supports sniffer mode */ /* SIMtrace board supports sniffer mode */
#ifdef APPLICATION_trace
#define HAVE_SNIFFER #define HAVE_SNIFFER
#endif
/* SIMtrace board supports CCID mode */ /* SIMtrace board supports CCID mode */
#ifdef APPLICATION_ccid
//#define HAVE_CCID //#define HAVE_CCID
#endif
/* SIMtrace board supports card emulation mode */ /* SIMtrace board supports card emulation mode */
//#define HAVE_CARDEM #ifdef APPLICATION_cardem
#define HAVE_CARDEM
#endif
/* SIMtrace board supports man-in-the-middle mode */ /* SIMtrace board supports man-in-the-middle mode */
#ifdef APPLICATION_mitm
//#define HAVE_MITM //#define HAVE_MITM
#endif

View File

@@ -0,0 +1,63 @@
/* Code to switch between local (physical) and remote (emulated) SIM
*
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
* (C) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
*
* 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 "board.h"
#include "trace.h"
#include "led.h"
#include "sim_switch.h"
#ifdef PIN_SIM_SWITCH1
static const Pin pin_conn_usim1 = {PIO_PA20, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT};
#endif
#ifdef PIN_SIM_SWITCH2
static const Pin pin_conn_usim2 = {PIO_PA28, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT};
#endif
static int initialized = 0;
int sim_switch_use_physical(unsigned int nr, int physical)
{
const Pin pin_sc = PIN_SC_SW_DEFAULT; // pin to control bus switch for VCC/RST/CLK signals
const Pin pin_io = PIN_IO_SW_DEFAULT; // pin to control bus switch for I/O signal
if (nr > 0) {
TRACE_ERROR("SIM interface for Modem %d can't be switched\r\n", nr);
return -1;
}
TRACE_INFO("Modem %u: %s SIM\n\r", nr, physical ? "physical" : "virtual");
if (physical) {
TRACE_INFO("%u: Use local/physical SIM\r\n", nr);
PIO_Set(&pin_sc);
PIO_Set(&pin_io);
} else {
TRACE_INFO("%u: Use remote/emulated SIM\r\n", nr);
PIO_Clear(&pin_sc);
PIO_Clear(&pin_io);
}
return 0;
}
int sim_switch_init(void)
{
// the bus switch is already initialised
return 1; // SIMtrace hardware has only one switchable interface
}

View File

@@ -48,10 +48,41 @@ struct llist_head *card_emu_get_uart_tx_queue(struct card_handle *ch);
void card_emu_have_new_uart_tx(struct card_handle *ch); void card_emu_have_new_uart_tx(struct card_handle *ch);
void card_emu_report_status(struct card_handle *ch); void card_emu_report_status(struct card_handle *ch);
/*! call when the waiting time has half-expired
* param[in] ch card for which the waiting time half expired
*/
void card_emu_wt_halfed(struct card_handle *ch);
/*! call when the waiting time has expired
* param[in] ch card for which the waiting time expired
*/
void card_emu_wt_expired(struct card_handle *ch);
#define ENABLE_TX 0x01 #define ENABLE_TX 0x01
#define ENABLE_RX 0x02 #define ENABLE_RX 0x02
int card_emu_uart_update_fidi(uint8_t uart_chan, unsigned int fidi); // the following functions are callbacks implement in mode_cardemu.c
/*! update F and D on USART peripheral
* @param[in] usart USART peripheral to configure
* @param[in] f clock rate conversion integer F value
* @param[in] d baud rate adjustment factor D value
* @note this should happen after reset and protocol select (through PPS or implicit)
*/
void card_emu_uart_update_fd(uint8_t uart_chan, uint16_t f, uint8_t d);
/*! update WT on USART peripheral
* @param[in] usart USART peripheral to configure
* @param[in] wt inactivity Waiting Time before card_emu_wt_expired is called (0 to disable)
*/
void card_emu_uart_update_wt(uint8_t uart_chan, uint32_t wt);
/*! reset waiting timeout count down on USART peripheral
* @param[in] usart USART peripheral to configure
*/
void card_emu_uart_reset_wt(uint8_t uart_chan);
/*! set I/O line high
* @param[in] usart USART peripheral to configure
* @param[in] set if I/O line should be set high (true), or cleared low (false)
*/
void card_emu_uart_io_set(uint8_t uart_chan, bool set);
int card_emu_uart_tx(uint8_t uart_chan, uint8_t byte); int card_emu_uart_tx(uint8_t uart_chan, uint8_t byte);
void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx); void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx);
void card_emu_uart_wait_tx_idle(uint8_t uart_chan); void card_emu_uart_wait_tx_idle(uint8_t uart_chan);

View File

@@ -0,0 +1,98 @@
/*
* Copyright (C) 2019 sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/* this library provides utilities to handle the ISO-7816 part 3 communication aspects (e.g. related to F and D) */
#pragma once
#include <stdint.h>
#include <stdbool.h>
/** default clock rate conversion integer Fd
* @implements ISO/IEC 7816-3:2006(E) section 8.1
*/
#define ISO7816_3_DEFAULT_FD 372
/** default baud rate adjustment factor Dd
* @implements ISO/IEC 7816-3:2006(E) section 8.1
*/
#define ISO7816_3_DEFAULT_DD 1
/** default clock rate conversion integer Fi
* @implements ISO/IEC 7816-3:2006(E) section 8.3
* @note non-default value is optionally specified in TA1
*/
#define ISO7816_3_DEFAULT_FI 372
/** default baud rate adjustment factor Di
* @implements ISO/IEC 7816-3:2006(E) section 8.3
* @note non-default value is optionally specified in TA1
*/
#define ISO7816_3_DEFAULT_DI 1
/** default maximum clock frequency, in Hz
* @implements ISO/IEC 7816-3:2006(E) section 8.3
* @note non-default value is optionally specified in TA1
*/
#define ISO7816_3_DEFAULT_FMAX 5000000UL
/** default Waiting Integer (WI) value for T=0
* @implements ISO/IEC 7816-3:2006(E) section 10.2
* @note non-default value is optionally specified in TC2
*/
#define ISO7816_3_DEFAULT_WI 10
/** default Waiting Time (WT) value, in ETU
* @implements ISO/IEC 7816-3:2006(E) section 8.1
* @note depends on Fi, Di, and WI if protocol T=0 is selected
*/
#define ISO7816_3_DEFAULT_WT 9600
/** Table encoding the clock rate conversion integer Fi
* @note Fi is indicated in TA1, but the same table is used for F and Fn during PPS
* @implements ISO/IEC 7816-3:2006(E) table 7
*/
extern const uint16_t iso7816_3_fi_table[];
/** Table encoding the maximum clock frequency f_max in Hz
* @implements ISO/IEC 7816-3:2006(E) table 7
* @note f_max is indicated in TA1, but the same table is used for F and Fn during PPS
*/
extern const uint32_t iso7816_3_fmax_table[];
/** Table encoding the baud rate adjust integer Di
* @implements ISO/IEC 7816-3:2006(E) table 8
* @note Di is indicated in TA1, but the same table is used for D and Dn during PPS
*/
extern const uint8_t iso7816_3_di_table[];
/* verify if the clock rate conversion integer F value is valid
* @param[in] f F value to be validated
* @return if F value is valid
* @note only values in ISO/IEC 7816-3:2006(E) table 7 are valid
*/
bool iso7816_3_valid_f(uint16_t f);
/* verify if the baud rate adjustment factor D value is valid
* @param[in] d D value to be validated
* @return if D value is valid
* @note only values in ISO/IEC 7816-3:2006(E) table 8 are valid
*/
bool iso7816_3_valid_d(uint8_t d);
/** calculate Waiting Time (WT)
* @param[in] wi Waiting Integer
* @param[in] fi clock rate conversion integer Fi value
* @param[in] di baud rate adjustment factor Di value
* @param[in] f clock rate conversion integer F value
* @param[in] d baud rate adjustment factor D value
* @return Waiting Time WT, in ETU, or < 0 on error (see code for return codes)
* @note this should happen after reset and T=0 protocol select (through PPS or implicit)
* @implements ISO/IEC 7816-3:2006(E) section 8.1 and 10.2
*/
int32_t iso7816_3_calculate_wt(uint8_t wi, uint16_t fi, uint8_t di, uint16_t f, uint8_t d);

View File

@@ -228,11 +228,10 @@ struct cardemu_usb_msg_status {
uint32_t flags; uint32_t flags;
/* phone-applied target voltage in mV */ /* phone-applied target voltage in mV */
uint16_t voltage_mv; uint16_t voltage_mv;
/* Fi/Di related information */ uint8_t f; /*!< index of F and f_max values as encoded in ISO/IEC 7816-3:2006(E) Table 7 */
uint8_t fi; uint8_t d; /*!< index of D value as encoded in ISO/IEC 7816-3:2006(E) Table 8 */
uint8_t di; uint8_t wi; /*!< Waiting Integer as defined in ISO/IEC 7816-3:2006(E) Section 10.2 */
uint8_t wi; uint32_t wt; /*!< Waiting Time in ETU as defined in ISO/IEC 7816-3:2006(E) Section 8.1 */
uint32_t waiting_time;
} __attribute__ ((packed)); } __attribute__ ((packed));
/* CEMU_USB_MSGT_DO_PTS */ /* CEMU_USB_MSGT_DO_PTS */

View File

@@ -1,7 +1,7 @@
/* ISO7816-3 state machine for the card side /* ISO7816-3 state machine for the card side
* *
* (C) 2010-2017 by Harald Welte <laforge@gnumonks.org> * (C) 2010-2017 by Harald Welte <laforge@gnumonks.org>
* (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de> * (C) 2018-2019 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -26,15 +26,13 @@
#include "utils.h" #include "utils.h"
#include "trace.h" #include "trace.h"
#include "iso7816_fidi.h" #include "iso7816_3.h"
#include "tc_etu.h"
#include "card_emu.h" #include "card_emu.h"
#include "simtrace_prot.h" #include "simtrace_prot.h"
#include "usb_buf.h" #include "usb_buf.h"
#include <osmocom/core/linuxlist.h> #include <osmocom/core/linuxlist.h>
#include <osmocom/core/msgb.h> #include <osmocom/core/msgb.h>
#define NUM_SLOTS 2 #define NUM_SLOTS 2
#define ISO7816_3_INIT_WTIME 9600 #define ISO7816_3_INIT_WTIME 9600
@@ -55,14 +53,38 @@ enum iso7816_3_card_state {
}; };
const struct value_string iso7816_3_card_state_names[] = { const struct value_string iso7816_3_card_state_names[] = {
OSMO_VALUE_STRING(ISO_S_WAIT_POWER), {
OSMO_VALUE_STRING(ISO_S_WAIT_CLK), .value = ISO_S_WAIT_POWER,
OSMO_VALUE_STRING(ISO_S_WAIT_RST), .str = "WAIT_POWER",
OSMO_VALUE_STRING(ISO_S_WAIT_ATR), },
OSMO_VALUE_STRING(ISO_S_IN_ATR), {
OSMO_VALUE_STRING(ISO_S_IN_PTS), .value = ISO_S_WAIT_CLK,
OSMO_VALUE_STRING(ISO_S_WAIT_TPDU), .str = "WAIT_CLK",
OSMO_VALUE_STRING(ISO_S_IN_TPDU), },
{
.value = ISO_S_WAIT_RST,
.str = "WAIT_RST",
},
{
.value = ISO_S_WAIT_ATR,
.str = "WAIT_ATR",
},
{
.value = ISO_S_IN_ATR,
.str = "IN_ATR",
},
{
.value = ISO_S_IN_PTS,
.str = "IN_PTS",
},
{
.value = ISO_S_WAIT_TPDU,
.str = "WAIT_TPDU",
},
{
.value = ISO_S_IN_TPDU,
.str = "IN_TPDU",
},
{ {
.value = 0, .value = 0,
.str = NULL, .str = NULL,
@@ -86,6 +108,7 @@ enum pts_state {
PTS_S_WAIT_RESP_PCK = PTS_S_WAIT_REQ_PCK | 0x10, PTS_S_WAIT_RESP_PCK = PTS_S_WAIT_REQ_PCK | 0x10,
}; };
/* PTS field byte index */
#define _PTSS 0 #define _PTSS 0
#define _PTS0 1 #define _PTS0 1
#define _PTS1 2 #define _PTS1 2
@@ -105,6 +128,46 @@ enum tpdu_state {
TPDU_S_WAIT_TX, /* waiting for more data to reader */ TPDU_S_WAIT_TX, /* waiting for more data to reader */
}; };
const struct value_string tpdu_state_names[] = {
{
.value = TPDU_S_WAIT_CLA,
.str = "WAIT_CLA",
},
{
.value = TPDU_S_WAIT_INS,
.str = "WAIT_INS",
},
{
.value = TPDU_S_WAIT_P1,
.str = "WAIT_P1",
},
{
.value = TPDU_S_WAIT_P2,
.str = "WAIT_P2",
},
{
.value = TPDU_S_WAIT_P3,
.str = "WAIT_P3",
},
{
.value = TPDU_S_WAIT_PB,
.str = "WAIT_PB",
},
{
.value = TPDU_S_WAIT_RX,
.str = "WAIT_RX",
},
{
.value = TPDU_S_WAIT_TX,
.str = "WAIT_TX",
},
{
.value = 0,
.str = NULL,
},
};
/* TPDU field byte index */
#define _CLA 0 #define _CLA 0
#define _INS 1 #define _INS 1
#define _P1 2 #define _P1 2
@@ -121,18 +184,53 @@ struct card_handle {
uint8_t in_reset; /* 1 = RST low, 0 = RST high */ uint8_t in_reset; /* 1 = RST low, 0 = RST high */
uint8_t clocked; /* 1 = active, 0 = inactive */ uint8_t clocked; /* 1 = active, 0 = inactive */
/* timing parameters, from PTS */
uint8_t fi;
uint8_t di;
uint8_t wi;
uint8_t tc_chan; /* TC channel number */ uint8_t tc_chan; /* TC channel number */
uint8_t uart_chan; /* UART channel */ uint8_t uart_chan; /* UART channel */
uint8_t in_ep; /* USB IN EP */ uint8_t in_ep; /* USB IN EP */
uint8_t irq_ep; /* USB IN EP */ uint8_t irq_ep; /* USB IN EP */
uint32_t waiting_time; /* in clocks */ /*! clock rate conversion integer F
* @implements ISO/IEC 7816-3:2006(E) section 7.1
* @note this represents the current value used
*/
uint16_t f;
/*! baud rate adjustment factor D
* @implements ISO/IEC 7816-3:2006(E) section 7.1
* @note this represents the current value used
*/
uint8_t d;
/*! clock frequency in Hz
* @implements ISO/IEC 7816-3:2006(E) section 7.1
* @note the USART peripheral in slave mode does not provide the current value. we could measure it but this is not really useful. instead we remember the maximum possible value corresponding to the selected F value
*/
uint32_t f_cur;
/*! clock rate conversion integer Fi
* @implements ISO/IEC 7816-3:2006(E) Table 7
* @note this represents the maximum value supported by the card, and can be indicated in TA1
* @note this value can be set in TA1
*/
uint16_t fi;
/*! baud rate adjustment factor Di
* @implements ISO/IEC 7816-3:2006(E) Table 8
* @note this represents the maximum value supported by the card, and can be indicated in TA1
*/
uint8_t di;
/*! clock frequency, in Hz
* @implements ISO/IEC 7816-3:2006(E) Table 7
* @note this represents the maximum value supported by the card, and can be indicated in TA1
*/
uint32_t f_max;
/*! Waiting Integer
* @implements ISO/IEC 7816-3:2006(E) Section 10.2
* @note this value can be set in TA2
*/
uint8_t wi;
/*! Waiting Time, in ETU
* @implements ISO/IEC 7816-3:2006(E) Section 8.1
* @note this depends on Fi, Di, and WI if T=0 is used
*/
uint32_t wt;
/* ATR state machine */ /* ATR state machine */
struct { struct {
@@ -280,23 +378,6 @@ static void flush_pts(struct card_handle *ch)
usb_buf_upd_len_and_submit(msg); usb_buf_upd_len_and_submit(msg);
} }
static void emu_update_fidi(struct card_handle *ch)
{
int rc;
rc = compute_fidi_ratio(ch->fi, ch->di);
if (rc > 0 && rc < 0x400) {
TRACE_INFO("%u: computed Fi(%u) Di(%u) ratio: %d\r\n",
ch->num, ch->fi, ch->di, rc);
/* make sure UART uses new F/D ratio */
card_emu_uart_update_fidi(ch->uart_chan, rc);
/* notify ETU timer about this */
tc_etu_set_etu(ch->tc_chan, rc);
} else
TRACE_INFO("%u: computed FiDi ration %d unsupported\r\n",
ch->num, rc);
}
/* Update the ISO 7816-3 TPDU receiver state */ /* Update the ISO 7816-3 TPDU receiver state */
static void card_set_state(struct card_handle *ch, static void card_set_state(struct card_handle *ch,
enum iso7816_3_card_state new_state) enum iso7816_3_card_state new_state)
@@ -304,40 +385,47 @@ static void card_set_state(struct card_handle *ch,
if (ch->state == new_state) if (ch->state == new_state)
return; return;
TRACE_DEBUG("%u: 7816 card state %u (%s) -> %u (%s)\r\n", ch->num, TRACE_DEBUG("%u: 7816 card state %s -> %s\r\n", ch->num,
ch->state, get_value_string(iso7816_3_card_state_names, ch->state), get_value_string(iso7816_3_card_state_names, ch->state),
new_state, get_value_string(iso7816_3_card_state_names, new_state)); get_value_string(iso7816_3_card_state_names, new_state));
ch->state = new_state; ch->state = new_state;
switch (new_state) { switch (new_state) {
case ISO_S_WAIT_POWER: case ISO_S_WAIT_POWER:
case ISO_S_WAIT_CLK: case ISO_S_WAIT_CLK:
case ISO_S_WAIT_RST: case ISO_S_WAIT_RST:
/* disable Rx and Tx of UART */ card_emu_uart_enable(ch->uart_chan, 0); // disable Rx and Tx of UART
card_emu_uart_enable(ch->uart_chan, 0); card_emu_uart_update_wt(ch->uart_chan, 0); // disable timeout
if (ISO_S_WAIT_POWER == new_state) {
card_emu_uart_io_set(ch->uart_chan, false); // pull I/O line low
} else {
card_emu_uart_io_set(ch->uart_chan, true); // pull I/O line high
}
break; break;
case ISO_S_WAIT_ATR: case ISO_S_WAIT_ATR:
/* Reset to initial Fi / Di ratio */ // reset the ETU-related values
ch->fi = 1; ch->f = ISO7816_3_DEFAULT_FD;
ch->di = 1; ch->d = ISO7816_3_DEFAULT_DD;
emu_update_fidi(ch); card_emu_uart_update_fd(ch->uart_chan, ch->f, ch->d); // set baud rate
// reset values optionally specified in the ATR
ch->fi = ISO7816_3_DEFAULT_FI;
ch->di = ISO7816_3_DEFAULT_DI;
ch->wi = ISO7816_3_DEFAULT_WI;
int32_t wt = iso7816_3_calculate_wt(ch->wi, ch->fi, ch->di, ch->f, ch->d); // get default waiting time
if (wt <= 0) {
TRACE_FATAL("%u: invalid WT %ld\r\n", ch->num, wt);
}
ch->wt = wt;
card_emu_uart_enable(ch->uart_chan, ENABLE_TX); // enable TX to be able to use the timeout
/* the ATR should only be sent 400 to 40k clock cycles after the RESET. /* the ATR should only be sent 400 to 40k clock cycles after the RESET.
* we use the tc_etu mechanism to wait this time. * we use the tc_etu mechanism to wait this time.
* since the initial ETU is Fd=372/Dd=1 clock cycles long, we have to wait 2-107 ETU. * since the initial ETU is Fd=372/Dd=1 clock cycles long, we have to wait 2-107 ETU.
*/ */
tc_etu_set_wtime(ch->tc_chan, 2); card_emu_uart_update_wt(ch->uart_chan, 2);
/* ensure the TC_ETU timer is enabled */
tc_etu_enable(ch->tc_chan);
break; break;
case ISO_S_IN_ATR: case ISO_S_IN_ATR:
/* initialize to default WI, this will be overwritten if we // FIXME disable timeout while sending ATR
* send TC2, and it will be programmed into hardware after
* ATR is finished */
ch->wi = ISO7816_3_DEFAULT_WI;
/* update waiting time to initial waiting time */
ch->waiting_time = ISO7816_3_INIT_WTIME;
/* set initial waiting time */
tc_etu_set_wtime(ch->tc_chan, ch->waiting_time);
/* Set ATR sub-state to initial state */ /* Set ATR sub-state to initial state */
ch->atr.idx = 0; ch->atr.idx = 0;
/* enable USART transmission to reader */ /* enable USART transmission to reader */
@@ -383,7 +471,6 @@ static int tx_byte_atr(struct card_handle *ch)
return 1; return 1;
} else { /* The ATR has been completely transmitted */ } else { /* The ATR has been completely transmitted */
/* search for TC2 to updated WI */ /* search for TC2 to updated WI */
ch->wi = ISO7816_3_DEFAULT_WI;
if (ch->atr.len >= 2 && ch->atr.atr[1] & 0xf0) { /* Y1 has some data */ if (ch->atr.len >= 2 && ch->atr.atr[1] & 0xf0) { /* Y1 has some data */
uint8_t atr_td1 = 2; uint8_t atr_td1 = 2;
if (ch->atr.atr[1] & 0x10) { /* TA1 is present */ if (ch->atr.atr[1] & 0x10) { /* TA1 is present */
@@ -412,9 +499,7 @@ static int tx_byte_atr(struct card_handle *ch)
} }
} }
} }
/* update waiting time (see ISO 7816-3 10.2) */ /* FIXME update waiting time in case of card is specific mode */
ch->waiting_time = ch->wi * 960 * ch->fi;
tc_etu_set_wtime(ch->tc_chan, ch->waiting_time);
/* reset PTS to initial state */ /* reset PTS to initial state */
set_pts_state(ch, PTS_S_WAIT_REQ_PTSS); set_pts_state(ch, PTS_S_WAIT_REQ_PTSS);
/* go to next state */ /* go to next state */
@@ -481,9 +566,12 @@ from_pts3:
return PTS_S_WAIT_REQ_PCK | is_resp; return PTS_S_WAIT_REQ_PCK | is_resp;
} }
/*! process incoming PTS byte
static int * @param[in] ch card handle on which the byte has been received
process_byte_pts(struct card_handle *ch, uint8_t byte) * @param[in] byte received PTS byte
* @return new iso7816_3_card_state or -1 at the end of PTS request
*/
static int process_byte_pts(struct card_handle *ch, uint8_t byte)
{ {
switch (ch->pts.state) { switch (ch->pts.state) {
case PTS_S_WAIT_REQ_PTSS: case PTS_S_WAIT_REQ_PTSS:
@@ -510,7 +598,7 @@ process_byte_pts(struct card_handle *ch, uint8_t byte)
set_pts_state(ch, PTS_S_WAIT_REQ_PTSS); set_pts_state(ch, PTS_S_WAIT_REQ_PTSS);
return ISO_S_WAIT_TPDU; return ISO_S_WAIT_TPDU;
} }
/* FIXME: check if proposal matches capabilities in ATR */ /* FIXME check if proposal matches capabilities in TA1 */
memcpy(ch->pts.resp, ch->pts.req, sizeof(ch->pts.resp)); memcpy(ch->pts.resp, ch->pts.req, sizeof(ch->pts.resp));
break; break;
default: default:
@@ -549,11 +637,17 @@ static int tx_byte_pts(struct card_handle *ch)
break; break;
case PTS_S_WAIT_RESP_PTS1: case PTS_S_WAIT_RESP_PTS1:
byte = ch->pts.resp[_PTS1]; byte = ch->pts.resp[_PTS1];
/* This must be TA1 */ // TODO the value should have been validated when receiving the request
ch->fi = byte >> 4; ch->f = iso7816_3_fi_table[byte >> 4]; // save selected Fn
ch->di = byte & 0xf; if (0 == ch->f) {
TRACE_DEBUG("%u: found Fi=%u Di=%u\r\n", ch->num, TRACE_ERROR("%u: invalid F index in PPS response: %u\r\n", ch->num, byte >> 4);
ch->fi, ch->di); // TODO become unresponsive to signal error condition
}
ch->d = iso7816_3_di_table[byte & 0xf]; // save selected Dn
if (0 == ch->d) {
TRACE_ERROR("%u: invalid D index in PPS response: %u\r\n", ch->num, byte & 0xf);
// TODO become unresponsive to signal error condition
}
break; break;
case PTS_S_WAIT_RESP_PTS2: case PTS_S_WAIT_RESP_PTS2:
byte = ch->pts.resp[_PTS2]; byte = ch->pts.resp[_PTS2];
@@ -578,8 +672,15 @@ static int tx_byte_pts(struct card_handle *ch)
switch (ch->pts.state) { switch (ch->pts.state) {
case PTS_S_WAIT_RESP_PCK: case PTS_S_WAIT_RESP_PCK:
card_emu_uart_wait_tx_idle(ch->uart_chan); card_emu_uart_wait_tx_idle(ch->uart_chan);
/* update baud rate generator with Fi/Di */ card_emu_uart_update_fd(ch->uart_chan, ch->f, ch->d); // set selected baud rate
emu_update_fidi(ch); int32_t wt = iso7816_3_calculate_wt(ch->wi, ch->fi, ch->di, ch->f, ch->d); // get new waiting time
if (wt <= 0) {
TRACE_ERROR("%u: invalid WT calculated: %ld\r\n", ch->num, wt);
// TODO become unresponsive to signal error condition
} else {
ch->wt = wt;
}
// FIXME disable WT
/* Wait for the next TPDU */ /* Wait for the next TPDU */
card_set_state(ch, ISO_S_WAIT_TPDU); card_set_state(ch, ISO_S_WAIT_TPDU);
set_pts_state(ch, PTS_S_WAIT_REQ_PTSS); set_pts_state(ch, PTS_S_WAIT_REQ_PTSS);
@@ -650,22 +751,31 @@ static void set_tpdu_state(struct card_handle *ch, enum tpdu_state new_ts)
{ {
if (ch->tpdu.state == new_ts) if (ch->tpdu.state == new_ts)
return; return;
if (ISO_S_IN_TPDU != ch->state && ISO_S_WAIT_TPDU != ch->state) {
TRACE_ERROR("%u: setting TPDU state in %s state\r\n", ch->num,
get_value_string(iso7816_3_card_state_names, ch->state));
}
TRACE_DEBUG("%u: 7816 TPDU state %u -> %u\r\n", ch->num, TRACE_DEBUG("%u: 7816 TPDU state %s -> %s\r\n", ch->num,
ch->tpdu.state, new_ts); get_value_string(tpdu_state_names, ch->tpdu.state),
get_value_string(tpdu_state_names, new_ts));
ch->tpdu.state = new_ts; ch->tpdu.state = new_ts;
switch (new_ts) { switch (new_ts) {
case TPDU_S_WAIT_CLA: case TPDU_S_WAIT_CLA: // we will be waiting for the next incoming TDPU
case TPDU_S_WAIT_RX: card_emu_uart_enable(ch->uart_chan, ENABLE_RX); // switch back to receiving mode
card_emu_uart_enable(ch->uart_chan, ENABLE_RX); card_emu_uart_update_wt(ch->uart_chan, 0); // disable waiting time since we don't expect any data
break;
case TPDU_S_WAIT_INS: // the reader started sending the TPDU header
card_emu_uart_update_wt(ch->uart_chan, ch->wt); // start waiting for the rest of the header/body
break;
case TPDU_S_WAIT_RX: // the reader should send us the TPDU body data
card_emu_uart_enable(ch->uart_chan, ENABLE_RX); // switch to receive mode to receive the body
card_emu_uart_update_wt(ch->uart_chan, ch->wt); // start waiting for the rest body
break; break;
case TPDU_S_WAIT_PB: case TPDU_S_WAIT_PB:
/* we just completed the TPDU header from reader to card card_emu_uart_enable(ch->uart_chan, ENABLE_TX); // header is completely received, now we need to transmit the procedure byte
* and now need to disable the receiver, enable the card_emu_uart_update_wt(ch->uart_chan, ch->wt); // prepare to extend the waiting time once half of it is reached
* transmitter and transmit the procedure byte */
card_emu_uart_enable(ch->uart_chan, ENABLE_TX);
break; break;
default: default:
break; break;
@@ -944,11 +1054,11 @@ void card_emu_report_status(struct card_handle *ch)
sts->flags |= CEMU_STATUS_F_CLK_ACTIVE; sts->flags |= CEMU_STATUS_F_CLK_ACTIVE;
if (ch->in_reset) if (ch->in_reset)
sts->flags |= CEMU_STATUS_F_RESET_ACTIVE; sts->flags |= CEMU_STATUS_F_RESET_ACTIVE;
/* FIXME: voltage + card insert */ /* FIXME set voltage and card insert values */
sts->fi = ch->fi; sts->f = ch->f;
sts->di = ch->di; sts->d = ch->d;
sts->wi = ch->wi; sts->wi = ch->wi;
sts->waiting_time = ch->waiting_time; sts->wt = ch->wt;
usb_buf_upd_len_and_submit(msg); usb_buf_upd_len_and_submit(msg);
} }
@@ -960,7 +1070,6 @@ void card_emu_io_statechg(struct card_handle *ch, enum card_io io, int active)
case CARD_IO_VCC: case CARD_IO_VCC:
if (active == 0 && ch->vcc_active == 1) { if (active == 0 && ch->vcc_active == 1) {
TRACE_INFO("%u: VCC deactivated\r\n", ch->num); TRACE_INFO("%u: VCC deactivated\r\n", ch->num);
tc_etu_disable(ch->tc_chan);
card_set_state(ch, ISO_S_WAIT_POWER); card_set_state(ch, ISO_S_WAIT_POWER);
} else if (active == 1 && ch->vcc_active == 0) { } else if (active == 1 && ch->vcc_active == 0) {
TRACE_INFO("%u: VCC activated\r\n", ch->num); TRACE_INFO("%u: VCC activated\r\n", ch->num);
@@ -981,18 +1090,18 @@ void card_emu_io_statechg(struct card_handle *ch, enum card_io io, int active)
case CARD_IO_RST: case CARD_IO_RST:
if (active == 0 && ch->in_reset) { if (active == 0 && ch->in_reset) {
TRACE_INFO("%u: RST released\r\n", ch->num); TRACE_INFO("%u: RST released\r\n", ch->num);
if (ch->vcc_active && ch->clocked) { if (ch->vcc_active && ch->clocked && ISO_S_WAIT_RST == ch->state) {
/* enable the TC/ETU counter once reset has been released */
tc_etu_enable(ch->tc_chan);
/* prepare to send the ATR */ /* prepare to send the ATR */
card_set_state(ch, ISO_S_WAIT_ATR); card_set_state(ch, ISO_S_WAIT_ATR);
} }
} else if (active && !ch->in_reset) { } else if (active && !ch->in_reset) {
TRACE_INFO("%u: RST asserted\r\n", ch->num); TRACE_INFO("%u: RST asserted\r\n", ch->num);
tc_etu_disable(ch->tc_chan); card_set_state(ch, ISO_S_WAIT_RST);
} }
ch->in_reset = active; ch->in_reset = active;
break; break;
default:
break;
} }
} }
@@ -1002,62 +1111,61 @@ int card_emu_set_atr(struct card_handle *ch, const uint8_t *atr, uint8_t len)
if (len > sizeof(ch->atr.atr)) if (len > sizeof(ch->atr.atr))
return -1; return -1;
/* ignore new ATR for now since we PPS has not been tested
memcpy(ch->atr.atr, atr, len); memcpy(ch->atr.atr, atr, len);
ch->atr.len = len; ch->atr.len = len;
ch->atr.idx = 0; ch->atr.idx = 0;
*/
#if TRACE_LEVEL >= TRACE_LEVEL_INFO #if TRACE_LEVEL >= TRACE_LEVEL_INFO
uint8_t i; uint8_t i;
TRACE_INFO("%u: ATR set: ", ch->num); TRACE_INFO("%u: ATR set: ", ch->num);
for (i = 0; i < ch->atr.len; i++) { for (i = 0; i < len; i++) {
TRACE_INFO_WP("%02x ", atr[i]); TRACE_INFO_WP("%02x ", atr[i]);
} }
TRACE_INFO_WP("\n\r"); TRACE_INFO_WP("\n\r");
TRACE_INFO("%u: ATR set currently ignored\n\r", ch->num);
#endif #endif
/* FIXME: race condition with transmitting ATR to reader? */ /* FIXME: race condition with transmitting ATR to reader? */
return 0; return 0;
} }
/* hardware driver informs us that one (more) ETU has expired */ void card_emu_wt_halfed(struct card_handle *ch)
void tc_etu_wtime_half_expired(void *handle)
{ {
struct card_handle *ch = handle;
/* transmit NULL procedure byte well before waiting time expires */
switch (ch->state) { switch (ch->state) {
case ISO_S_IN_TPDU: case ISO_S_IN_TPDU:
switch (ch->tpdu.state) { switch (ch->tpdu.state) {
case TPDU_S_WAIT_PB:
case TPDU_S_WAIT_TX: case TPDU_S_WAIT_TX:
case TPDU_S_WAIT_PB:
putchar('N'); putchar('N');
card_emu_uart_tx(ch->uart_chan, ISO7816_3_PB_NULL); card_emu_uart_tx(ch->uart_chan, ISO7816_3_PB_NULL); // we are waiting for data from the user. send a procedure byte to ask the reader to wait more time
card_emu_uart_reset_wt(ch->uart_chan); // reset WT
break; break;
default: default:
break; break;
} }
break;
default: default:
break; break;
} }
} }
/* hardware driver informs us that one (more) ETU has expired */ void card_emu_wt_expired(struct card_handle *ch)
void tc_etu_wtime_expired(void *handle)
{ {
struct card_handle *ch = handle;
switch (ch->state) { switch (ch->state) {
case ISO_S_WAIT_ATR: case ISO_S_WAIT_ATR:
/* ISO 7816-3 6.2.1 time tc has passed, we can now send the ATR */ /* ISO 7816-3 6.2.1 time tc has passed, we can now send the ATR */
card_set_state(ch, ISO_S_IN_ATR); card_set_state(ch, ISO_S_IN_ATR);
break; break;
default: default:
// TODO become unresponsive
TRACE_ERROR("%u: wtime_exp\r\n", ch->num); TRACE_ERROR("%u: wtime_exp\r\n", ch->num);
break; break;
} }
} }
/* shortest ATR found in smartcard_list.txt */ /* shortest ATR possible (uses default speed and no options) */
static const uint8_t default_atr[] = { 0x3B, 0x02, 0x14, 0x50 }; static const uint8_t default_atr[] = { 0x3B, 0x00 };
static struct card_handle card_handles[NUM_SLOTS]; static struct card_handle card_handles[NUM_SLOTS];
@@ -1084,13 +1192,13 @@ struct card_handle *card_emu_init(uint8_t slot_num, uint8_t tc_chan, uint8_t uar
ch->in_reset = 1; ch->in_reset = 1;
ch->clocked = 0; ch->clocked = 0;
ch->fi = 0; ch->fi = ISO7816_3_DEFAULT_FI;
ch->di = 1; ch->di = ISO7816_3_DEFAULT_DI;
ch->wi = ISO7816_3_DEFAULT_WI; ch->wi = ISO7816_3_DEFAULT_WI;
ch->wt = ISO7816_3_DEFAULT_WT;;
ch->tc_chan = tc_chan; ch->tc_chan = tc_chan;
ch->uart_chan = uart_chan; ch->uart_chan = uart_chan;
ch->waiting_time = ISO7816_3_INIT_WTIME;
ch->atr.idx = 0; ch->atr.idx = 0;
ch->atr.len = sizeof(default_atr); ch->atr.len = sizeof(default_atr);
@@ -1099,7 +1207,5 @@ struct card_handle *card_emu_init(uint8_t slot_num, uint8_t tc_chan, uint8_t uar
ch->pts.state = PTS_S_WAIT_REQ_PTSS; ch->pts.state = PTS_S_WAIT_REQ_PTSS;
ch->tpdu.state = TPDU_S_WAIT_CLA; ch->tpdu.state = TPDU_S_WAIT_CLA;
tc_etu_init(ch->tc_chan, ch);
return ch; return ch;
} }

View File

@@ -0,0 +1,123 @@
/*
* Copyright (C) 2019 sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdint.h>
#include <stddef.h>
#include "utils.h"
#include "iso7816_3.h"
const uint16_t iso7816_3_fi_table[16] = {
372, 372, 558, 744, 1116, 1488, 1860, 0,
0, 512, 768, 1024, 1536, 2048, 0, 0
};
const uint32_t iso7816_3_fmax_table[16] = {
4000000, 5000000, 6000000, 8000000, 12000000, 16000000, 20000000, 0,
0, 5000000, 7500000, 10000000, 15000000, 20000000, 0, 0
};
const uint8_t iso7816_3_di_table[16] = {
0, 1, 2, 4, 8, 16, 32, 64,
12, 20, 0, 0, 0, 0, 0, 0,
};
/* all values are based on the Elementary Time Unit (ETU), defined in ISO/IEC 7816-3 section 7.1
* this is the time required to transmit a bit, and is calculated as follows: 1 ETU = (F / D) x (1 / f) where:
* - F is the clock rate conversion integer
* - D is the baud rate adjustment factor
* - f is the clock frequency
* the possible F, f(max), and D values are defined in ISO/IEC 7816-3 table 7 and 8
* - the initial value for F (after reset) is Fd = 372
* - the initial value for D (after reset) is Dd = 1
* - the initial maximum frequency f(max) is 5 MHz
* the card must measure the ETU based on the clock signal provided by the reader
* one ETU (e.g. 1 bit) takes F/D clock cycles, which the card must count
*
* the card can indicate an alternative set of supported values Fi (with corresponding f(max)) and Di for higher baud rate in TA1 in the ATR (see ISO/IEC 7816-3 section 8.3)
* these values are selected according to ISO/IEC 7816-3 section 6.3.1:
* - card in specific mode: they are enforced if TA2 is present (the reader can deactivate the card if it does not support these values)
* - card in negotiable mode:
* -- they can be selected by the reader using the Protocol and Parameters Selection (PPS) procedure
* -- the first offered protocol and default values are used when no PPS is started
*
* PPS is done with Fd and Dd (see ISO/IEC 7816-3 section 9)
* the reader can propose any F and D values between from Fd to Fi, and from Dd to Di (Fi and Di are indicated in TA1)
* the in PPS agreed values F and D are called Fn and Dn and are applied after a successful exchange, corresponding to PPS1_Response bit 5
*
* the F and D values must be provided to the SAM3S USART peripheral (after reset and PPS)
*/
bool iso7816_3_valid_f(uint16_t f)
{
if (0 == f) {
return false;
}
uint8_t i = 0;
for (i = 0; i < ARRAY_SIZE(iso7816_3_fi_table) && iso7816_3_fi_table[i] != f; i++);
return (i < ARRAY_SIZE(iso7816_3_fi_table) && iso7816_3_fi_table[i] == f);
}
bool iso7816_3_valid_d(uint8_t d)
{
if (0 == d) {
return false;
}
uint8_t i = 0;
for (i = 0; i < ARRAY_SIZE(iso7816_3_di_table) && iso7816_3_di_table[i] != d; i++);
return (i < ARRAY_SIZE(iso7816_3_di_table) && iso7816_3_di_table[i] == d);
}
/*
* the ETU is not only used to define the baud rate, but also the Waiting Time (WT) (see ISO/IEC 7816-3 section 8.1)
* when exceeding WT without card response, the reader flags the card as unresponsive, and resets it
* this can be used by the card to indicate errors or unsupported operations
* if the card requires more time to respond, it shall send a procedure byte to restart WT
* WT is calculated as follows (for T=0, see ISO/IEC 7816-3 section 10.2): WT = WI x 960 x (Fi / f(max)) where
* - WI is encoded in TC2 in the ATR (10 if absent)
* - WI does not depend on D/Di (used for the ETU)
* - after reset WT is 9600 ETU
* - WI (e.g. the new WT) is applied when T=0 is used (after 6.3.1), even if Fi is not Fn (this WT extension is important to know for the reader so to have the right timeout)
*/
int32_t iso7816_3_calculate_wt(uint8_t wi, uint16_t fi, uint8_t di, uint16_t f, uint8_t d)
{
// sanity checks
if (0 == wi) {
return -1;
}
if (!iso7816_3_valid_f(fi)) {
return -2;
}
if (!iso7816_3_valid_d(di)) {
return -3;
}
if (!iso7816_3_valid_f(f)) {
return -4;
}
if (!iso7816_3_valid_d(d)) {
return -5;
}
if (f > fi) {
return -6;
}
if (d > di) {
return -7;
}
return wi * 960UL * (fi/f) * (di/d); // calculate timeout value in ETU
}

View File

@@ -1,7 +1,7 @@
/* card emulation mode /* card emulation mode
* *
* (C) 2015-2017 by Harald Welte <laforge@gnumonks.org> * (C) 2015-2017 by Harald Welte <laforge@gnumonks.org>
* (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de> * (C) 2018-2019 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -22,7 +22,7 @@
#include "simtrace.h" #include "simtrace.h"
#include "ringbuffer.h" #include "ringbuffer.h"
#include "card_emu.h" #include "card_emu.h"
#include "iso7816_fidi.h" #include "iso7816_3.h"
#include "utils.h" #include "utils.h"
#include <osmocom/core/linuxlist.h> #include <osmocom/core/linuxlist.h>
#include <osmocom/core/msgb.h> #include <osmocom/core/msgb.h>
@@ -54,11 +54,15 @@ struct cardem_inst {
struct card_handle *ch; struct card_handle *ch;
struct llist_head usb_out_queue; struct llist_head usb_out_queue;
struct ringbuf rb; struct ringbuf rb;
uint32_t wt; /*!< receiver waiting time to trigger timeout (0 to deactivate it) */
uint32_t wt_remaining; /*!< remaining waiting time */
bool wt_halfed; /*!< if at least half of the waiting time passed */
struct Usart_info usart_info; struct Usart_info usart_info;
int usb_pending_old; int usb_pending_old;
uint8_t ep_out; uint8_t ep_out;
uint8_t ep_in; uint8_t ep_in;
uint8_t ep_int; uint8_t ep_int;
const Pin pin_io;
const Pin pin_insert; const Pin pin_insert;
uint32_t vcc_uv; uint32_t vcc_uv;
uint32_t vcc_uv_last; uint32_t vcc_uv_last;
@@ -75,6 +79,7 @@ struct cardem_inst cardem_inst[] = {
.ep_out = SIMTRACE_CARDEM_USB_EP_USIM1_DATAOUT, .ep_out = SIMTRACE_CARDEM_USB_EP_USIM1_DATAOUT,
.ep_in = SIMTRACE_CARDEM_USB_EP_USIM1_DATAIN, .ep_in = SIMTRACE_CARDEM_USB_EP_USIM1_DATAIN,
.ep_int = SIMTRACE_CARDEM_USB_EP_USIM1_INT, .ep_int = SIMTRACE_CARDEM_USB_EP_USIM1_INT,
.pin_io = PIN_USIM1_IO,
#ifdef PIN_SET_USIM1_PRES #ifdef PIN_SET_USIM1_PRES
.pin_insert = PIN_SET_USIM1_PRES, .pin_insert = PIN_SET_USIM1_PRES,
#endif #endif
@@ -90,6 +95,7 @@ struct cardem_inst cardem_inst[] = {
.ep_out = SIMTRACE_CARDEM_USB_EP_USIM2_DATAOUT, .ep_out = SIMTRACE_CARDEM_USB_EP_USIM2_DATAOUT,
.ep_in = SIMTRACE_CARDEM_USB_EP_USIM2_DATAIN, .ep_in = SIMTRACE_CARDEM_USB_EP_USIM2_DATAIN,
.ep_int = SIMTRACE_CARDEM_USB_EP_USIM2_INT, .ep_int = SIMTRACE_CARDEM_USB_EP_USIM2_INT,
.pin_io = PIN_USIM2_IO,
#ifdef PIN_SET_USIM2_PRES #ifdef PIN_SET_USIM2_PRES
.pin_insert = PIN_SET_USIM2_PRES, .pin_insert = PIN_SET_USIM2_PRES,
#endif #endif
@@ -140,7 +146,7 @@ void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx)
* receiver enabled during transmit */ * receiver enabled during transmit */
USART_SetReceiverEnabled(usart, 1); USART_SetReceiverEnabled(usart, 1);
usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK; usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
USART_EnableIt(usart, US_IER_TXRDY); USART_EnableIt(usart, US_IER_TXRDY | US_IER_TIMEOUT);
USART_SetTransmitterEnabled(usart, 1); USART_SetTransmitterEnabled(usart, 1);
break; break;
case ENABLE_RX: case ENABLE_RX:
@@ -150,7 +156,7 @@ void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx)
USART_SetTransmitterEnabled(usart, 1); USART_SetTransmitterEnabled(usart, 1);
wait_tx_idle(usart); wait_tx_idle(usart);
usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK; usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
USART_EnableIt(usart, US_IER_RXRDY); USART_EnableIt(usart, US_IER_RXRDY | US_IER_TIMEOUT);
USART_SetReceiverEnabled(usart, 1); USART_SetReceiverEnabled(usart, 1);
break; break;
case 0: case 0:
@@ -188,57 +194,157 @@ int card_emu_uart_tx(uint8_t uart_chan, uint8_t byte)
return 1; return 1;
} }
/* FIXME: integrate this with actual irq handler */ /* FIXME: integrate this with actual irq handler */
static void usart_irq_rx(uint8_t inst_num) static void usart_irq_rx(uint8_t inst_num)
{ {
if (inst_num >= ARRAY_SIZE(cardem_inst)) {
TRACE_ERROR("%u: UART channel out of bounds\r\n", inst_num);
return;
}
Usart *usart = get_usart_by_chan(inst_num); Usart *usart = get_usart_by_chan(inst_num);
struct cardem_inst *ci = &cardem_inst[inst_num]; struct cardem_inst *ci = &cardem_inst[inst_num];
uint32_t csr; uint32_t csr;
uint8_t byte = 0; uint8_t byte = 0;
csr = usart->US_CSR & usart->US_IMR; csr = usart->US_CSR & usart->US_IMR; // save state/flags before they get changed
if (csr & US_CSR_RXRDY) { if (csr & US_CSR_RXRDY) { // bytes has been received
byte = (usart->US_RHR) & 0xFF; byte = (usart->US_RHR) & 0xFF; // ready out byte
if (rbuf_write(&ci->rb, byte) < 0) if (rbuf_write(&ci->rb, byte) < 0) // store byte in buffer
TRACE_ERROR("rbuf overrun\r\n"); TRACE_ERROR("rbuf overrun\r\n"); // error if could not store in buffer
} }
if (csr & US_CSR_TXRDY) { if (csr & US_CSR_TXRDY) { // ready to transmit the next byte
if (card_emu_tx_byte(ci->ch) == 0) if (card_emu_tx_byte(ci->ch) == 0) // transmit next byte, and check if a byte is being transmitted
USART_DisableIt(usart, US_IER_TXRDY); USART_DisableIt(usart, US_IER_TXRDY); // stop the TX ready signal if not byte has been transmitted
} }
if (csr & (US_CSR_OVRE|US_CSR_FRAME|US_CSR_PARE| if (csr & (US_CSR_OVRE | US_CSR_FRAME | US_CSR_PARE | US_CSR_NACK | (1 << 10))) { // error flag set
US_CSR_TIMEOUT|US_CSR_NACK|(1<<10))) { usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK; // reset UART state to clear flag
usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK; TRACE_ERROR("%u USART error on 0x%x status: 0x%lx\n", ci->num, byte, csr); // warn user about error
TRACE_ERROR("%u e 0x%x st: 0x%lx\n", ci->num, byte, csr); }
// handle timeout
if (csr & US_CSR_TIMEOUT) { // RX has been inactive for some time
if (ci->wt_remaining <= (usart->US_RTOR & 0xffff)) { // waiting time has passed
ci->wt_remaining = 0; // timeout reached (will stop the timer)
} else {
ci->wt_remaining -= (usart->US_RTOR & 0xffff); // be sure to subtract the actual timeout since the new might not have been set and reloaded yet
}
if (0 == ci->wt_remaining) {
card_emu_wt_expired(ci->ch); // let the state know WT has expired
} else if (ci->wt_remaining <= ci->wt / 2 && !ci->wt_halfed) {
ci->wt_halfed = true;
card_emu_wt_halfed(ci->ch); // let the state know WT has half expired
}
if (ci->wt_remaining > 0xffff) { // value exceeds the USART TO range
usart->US_RTOR = 0xffff; // use the MAX
} else {
usart->US_RTOR = ci->wt_remaining;
}
usart->US_CR |= US_CR_STTTO; // clear timeout flag (and stop timeout until next character is received)
usart->US_CR |= US_CR_RETTO; // restart the counter (it wt is 0, the timeout is not started)
} }
} }
/*! ISR called for USART0 */
void mode_cardemu_usart0_irq(void) void mode_cardemu_usart0_irq(void)
{ {
/* USART0 == Instance 1 == USIM 2 */ /* USART0 == Instance 1 == USIM 2 */
usart_irq_rx(1); usart_irq_rx(1);
} }
/*! ISR called for USART1 */
void mode_cardemu_usart1_irq(void) void mode_cardemu_usart1_irq(void)
{ {
/* USART1 == Instance 0 == USIM 1 */ /* USART1 == Instance 0 == USIM 1 */
usart_irq_rx(0); usart_irq_rx(0);
} }
/* call-back from card_emu.c to change UART baud rate */ // call-back from card_emu.c to change UART baud rate
int card_emu_uart_update_fidi(uint8_t uart_chan, unsigned int fidi)
{
int rc;
Usart *usart = get_usart_by_chan(uart_chan);
usart->US_CR |= US_CR_RXDIS | US_CR_RSTRX; void card_emu_uart_update_fd(uint8_t uart_chan, uint16_t f, uint8_t d)
usart->US_FIDI = fidi & 0x3ff; {
usart->US_CR |= US_CR_RXEN | US_CR_STTTO; Usart *usart = get_usart_by_chan(uart_chan); // get the USART based on the card handle
return 0; if (NULL == usart) {
TRACE_ERROR("%u: USART not found by chan\r\n", uart_chan);
return;
}
if (!iso7816_3_valid_f(f)) {
TRACE_ERROR("%u: invalid F: %u\r\n", uart_chan, f);
return;
}
if (!iso7816_3_valid_d(d)) {
TRACE_ERROR("%u: invalid D: %u\r\n", uart_chan, d);
return;
}
uint16_t ratio = f / d;
if (ratio > 0 && ratio < 2048) {
/* make sure USART uses new F/D ratio */
usart->US_CR |= US_CR_RXDIS | US_CR_RSTRX; // disable USART before changing baud rate
usart->US_FIDI = (ratio & 0x7ff); // change baud rate (ratio)
usart->US_CR |= US_CR_RXEN | US_CR_STTTO; // re-enable USART (and stop timeout)
TRACE_INFO("%u: USART F/D set to %u/%u\r\n", uart_chan, f, d);
} else {
TRACE_ERROR("%u: USART could not set F/D to %u/%u\r\n", uart_chan, f, d);
// TODO become unresponsive
}
}
void card_emu_uart_update_wt(uint8_t uart_chan, uint32_t wt)
{
if (uart_chan >= ARRAY_SIZE(cardem_inst)) {
TRACE_ERROR("%u: UART channel out of bounds\r\n", uart_chan);
return;
}
struct cardem_inst *ci = &cardem_inst[uart_chan];
Usart *usart = get_usart_by_chan(uart_chan); // get the USART based on the card handle
if (NULL == usart) {
TRACE_ERROR("%u: USART not found by chan\r\n", uart_chan);
return;
}
ci->wt = wt; // save value
card_emu_uart_reset_wt(uart_chan); // reset and start timer
TRACE_INFO("%u: USART WT set to %lu ETU\r\n", uart_chan, wt);
}
void card_emu_uart_reset_wt(uint8_t uart_chan)
{
if (uart_chan >= ARRAY_SIZE(cardem_inst)) {
TRACE_ERROR("%u: UART channel out of bounds\r\n", uart_chan);
return;
}
struct cardem_inst *ci = &cardem_inst[uart_chan];
Usart *usart = get_usart_by_chan(uart_chan); // get the USART based on the card handle
if (NULL == usart) {
TRACE_ERROR("%u: USART not found by chan\r\n", uart_chan);
return;
}
ci->wt_remaining = ci->wt; // reload WT value
ci->wt_halfed = false; // reset half expired
if (ci->wt_remaining > 0xffff) { // value exceeds the USART TO range
usart->US_RTOR = 0xffff; // use the MAX
} else {
usart->US_RTOR = ci->wt_remaining;
}
usart->US_CR |= US_CR_RETTO; // restart the counter (if wt is 0, the timeout is not started)
}
void card_emu_uart_io_set(uint8_t uart_chan, bool set)
{
if (uart_chan >= ARRAY_SIZE(cardem_inst)) {
TRACE_ERROR("%u: UART channel out of bounds\r\n", uart_chan);
return;
}
struct cardem_inst *ci = &cardem_inst[uart_chan];
if (set) {
PIO_Set(&ci->pin_io);
} else {
PIO_Clear(&ci->pin_io);
}
} }
/* call-back from card_emu.c to force a USART interrupt */ /* call-back from card_emu.c to force a USART interrupt */
@@ -366,7 +472,7 @@ static void usim1_vcc_irqhandler(const Pin *pPin)
{ {
int active = PIO_Get(&pin_usim1_vcc) ? 1 : 0; int active = PIO_Get(&pin_usim1_vcc) ? 1 : 0;
card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_VCC, active); card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_VCC, active);
/* FIXME do this for real */ /* FIXME readers enable clock after providing power and before releasing reset, but we should check it */
card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_CLK, active); card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_CLK, active);
} }
#endif /* !DETECT_VCC_BY_ADC */ #endif /* !DETECT_VCC_BY_ADC */
@@ -383,7 +489,7 @@ static void usim2_vcc_irqhandler(const Pin *pPin)
{ {
int active = PIO_Get(&pin_usim2_vcc) ? 1 : 0; int active = PIO_Get(&pin_usim2_vcc) ? 1 : 0;
card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_VCC, active); card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_VCC, active);
/* FIXME do this for real */ /* FIXME readers enable clock after providing power and before releasing reset, but we should check it */
card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_CLK, active); card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_CLK, active);
} }
#endif /* !DETECT_VCC_BY_ADC */ #endif /* !DETECT_VCC_BY_ADC */
@@ -402,32 +508,47 @@ void mode_cardemu_init(void)
TRACE_ENTRY(); TRACE_ENTRY();
#ifdef PINS_PWR_CARDEMU
// enable power on required peripherals, else disable
Pin pins_pwr_cardemu[] = { PINS_PWR_CARDEMU };
PIO_Configure(pins_pwr_cardemu, PIO_LISTSIZE(pins_pwr_cardemu));
#endif /* PINS_PWR_CARDEMU */
#ifdef PINS_CARDSIM #ifdef PINS_CARDSIM
PIO_Configure(pins_cardsim, PIO_LISTSIZE(pins_cardsim)); PIO_Configure(pins_cardsim, PIO_LISTSIZE(pins_cardsim));
#endif #endif
// ADC channel 6 and 7 are used to measure VCC (else they are grounded)
ADC->ADC_CHER |= ADC_CHER_CH6 | ADC_CHER_CH7; // enable the ADC channels to put them in high impedance (else they leak current)
#ifdef DETECT_VCC_BY_ADC #ifdef DETECT_VCC_BY_ADC
card_vcc_adc_init(); card_vcc_adc_init(); // configure the ADC to measure VCC
#endif /* DETECT_VCC_BY_ADC */ #endif /* DETECT_VCC_BY_ADC */
// TODO pull SIMtrace board SIM lines low, else they can leak current back to VCC
INIT_LLIST_HEAD(&cardem_inst[0].usb_out_queue); INIT_LLIST_HEAD(&cardem_inst[0].usb_out_queue);
rbuf_reset(&cardem_inst[0].rb); rbuf_reset(&cardem_inst[0].rb);
PIO_Configure(pins_usim1, PIO_LISTSIZE(pins_usim1)); PIO_Configure(pins_usim1, PIO_LISTSIZE(pins_usim1));
ISO7816_Init(&cardem_inst[0].usart_info, CLK_SLAVE); ISO7816_Init(&cardem_inst[0].usart_info, CLK_SLAVE); // configure USART as ISO-7816 slave (e.g. card)
NVIC_EnableIRQ(USART1_IRQn); cardem_inst[0].usart_info.base->US_RTOR = 0; // don't use receive timeout timer for now
PIO_ConfigureIt(&pin_usim1_rst, usim1_rst_irqhandler); USART_EnableIt(cardem_inst[0].usart_info.base, US_IER_RXRDY | US_IER_TIMEOUT); // enable interrupts to indicate when data has been received or timeout occurred
PIO_EnableIt(&pin_usim1_rst); NVIC_EnableIRQ(USART1_IRQn); // enable interrupt requests for the USART peripheral
PIO_ConfigureIt(&pin_usim1_rst, usim1_rst_irqhandler); // register ISR to handle reset signal change
PIO_EnableIt(&pin_usim1_rst); // enable interrupt for reset pin change
#ifndef DETECT_VCC_BY_ADC #ifndef DETECT_VCC_BY_ADC
PIO_ConfigureIt(&pin_usim1_vcc, usim1_vcc_irqhandler); PIO_ConfigureIt(&pin_usim1_vcc, usim1_vcc_irqhandler); // register ISR to handle VCC signal change
PIO_EnableIt(&pin_usim1_vcc); PIO_EnableIt(&pin_usim1_vcc); // enable interrupt for VCC pin change
#endif /* DETECT_VCC_BY_ADC */ #endif /* DETECT_VCC_BY_ADC */
cardem_inst[0].ch = card_emu_init(0, 2, 0, SIMTRACE_CARDEM_USB_EP_USIM1_DATAIN, SIMTRACE_CARDEM_USB_EP_USIM1_INT); cardem_inst[0].ch = card_emu_init(0, 2, 0, SIMTRACE_CARDEM_USB_EP_USIM1_DATAIN, SIMTRACE_CARDEM_USB_EP_USIM1_INT);
sim_switch_use_physical(0, 1); sim_switch_use_physical(0, 1);
#ifndef DETECT_VCC_BY_ADC
usim1_vcc_irqhandler(NULL); // check VCC/CLK state
#endif
usim1_rst_irqhandler(NULL); // force RST state
#ifdef CARDEMU_SECOND_UART #ifdef CARDEMU_SECOND_UART
INIT_LLIST_HEAD(&cardem_inst[1].usb_out_queue); INIT_LLIST_HEAD(&cardem_inst[1].usb_out_queue);
rbuf_reset(&cardem_inst[1].rb); rbuf_reset(&cardem_inst[1].rb);
PIO_Configure(pins_usim2, PIO_LISTSIZE(pins_usim2)); PIO_Configure(pins_usim2, PIO_LISTSIZE(pins_usim2));
ISO7816_Init(&cardem_inst[1].usart_info, CLK_SLAVE); ISO7816_Init(&cardem_inst[1].usart_info, CLK_SLAVE);
// TODO enable timeout
NVIC_EnableIRQ(USART0_IRQn); NVIC_EnableIRQ(USART0_IRQn);
PIO_ConfigureIt(&pin_usim2_rst, usim2_rst_irqhandler); PIO_ConfigureIt(&pin_usim2_rst, usim2_rst_irqhandler);
PIO_EnableIt(&pin_usim2_rst); PIO_EnableIt(&pin_usim2_rst);
@@ -437,6 +558,7 @@ void mode_cardemu_init(void)
#endif /* DETECT_VCC_BY_ADC */ #endif /* DETECT_VCC_BY_ADC */
cardem_inst[1].ch = card_emu_init(1, 0, 1, SIMTRACE_CARDEM_USB_EP_USIM2_DATAIN, SIMTRACE_CARDEM_USB_EP_USIM2_INT); cardem_inst[1].ch = card_emu_init(1, 0, 1, SIMTRACE_CARDEM_USB_EP_USIM2_DATAIN, SIMTRACE_CARDEM_USB_EP_USIM2_INT);
sim_switch_use_physical(1, 1); sim_switch_use_physical(1, 1);
// TODO check rst and vcc
#endif /* CARDEMU_SECOND_UART */ #endif /* CARDEMU_SECOND_UART */
} }

View File

@@ -80,7 +80,7 @@ void ISR_PhoneRST(const Pin * pPin)
} }
/* /*
* char_stat is zero if no error occured. * char_stat is zero if no error occurred.
* Otherwise it is filled with the content of the status register. * Otherwise it is filled with the content of the status register.
*/ */
void mode_trace_usart1_irq(void) void mode_trace_usart1_irq(void)
@@ -110,7 +110,7 @@ void mode_trace_usart1_irq(void)
rbuf_write(&sim_rcv_buf, c); rbuf_write(&sim_rcv_buf, c);
} else { } else {
TRACE_DEBUG("e %x st: %x\n", c, stat); TRACE_DEBUG("e %x st: %x\n", c, stat);
} /* else: error occured */ } /* else: error occurred */
char_stat = stat; char_stat = stat;
} }

View File

@@ -214,8 +214,8 @@ static void update_wt(uint8_t wi, uint8_t d)
if (0 != d) { if (0 != d) {
wt_d = d; wt_d = d;
} }
wt = wt_wi*960UL*wt_d; wt = wt_wi * 960UL * wt_d;
TRACE_INFO("WT updated to %lu\n\r", wt); TRACE_INFO("WT updated to %lu ETU\n\r", wt);
} }
/*! Allocate USB buffer and push + initialize simtrace_msg_hdr /*! Allocate USB buffer and push + initialize simtrace_msg_hdr

View File

@@ -350,19 +350,22 @@ signed int vsnprintf(char *pStr, size_t length, const char *pFormat, va_list ap)
} }
// Parse type // Parse type
switch (*pFormat) { do {
case 'd': num = 0;
case 'i': num = PutSignedInt(pStr, fill, width, va_arg(ap, signed int)); break; switch (*pFormat) {
case 'u': num = PutUnsignedInt(pStr, fill, width, va_arg(ap, unsigned int)); break; case 'l': num = -1; break; // ignore long qualifier since int == long (and long long is not supported)
case 'x': num = PutHexa(pStr, fill, width, 0, va_arg(ap, unsigned int)); break; case 'd':
case 'X': num = PutHexa(pStr, fill, width, 1, va_arg(ap, unsigned int)); break; case 'i': num = PutSignedInt(pStr, fill, width, va_arg(ap, signed int)); break;
case 's': num = PutString(pStr, va_arg(ap, char *)); break; case 'u': num = PutUnsignedInt(pStr, fill, width, va_arg(ap, unsigned int)); break;
case 'c': num = PutChar(pStr, va_arg(ap, unsigned int)); break; case 'x': num = PutHexa(pStr, fill, width, 0, va_arg(ap, unsigned int)); break;
default: case 'X': num = PutHexa(pStr, fill, width, 1, va_arg(ap, unsigned int)); break;
return EOF; case 's': num = PutString(pStr, va_arg(ap, char *)); break;
} case 'c': num = PutChar(pStr, va_arg(ap, unsigned int)); break;
default:
pFormat++; return EOF;
}
pFormat++;
} while (num < 0);
pStr += num; pStr += num;
size += num; size += num;
} }
@@ -426,12 +429,17 @@ signed int vsprintf(char *pString, const char *pFormat, va_list ap)
signed int vfprintf(FILE *pStream, const char *pFormat, va_list ap) signed int vfprintf(FILE *pStream, const char *pFormat, va_list ap)
{ {
char pStr[MAX_STRING_SIZE]; char pStr[MAX_STRING_SIZE];
char pError[] = "stdio.c: increase MAX_STRING_SIZE\n\r";
// Write formatted string in buffer // Write formatted string in buffer
if (vsprintf(pStr, pFormat, ap) >= MAX_STRING_SIZE) { int rc = vsprintf(pStr, pFormat, ap);
if (rc < 0) {
fputs(pError, stderr); fputs("format string error in ", stderr);
fputs(pFormat, stderr);
return rc;
}
if (rc >= MAX_STRING_SIZE) {
fputs("stdio.c: increase MAX_STRING_SIZE\n\r", stderr);
return rc;
} }
// Display string // Display string
@@ -451,12 +459,17 @@ signed int vfprintf(FILE *pStream, const char *pFormat, va_list ap)
signed int vfprintf_sync(FILE *pStream, const char *pFormat, va_list ap) signed int vfprintf_sync(FILE *pStream, const char *pFormat, va_list ap)
{ {
char pStr[MAX_STRING_SIZE]; char pStr[MAX_STRING_SIZE];
char pError[] = "stdio.c: increase MAX_STRING_SIZE\n\r";
// Write formatted string in buffer // Write formatted string in buffer
if (vsprintf(pStr, pFormat, ap) >= MAX_STRING_SIZE) { int rc = vsprintf(pStr, pFormat, ap);
if (rc < 0) {
fputs_sync(pError, stderr); fputs_sync("format string error in ", stderr);
fputs_sync(pFormat, stderr);
return rc;
}
if (rc >= MAX_STRING_SIZE) {
fputs_sync("stdio.c: increase MAX_STRING_SIZE\n\r", stderr);
return rc;
} }
// Display string // Display string

View File

@@ -36,7 +36,7 @@ const char *get_value_string_or_null(const struct value_string *vs,
int get_string_value(const struct value_string *vs, const char *str); int get_string_value(const struct value_string *vs, const char *str);
char osmo_bcd2char(uint8_t bcd); char osmo_bcd2char(uint8_t bcd);
/* only works for numbers in ascci */ /* only works for numbers in ASCII */
uint8_t osmo_char2bcd(char c); uint8_t osmo_char2bcd(char c);
int osmo_hexparse(const char *str, uint8_t *b, int max_len); int osmo_hexparse(const char *str, uint8_t *b, int max_len);
@@ -60,7 +60,7 @@ do { \
rem -= ret; \ rem -= ret; \
} while (0) } while (0)
/*! Helper macro to terminate when an assertion failes /*! Helper macro to terminate when an assertion fails
* \param[in] exp Predicate to verify * \param[in] exp Predicate to verify
* This function will generate a backtrace and terminate the program if * This function will generate a backtrace and terminate the program if
* the predicate evaluates to false (0). * the predicate evaluates to false (0).
@@ -75,7 +75,7 @@ do { \
/*! duplicate a string using talloc and release its prior content (if any) /*! duplicate a string using talloc and release its prior content (if any)
* \param[in] ctx Talloc context to use for allocation * \param[in] ctx Talloc context to use for allocation
* \param[out] dst pointer to string, will be updated with ptr to new string * \param[out] dst pointer to string, will be updated with ptr to new string
* \param[in] newstr String that will be copieed to newly allocated string */ * \param[in] newstr String that will be copied to newly allocated string */
static inline void osmo_talloc_replace_string(void *ctx, char **dst, const char *newstr) static inline void osmo_talloc_replace_string(void *ctx, char **dst, const char *newstr)
{ {
if (*dst) if (*dst)

View File

@@ -1,4 +1,4 @@
LDFLAGS=`pkg-config --libs libusb-1.0 libosmocore` -losmocore LDFLAGS+=`pkg-config --libs libusb-1.0 libosmocore` -pthread
CFLAGS=-Wall -g CFLAGS=-Wall -g
APPS=simtrace2-remsim simtrace2-remsim-usb2udp simtrace2-list simtrace2-sniff APPS=simtrace2-remsim simtrace2-remsim-usb2udp simtrace2-list simtrace2-sniff
@@ -6,7 +6,7 @@ APPS=simtrace2-remsim simtrace2-remsim-usb2udp simtrace2-list simtrace2-sniff
all: $(APPS) all: $(APPS)
simtrace2-remsim: simtrace2-remsim.o apdu_dispatch.o simtrace2-discovery.o libusb_util.o simtrace2-remsim: simtrace2-remsim.o apdu_dispatch.o simtrace2-discovery.o libusb_util.o
$(CC) -o $@ $^ $(LDFLAGS) -losmosim $(CC) -o $@ $^ $(LDFLAGS) `pkg-config --libs libosmosim libpcsclite`
simtrace2-remsim-usb2udp: usb2udp.o simtrace2-discovery.o simtrace2-remsim-usb2udp: usb2udp.o simtrace2-discovery.o
$(CC) -o $@ $^ $(LDFLAGS) $(CC) -o $@ $^ $(LDFLAGS)

View File

@@ -159,7 +159,7 @@ int dev_find_matching_interfaces(libusb_device *dev, int class, int sub_class, i
out[out_idx].vendor = dev_desc.idVendor; out[out_idx].vendor = dev_desc.idVendor;
out[out_idx].product = dev_desc.idProduct; out[out_idx].product = dev_desc.idProduct;
out[out_idx].addr = addr; out[out_idx].addr = addr;
strncpy(out[out_idx].path, path, sizeof(out[out_idx].path)); strncpy(out[out_idx].path, path, sizeof(out[out_idx].path)-1);
out[out_idx].path[sizeof(out[out_idx].path)-1] = '\0'; out[out_idx].path[sizeof(out[out_idx].path)-1] = '\0';
out[out_idx].configuration = conf_desc->bConfigurationValue; out[out_idx].configuration = conf_desc->bConfigurationValue;
out[out_idx].interface = if_desc->bInterfaceNumber; out[out_idx].interface = if_desc->bInterfaceNumber;

View File

@@ -1,7 +1,8 @@
/* simtrace2-remsim - main program for the host PC to provide a remote SIM /* simtrace2-remsim - main program for the host PC to provide a remote SIM
* using the SIMtrace 2 firmware in card emulation mode * using the SIMtrace 2 firmware in card emulation mode
* *
* (C) 2016 by Harald Welte <hwelte@hmw-consulting.de> * (C) 2016-2017 by Harald Welte <hwelte@hmw-consulting.de>
* (C) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -217,7 +218,7 @@ static int cardem_request_pb_and_rx(struct cardem_inst *ci, uint8_t pb, uint8_t
/*! \brief Request the SIMtrace2 to transmit a Procedure Byte, then Tx */ /*! \brief Request the SIMtrace2 to transmit a Procedure Byte, then Tx */
static int cardem_request_pb_and_tx(struct cardem_inst *ci, uint8_t pb, static int cardem_request_pb_and_tx(struct cardem_inst *ci, uint8_t pb,
const uint8_t *data, uint8_t data_len_in) const uint8_t *data, uint16_t data_len_in)
{ {
struct msgb *msg = st_msgb_alloc(); struct msgb *msg = st_msgb_alloc();
struct cardemu_usb_msg_tx_data *txd; struct cardemu_usb_msg_tx_data *txd;
@@ -366,9 +367,9 @@ static int process_do_status(struct cardem_inst *ci, uint8_t *buf, int len)
struct cardemu_usb_msg_status *status; struct cardemu_usb_msg_status *status;
status = (struct cardemu_usb_msg_status *) buf; status = (struct cardemu_usb_msg_status *) buf;
printf("=> STATUS: flags=0x%x, fi=%u, di=%u, wi=%u wtime=%u\n", printf("=> STATUS: flags=0x%x, F=%u, D=%u, WI=%u WT=%u\n",
status->flags, status->fi, status->di, status->wi, status->flags, status->f, status->d, status->wi,
status->waiting_time); status->wt);
return 0; return 0;
} }
@@ -484,7 +485,8 @@ static int process_usb_msg(struct cardem_inst *ci, uint8_t *buf, int len)
static void print_welcome(void) static void print_welcome(void)
{ {
printf("simtrace2-remsim - Remote SIM card forwarding\n" printf("simtrace2-remsim - Remote SIM card forwarding\n"
"(C) 2010-2017 by Harald Welte <laforge@gnumonks.org>\n\n"); "(C) 2010-2017, Harald Welte <laforge@gnumonks.org>\n"
"(C) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>\n\n");
} }
static void print_help(void) static void print_help(void)
@@ -501,6 +503,7 @@ static void print_help(void)
"\t-I\t--usb-interface\tINTERFACE_ID\n" "\t-I\t--usb-interface\tINTERFACE_ID\n"
"\t-S\t--usb-altsetting ALTSETTING_ID\n" "\t-S\t--usb-altsetting ALTSETTING_ID\n"
"\t-A\t--usb-address\tADDRESS\n" "\t-A\t--usb-address\tADDRESS\n"
"\t-H\t--usb-path\tPATH\n"
"\n" "\n"
); );
} }
@@ -744,9 +747,7 @@ int main(int argc, char **argv)
st_modem_sim_select_remote(ci->slot); st_modem_sim_select_remote(ci->slot);
/* set the ATR */ /* set the ATR */
uint8_t real_atr[] = { 0x3B, 0x9F, 0x96, 0x80, 0x1F, 0xC7, 0x80, 0x31, uint8_t real_atr[] = { 0x3B, 0x00 }; // the simplest ATR
0xA0, 0x73, 0xBE, 0x21, 0x13, 0x67, 0x43, 0x20,
0x07, 0x18, 0x00, 0x00, 0x01, 0xA5 };
atr_update_csum(real_atr, sizeof(real_atr)); atr_update_csum(real_atr, sizeof(real_atr));
cardem_request_set_atr(ci, real_atr, sizeof(real_atr)); cardem_request_set_atr(ci, real_atr, sizeof(real_atr));

View File

@@ -51,6 +51,19 @@
#include <osmocom/sim/class_tables.h> #include <osmocom/sim/class_tables.h>
#include <osmocom/sim/sim.h> #include <osmocom/sim/sim.h>
/* as of August 26, 2018 we don't have any released libosmocore version which includes those
* definitions yet. Let's ensure some backwards compatibility: */
#ifndef GSMTAP_SIM_APDU
#define GSMTAP_SIM_APDU 0x00 /* APDU data (complete APDU) */
#define GSMTAP_SIM_ATR 0x01 /* card ATR data */
#define GSMTAP_SIM_PPS_REQ 0x02 /* PPS request data */
#define GSMTAP_SIM_PPS_RSP 0x03 /* PPS response data */
#define GSMTAP_SIM_TPDU_HDR 0x04 /* TPDU command header */
#define GSMTAP_SIM_TPDU_CMD 0x05 /* TPDU command body */
#define GSMTAP_SIM_TPDU_RSP 0x06 /* TPDU response body */
#define GSMTAP_SIM_TPDU_SW 0x07 /* TPDU response trailer */
#endif
/* transport to a SIMtrace device */ /* transport to a SIMtrace device */
struct st_transport { struct st_transport {
/* USB */ /* USB */

View File

@@ -85,4 +85,5 @@ int main(int argc, char **argv)
{ {
libusb_init(NULL); libusb_init(NULL);
find_devices(); find_devices();
return 0;
} }

View File

@@ -35,7 +35,7 @@
#include <libusb.h> #include <libusb.h>
#include "simtrace.h" #include "simtrace_usb.h"
#include "simtrace_prot.h" #include "simtrace_prot.h"
#include "apdu_dispatch.h" #include "apdu_dispatch.h"
#include "simtrace2-discovery.h" #include "simtrace2-discovery.h"
@@ -243,7 +243,7 @@ int main(int argc, char **argv)
libusb_set_pollfd_notifiers(NULL, &libusb_fd_added_cb, &libusb_fd_removed_cb, NULL); libusb_set_pollfd_notifiers(NULL, &libusb_fd_added_cb, &libusb_fd_removed_cb, NULL);
g_devh = libusb_open_device_with_vid_pid(NULL, SIMTRACE_USB_VENDOR, SIMTRACE_USB_PRODUCT); g_devh = libusb_open_device_with_vid_pid(NULL, USB_VENDOR_OPENMOKO, USB_PRODUCT_OWHW_SAM3);
if (!g_devh) { if (!g_devh) {
fprintf(stderr, "can't open USB device\n"); fprintf(stderr, "can't open USB device\n");
goto close_exit; goto close_exit;