76 Commits

Author SHA1 Message Date
Harald Welte
eb8fbc0296 fw/qmod: enable modem RESET by default at boot
When the uC firmware starts, assert the (high-active) _RESET GPIOs,
which will cause the transistors to drive the mPCIe slot !PERST
low.

There is of course a short instance of time between the uC reset
until it executes wwan_perst_init(). To avoid this, a hardware
pull-up would have to be re-worked onto the _RESET[1..4] signals
on the PCBA

Change-Id: I8742fefa4bf02e728e34d5d8cbc0fda771e78ffb
2021-06-06 11:46:50 +02:00
Harald Welte
9292d22726 WIP: firmware: sniffer: inbound USB handling
Change-Id: Ic953148600d82285281abcb573a07e2e9b8082a7
2021-06-06 11:46:50 +02:00
Harald Welte
d2bc858ddf firmware: More common infrastructure for USB handling
Let's move low-level handling of endpoint queue refill from the
individual apps into common/shared code.

Now the main simply has to call usb_process() for every interface,
and inbound messages will be dispatched to call-back functions from
there.

Change-Id: Ic6f9c6c1ffdbb0c9c3b284371ecc83b17e3be746
2021-06-06 11:46:49 +02:00
Harald Welte
29de264d6e HACK: Solve weird problem wih lost OUT transfer on ping-pong endpoint
This adds an unconditional endpoint reset procedure to every SET_FEATURE(UnHalt).

It doesn't really make sense that this is required, *particularly* as
we *MUST NOT* set bEndpoint->bank to 0 here.

Without this patch, I'm observing the following problem:

Every first OUT transfer after a SET_INTERFACE + UNHALT on a bulk endpoint
is lost. "lost" means that it completes successfully on the host, can
be seen completing successfully with an ACK on a USB bus analyzer,
but still doesn't show up in the firmware.  No Endpoint Interrupt
is generated.

This can be reproduced by calling libusb_set_interface_alt_setting()
from the host and then submitting a single OUT transfer.

Change-Id: I18ed530e617baddf76e8f9829512443ce2a76e0d
2021-06-06 11:46:49 +02:00
Kévin Redon
07fda1e706 card_emu: use edge-triggered VCC ADC logic
Before this patch, we used to st ci->vcc_active depending on the
instantaneous ADC reading of VCC.  Is it > .5v, we claim VCC is active,
and if it's below, VCC is inactive.

With this patch we move to an edge triggered approach: Only change
ci->vcc_active if the previous reading was different from the current
reading.

FIXME: why?

Change-Id: I71b703162219484e43638f1f2f692e9dd554ef55
2021-06-06 11:46:49 +02:00
Harald Welte
ed4ca25730 Introduce simtrace2-tool
The simtrace-tool isa command line tool which can be used to e.g.
manually request a modem reset.

Change-Id: I3a8896ac2b3caef7590b51118359e5caed820a40
2021-06-06 11:46:49 +02:00
Harald Welte
69c32f2e38 simtrace2-list: Use osmo_st2_compatible_dev_ids[]
we shouldn't use a local copy of the device id list, which is already
outdated now that OCTSIMTEST support has been added to libosmo-st2

Change-Id: I2231006b94c33fe3b28ce37b0d54c67206751058
2021-06-06 11:46:49 +02:00
Harald Welte
53dfaa0aab don't printf() directly from library code, go via libosmocore logging
This allows us to use different log levels, and permits the user to use
other log targets.

Change-Id: I08ef7cfa5d8734882746a11ccd5f059d757401ae
2021-06-06 11:46:49 +02:00
Harald Welte
f2e924c4aa firmware: octsimtest: ensure all card_insert GPIO are 0 after reset
Change-Id: I3c3744673ba53750cb66aa5023c8228edb006bfc
2021-06-06 11:46:49 +02:00
Harald Welte
efb47b3fae firmware: octsimtest: Add i/I command for setting card-insert via I2C GPIO
Change-Id: Ie1483ccf8465df0d640d55e50421fda910dced4a
2021-06-06 11:46:49 +02:00
Harald Welte
2b1d1e6d92 firmware: octsimtest: Fix disabling the card_insert signal
Back in I8c9b0c3d862a967832134b24252577739182da62 we added support
for enabling the card_insert signal, but not for explicit disable
of it.  Let's fix that.

Change-Id: I6f32bde60674119c9912e51059a53b5ee74d074a
2021-06-03 15:06:58 +02:00
Harald Welte
e2971dee2a firmware: octsimtest: use TRACE_* macros instead of direct printf
Change-Id: I41864bc2f64905a4f2ccb50769b1840e8a490c76
2021-06-03 14:37:45 +02:00
Harald Welte
731e199fc4 firmware: octsimtest: Support SIMTRACE_MSGT_DT_CEMU_CARDINSERT
The octsimtest board can control the card-insert contact of the OCTSIM
under test via an external I2C gpio multiplexer; let's add support for
that.

Change-Id: I8c9b0c3d862a967832134b24252577739182da62
2021-06-03 14:37:45 +02:00
Harald Welte
f69a60f255 firmware: cardem: re-factor CARDINSERT command processing
move it out of the general command dispatch switch statement
and into a separate function.

Change-Id: Ia40c3d9999be68248da0dcc69d298450ca6e4869
2021-06-03 14:37:45 +02:00
Harald Welte
dd5794c975 firmware: octsimtest: mcp23017 initializaiton
* driver should not have hard-coded understanding about I/O directions
* board code should pass the I/O direction to driver
* board code should use the correct I/O directions (A0..7, B0: output)

Change-Id: Id4a8e012a33cee01bb489e612e17920760b9be59
2021-06-03 14:37:45 +02:00
Harald Welte
d46f6bae2c firmware: octsimtest: Make slot mux configurable via USB
Change-Id: I4cdb250d2e1dbc5b8b0169f8b7c21e288b492e1d
2021-06-03 14:37:43 +02:00
Harald Welte
3561fc4c8b firmware: octsimtest: Fix IO_DIR pin definition
Change-Id: I776c9106bcd4ceb24a5d50ea05c6025dedb73822
2021-06-03 14:32:36 +02:00
Harald Welte
b69f5a85b3 contrib/jenkins.sh: Build 'cardem' app for 'octsimtest' board
Change-Id: Ia38bbb85c2828ab7307ffe688e50d7cdf70d6d39
2021-06-03 09:36:10 +02:00
Harald Welte
4996d7d634 octsimtest: Adjust VCC voltage thresholds (resistive VCC divider)
octsimtest has a resistive voltage divider in front of the VCC ADC
in order to also detect 5V.  We must make the thresholds board-specific
and adjust them for octsimtest.

Change-Id: I9e4adb4f349d2d838ea4100eb49271f3a0e7a2a5
2021-06-03 09:36:10 +02:00
Harald Welte
054d7ca499 cardem-pcsc: initialize libosmocore logging
Change-Id: I815d39190e944d9512ffc8e5f581515d7be9834f
2021-06-02 22:57:10 +02:00
Harald Welte
5b825beb41 octsimtest: Switch direction of I/O level shifter depending on uart tx / rx
Contrary to other hardware designs, octsimtest has a level-shifter in
the I/O line to support testing with 1.8, 3 and 5V.  This level shifter
is bi-directional, but the direction needs to be explicitly specified
via the SIM_IO_DIR signal attached to PA26.

Change-Id: I44171363b5bd69d6049b12c86f8143be83557cb2
2021-06-02 22:57:10 +02:00
Harald Welte
31d103b9f6 octsimtest: most code for support of this new board
* code for controlling the Card slot + frequencyt divider muxes
* put everything in place to build cardem application for it

Change-Id: I7e03e0c0f2999a1ce2dad966d98e22033fa58465
2021-06-02 22:56:12 +02:00
Harald Welte
73466e2b89 octsimtest: remove lots of unused #defines
The octsimtest board only supports cardem mode, not 'ccid'
nor 'sniffer'.  Remove related GPIO pin #defines from board.h

Change-Id: I43e8631d945ba183a1e5b1e37dd4565adb377154
2021-06-02 22:56:04 +02:00
Harald Welte
913c86b95d Add usb product ID of sysmoOCTSIMTEST
This is a custom board for production testing of the sysmoOCTSIM,
an 8-slot smart card reader.

Change-Id: I65839be50ac896c76f34755fb2800f836f6cdae4
2021-06-02 10:09:40 +02:00
Harald Welte
0516464620 assert: Use printf_sync() to ensure printing of assert / panic
Change-Id: Icc202e60445d9be1cdcd61176db5ed1704d583e7
2021-06-02 09:12:35 +02:00
Harald Welte
c1033c8611 simtrace2-cardem-pcsc: Reset the real card if reader resets cardem
When the cardem detects a reset from the phone/modem, pass this on
to the actual card via the PC/SC reader.  This is important to
reset the card state whenever requested by the stack/driver on the
phone/modem.

Change-Id: I7056476c5f81e8aa8f550afb86bf2380d1497ebb
Depends: libosmocore 20199da02d37a6d284915a27ec12641e79b8781c
2021-06-01 21:09:05 +02:00
Harald Welte
644c2131ca simtrace2-cardem-pcsc: Decode STATUS flags to strings
SIMtrace IRQ STATUS: flags=0x13, fi=9, di=6, wi=10 wtime=9600 (RESET VCC  CLK )

is more understandable than

SIMtrace IRQ STATUS: flags=0x13, fi=9, di=6, wi=10 wtime=9600

Change-Id: I5bbfa1d99ebee4b297d894a5f444dbe743c7ab70
2021-06-01 21:09:05 +02:00
Harald Welte
796501293d Revert "cardem: disable upload for simtrace2"
This reverts commit baa62777c8 which
deleted simtrace-cardem builds to prevent them from being published.

Change-Id: I63fd4bea2985fcc87f202d8b69a4f24661858185
2021-06-01 18:47:37 +02:00
Harald Welte
e33c2907bc jenkins.sh: build 'cardem' firmware also for simtrace board
Now that it is supported, we should also build + publish the related
binaries.

Change-Id: I9231503b865adc863959d74d98e7f24f83c293e9
2021-06-01 18:38:25 +02:00
Harald Welte
0f75d6ef1e simtrace board.h: Enable HAVE_CARDEM if we build the cardem firmware
likewise, enable HAVE_SNIFFER currently only if we build the sniffer
firmware.

It's been many years too long to finally get those all merged in one
firmware :(

Change-Id: Ib433f180746f75458a44f4988643465bd846b04b
2021-06-01 18:38:21 +02:00
Harald Welte
c690a1f130 st2-cardem-pcsc: Use ATR of real card by default
Before this patch, we would always use either a hard-coded default
ATR from the source code, or we would use one that the user specified
on the command line.

The more sane default is to pass-through the real ATR of the card.

Change-Id: I75bf618a6b0d983727de4c2f19b4b48ec3e12af8
Closes: OS#5107
Requires: libosmocore.git 22117a7164012d6d88fc202cd63df79c6068484d
2021-04-25 21:30:47 +02:00
Harald Welte
8e6ba005d4 st2-cardem-pcsc: Fix goto-in-while mess
There's some code that wasnts to goto within the while loop, and there's
some other code that wants to goto after the while loop.  Don't jump
from outside the while loop into the while loop.

Change-Id: Ic2a94ad034dd259f15712687443b569f0d18ff3f
2021-04-25 21:30:47 +02:00
Harald Welte
206d613b4d contrib/jenkins.sh: Switch from rita -> ftp.osmocom.org
We should use service-aliases and not the primary host name, as
that makes migration between machines hard.

Change-Id: I34b18457268ae6f8ae3a053c5424210074a4d52e
2021-04-22 11:21:12 +02:00
Harald Welte
7b681981ea card_emu: Fix computation of waiting time
As we store the waiting time (WT) in 'etu', we must adjust the formula
from ISO 7816-3.  The 'Fi' component in the formula only exists to
compute clock cycles from the etu, which we don't need here.

Without this patch, the waiting time would be way too large (by a factor
of 372 in the default case).

Change-Id: Ia21bc7303f9b38834b5b1753983ed2a99bfc7d95
Related: OS#1704
2021-04-08 21:28:37 +00:00
Harald Welte
e410842d8e card_emu: Fix USART timer, particularly in re-start situations
The existing code started the timer once (and expired once) but didn't
properly handle re-starting of the timer.  Neither did it handle
the 'half time expiration' case.  If we want to call a function after
half the WT expiring, we must of course program the hardware for half
the timeout, and not the full timeout...

Change-Id: Ia999d97f835c27597fcd1cf7ac78bac0ab9c98c1
Related: OS#1704
2021-04-08 21:28:37 +00:00
Harald Welte
752bc7f4b5 card_emu: Use USART timeout for waiting time
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 there
(contrary to other boards) the I/O signal is not wired to a TIO pin
of the timer/counter block, and hence Rx/Tx data cannot reset that
timer/counter.

As a result of this migration, cardem is now supported not only on
owhw + qmod, but also on the simtrace board.

The guts of this change have been lifted out of Change-Id
Ibcb2c8cace9137695adf5fb3de43566f7cfb93b5 by Kevin Redon, which was
unfortunately touching various different topics at the same time and
hence was split up. Some improvements are the introduction of the
ENABLE_TX_TIMER_ONLY mode, which avoids the USART interrupt handler
getting hammered with TXRDY between release of RST and start of the ATR.

Change-Id: Ibcb2c8cace9137695adf5fb3de43566f7cfb93b5
Related: OS#1704
2021-04-08 21:28:37 +00:00
Harald Welte
7f421ef014 card_emu: explicitly initialize PTS and TPDU states
Those are already initialized at various transitions of the master
7816 FSM, but let's properly initialize them at start-up, too.

Change-Id: I81b2a8ef3284559164700d94717e4ccf008f53df
2021-04-08 21:28:37 +00:00
Harald Welte
a708ea1d99 card_emu: improve reset detection conditions
* enter ISO_S_WAIT_RST when RST is asserted
* enter ISO_S_WAIT_ATR only when we RST is released while in state ISO_S_WAIT_RST

Change-Id: I620333aa8d45561a8028b948955a27f667b58406
2021-04-08 21:28:37 +00:00
Harald Welte
c1ffc8a603 iso7816_fidi: Add iso7816_3_ prefix to symbols; fix terminology
Fi/Di are not the index into the table, but the contents of the table
as resolved by Fi_index / Di_index.  Let's clarify the terminology.

Change-Id: If364e08e7c9a3a9707e6d54b9267c6a7c088e415
2021-04-08 21:28:37 +00:00
Harald Welte
79f0ea73a2 card_emu: Clarify and differentiate F/Fi/F_index/Fi_index
The ISO7816 spec terms are well-defined, let's not abuse them. We used
to consider "Fi" as the "index into the table of F values", while the
spec actually considers Fi as the initial value for F.

Let's make sure we use the terms quite clearly:
* Fi and Di are the initial values for F and D
* F*_index and D*_index are the indexes into the ISO7816-3 Tables

Furthermore, let's track Fi separately from F, as e.g. the waiting
time definition only considers Fi as indicated in the ATR, despite
an actually different F value might have been negotiated via PTS
meanwhile.

Change-Id: Ieb2425e8380a81b79df7b2bd072902994e9c3ee7
Related: OS##1704
2021-04-08 21:28:37 +00:00
Harald Welte
9454a062b5 card_emu: Rename fi to Fi and di to Di
As we will soon introduce the distinction between Fi and F, we should
use uppercase letters, as lower-case 'f' is defined in ISO7816-3 as
the frequency, which is different from the upper-case 'F'.

Change-Id: Iaede621551520576e9b9af878fa46fbc88e59c2a
2021-04-08 21:28:37 +00:00
Kévin Redon
6b7f8d142f 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
Related: OS#1704
2021-04-08 21:28:37 +00:00
Harald Welte
9c95162d5c card_emu: waiting_time is stored in etu, not clocks.
The comment didn't reflect the source.  I checked all users and
the code consistently stores the waiting time in units of 'etu'.

Change-Id: I2bc4a7c19cee5fb487ad639ee48ecaea706f6172
2021-04-08 21:28:37 +00:00
Oliver Smith
878fadd74f firmware: disable stack protector by default
Disable stack protector for all boards/apps by default, not only
qmod-dfu. Use 'make STACK_PROTECTOR=1' to enable.

This was recommened by Eric:
"I'd argue that we do not want this in general, since it adds canaries
to all functions that deal with buffers, and therefore impacts the
overall timing in a non determinstic way depending on inlining and
optimizations, while contributing nothing in non debug builds."

Related: OS#5081
Change-Id: I30ad97f231ea5b401def650bc9adc7e9f2770df0
2021-04-08 12:04:47 +02:00
Oliver Smith
9e0e0ddd5a firmware: qmod-dfu: disable stack protector
Prevent build failure on debian 9, ubuntu 20.04, 20.10, where
bin/qmod-dfu-flash.elf does not fit the ROM.

Fixes: OS#5081
Change-Id: I9fffe4c323094679062428f41a4246b1c1b30ca2
2021-04-07 15:23:55 +02:00
Harald Welte
7a3d93682f Revert "add library providing ISO 7816-3 utilities"
This reverts commit 4a29f64cbe.

The code replicates to a large extent what is already present in iso7816_fidi.c
and I have serious doubts about the correctness of the computation in
its iso7816_3_calculate_wt() function.

Change-Id: I80dab4401d13306d573a6a35ce8729d2acc141e4
2021-04-06 02:17:38 +02:00
Harald Welte
01868775ba Revert "add ISO 7816-3 library to remsim project"
This reverts commit 4a58c08d67.

The code replicates to a large extent what is already present in iso7816_fidi.c
and I have serious doubts about the correctness of the computation in
its iso7816_3_calculate_wt() function.

Change-Id: I3f26da4e9aa8d7b0f4b4b7992269cf365a643ec7
2021-04-06 02:17:37 +02:00
Harald Welte
9ec3de9346 simtrace2-cardem-pcsc: Make it work again
* support Interrupt STATUS notifications
* use osmocom libusb abstraction
* use asynchronous URBs for interrupt + bulk

Change-Id: Ib04798572295f25477719124530b6584780c5b75
2021-04-05 20:37:00 +02:00
Kévin Redon
b218cc38d0 minor add comments
this is just to better understand the flow

Change-Id: I045286836176da729cc8c863866d6f6aa3836592
2021-04-04 23:01:41 +02:00
Kévin Redon
50360e0706 rename PIN_PHONE_{CLK,IO} to PIN_USIM1_{CLK,IO}
While this differs from tha naming in the schematics ({CLK,IO}_PHONE),
this matches the naming scheme used for USIM2 and the naming on other
boards.

Change-Id: I486b14260faec897e8c8698c4b7987bf36492497
2021-04-04 23:00:54 +02:00
Kévin Redon
4a58c08d67 add ISO 7816-3 library to remsim project
Change-Id: I99f3fecbc00d2379c3a6dc457b047c6fee41c292
2021-04-04 21:02:27 +02:00
Kévin Redon
4a29f64cbe 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
2021-04-04 21:02:10 +02:00
Kévin Redon
debbf3c6fa 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
2021-04-04 18:06:51 +00:00
Eric Wild
0b1a3b4105 cardem: choose a more reasonable default ATR
PCSCd does not like invalid ATRs

Change-Id: I1eebfdc06be55931c2e80e2b515ac3a559737c38
2021-04-04 19:54:19 +02:00
Eric Wild
9316890a39 firmware: allow verbose builds
make V=1 can be used to echo all compilation commands, which is useful
because it allows IDEs to parse the gcc output in oder to properly index
the source files using the actual defines passed to the compiler.

Change-Id: I25c41dff89302a73ddd2a4aaba7cb14912fac3b8
2021-04-04 16:16:24 +00:00
Eric Wild
19cd3b0f71 firmware: do not allow undefined symbols
For some reason undefined symbols were downgraded to warnings, which
means building a firmware that calls missing functions  (= address zero)
was perfectly fine, which of course made development more exciting....

This applies to builtins, too, printf of one char gets downgraded to
putchar, which we don't have, so disable builtins.

Change-Id: I492f41ad4162b9d07b1881ae4aed019db2dff8b5
2021-04-04 16:16:24 +00:00
Kévin Redon
a1579ff4b0 minor: use same LED pattern for cardem as other applications
Change-Id: I5608c3312b648c0d59f79338ef1f97b6fe08f5b9
2021-04-04 15:02:19 +00:00
Oliver Smith
62ad58ad56 contrib/prepare_upload.sh: fix cd problems
Call the script from the proper directory, and cd into the topdir on top
of the script. Fixes:
/build/contrib/jenkins.sh: line 71: contrib/prepare_upload.sh: No such file or directory

Related: OS#4413
Change-Id: Icbfaa5579aab887830ca90b24a2e322df8d98f4f
2021-03-08 08:37:06 +01:00
Oliver Smith
1031d9b884 firmware: create duplicate files for upload only
Don't create copies of firmware files with version strings appended in
the normal build. Only do this before uploading the firmware files.

I have verified that "make" before this change and
"make; contrib/prepare_upload.sh" after produce the same files.

Close: OS#4413
Change-Id: I118a4ff397a178281c26a6b98112fa66b6f049ab
2021-03-05 15:38:48 +01:00
Oliver Smith
199cd431f3 gitignore: add firmware/apps/*/usb_strings.txt.patched
Change-Id: Ic99a5ae69ed755e6f74a1392678dcf71ab69e0d8
2021-03-05 15:04:06 +01:00
Oliver Smith
90e351f4a7 host: use git-version-gen/tarball-v. from topdir
Use .tarball-version from the topdir, because it only gets written there
when generating the OBS package. Remove the duplicate git-version-gen
script and use the one from the topdir to generate a version string if
building from the git tree.

Related: OS#4413
Change-Id: I4b197a218ab44632ff182ffbd72e15c2b20db341
2021-03-05 12:41:22 +01:00
Oliver Smith
09c3d45d6e firmware/Makefile: fix UNKNOWN in OBS packages
Fix having the version set to UNKNOWN in all packages built by OBS. The
osmo-ci.git scripts generating the source packages to be built by OBS
generate a ".tarball-version" file with a version string like
"0.7.0.70-657c", but it did not get used because the path was wrong.

Related: OS#4413
Related: https://osmocom.org/projects/cellular-infrastructure/wiki/Git-version-gen
Change-Id: Ic0b06011a604beec7c1c907c2c6e4ae927456e2e
2021-03-05 12:41:22 +01:00
Oliver Smith
810ecc5374 d/source/format: new file
Fixes:
  dpkg-source: warning: no source format specified in debian/source/format, see dpkg-source(1)

Related: OS#4413
Change-Id: I4c474547233ebb87a1246b01fbd7ff8879921c21
2021-03-05 12:41:22 +01:00
Eric
657cce1817 dfu: let the device reset itself
dfu flashing the ST12 was easy, but i was never able to
get ST34 into dfu mode. Changing the firmware so it resets
itself just like the octsim instead of starting a timer and
waiting for a reset from the host made it work every time for me.

Change-Id: Ida636ec925f40d6d56551f170150181350d03bbd
2021-01-29 11:02:27 +00:00
Harald Welte
aadd995664 remove old pre-autoconf makefile
Change-Id: Icd519a69a5cb1950daa79df4d9864e8dea091289
2020-10-27 15:55:07 +01:00
Harald Welte
0bb58e0b3c Update README
it has been long out of date.

Change-Id: I1137f33c5647f4d57a44224ee7259f3496edf1c4
2020-10-27 15:55:07 +01:00
Harald Welte
b1a56e0f77 rename simtrace2-remsim to simtrace2-cardem-pcsc
This renaming is to avoid any confusion with the osmo-remsim
project, living in its separate git repository.

The simtrace2-cardem-pcsc doesn't feature any 'remote' part.  Rather,
it emulates the SIM card interface towards the device/phone/modem,
and forwards it to a local PC/SC card reader.

Change-Id: Ic15f0a89964a72fe3ab7a5145a073720f6207e24
2020-10-27 15:48:37 +01:00
Harald Welte
80b8877a23 remove usb2udp
The UDP based forwarding really only ever was a quick hack to
demonstrate the capabilities.

Meanwhile, we've had the proper osmo-remsim project implemented,
which provides a much more reliable and comprehensive way of
managing SIM card emulation devices (SIMtrace2, sysmoQMOD, ...)
and collection of card readers (sysmoOCTSIM or any other PC/SC
supported readers).

Hence, remove the "UDP forwarding part.

Change-Id: Ia4b9447b95872b6e0dda6dca644f1ed4a87355a0
2020-10-27 15:48:35 +01:00
Leonard Hübner
1372aca28e remsim: adding cli argument to set the atr
Change-Id: I554b515e7954148f9ca5ba29417699da70b0945b
2020-10-27 15:34:36 +01:00
Harald Welte
a124c1714e migrate from BSC_FD_* to OSMO_FD_*
Change-Id: I01c834537e18eacdd1658f88a4b4a6d4690d87a6
2020-10-18 22:32:24 +02:00
Harald Welte
3907085239 dfu: Save another 60 bytes by changing the way we print horizontal lines
Change-Id: I1660a04fb3e42200bc2fdd23aa114119620125a1
2020-08-16 15:51:14 +02:00
Harald Welte
9866c7373c dfu: Shrink code by 144 bytes (by not calling PIO_InitializeInterrupts)
We are not using any PIO interrupts from DFU mode.  It's only used in
the main application firmware (verified by "git grep PIO_ConfigureIt")

Change-Id: Id1447af519df3183061f3d3f156a8dd84789af16
2020-08-16 15:47:00 +02:00
Harald Welte
1afb70a69d firmware: fix builds with gcc stack smashing protection enabled
On Ubuntu 20.04 when builiding dpkg packages, even when cross-compiling
firmware, gcc stack smashing protection is enabled.  Let's provide what
is minimally required in order to sucessfully complete builds on such
platforms.

Change-Id: Ic2f68f16b0730e7b5db17c30effc29a2909d1997
Closes: OS#4687
2020-08-05 11:59:26 +02:00
Harald Welte
859f1b0974 Introduce support for asynchronous USB transmission
libosmo-simtrace2 traditionally had only supported blocking, synchronous
I/O, while other osmocom programs such as remsim-client used
asynchronous USB I/O.

Using async USB I/O for IRQ + IN transfers while using blocking I/O for
OUT transfers doesn't seem to work reliably, so we have to offer a way
to perform the OUT transfers generated within libosmo-simtrace2 in async
mode.

Change-Id: Ib8939bdb7f533cd20a34a30a97f12b782b9816c2
2020-05-25 23:00:20 +02:00
Oliver Smith
4e73aaeba8 contrib: integrate RPM spec
Remove OpenSUSE bug report link, set version to 0.0.0, make it build with CentOS 8 etc.

Related: OS#4550
Change-Id: I8595642bc07bf3044720942a0f1802448920cb50
2020-05-19 15:59:01 +02:00
Oliver Smith
45e34c69de contrib: import RPM spec
Copy the RPM spec file from:
https://build.opensuse.org/project/show/home:mnhauke:osmocom:nightly

Related: OS#4550
Change-Id: I47ae01afb38fb18c462bf73501b49d6dc5d9f57f
2020-05-19 15:58:59 +02:00
59 changed files with 1663 additions and 1504 deletions

5
.gitignore vendored
View File

@@ -18,7 +18,8 @@ tags
*.bin
*.p
host/simtrace2-list
host/simtrace2-remsim
host/simtrace2-remsim-usb2udp
host/simtrace2-cardem-pcsc
host/contrib/simtrace2.spec
usb_strings_generated.h
firmware/usbstring/usbstring
firmware/apps/*/usb_strings.txt.patched

View File

@@ -5,9 +5,6 @@ This is the repository for the next-generation SIMtrace devices,
providing abilities to trace the communication between (U)SIM card and
phone, remote (U)SIM card forward, (U)SIM man-in-the-middle, and more.
This is under heavy development, and right now it is not surprising if
things still break on a daily basis.
NOTE: Nothing in this repository applies to the SIMtrace v1.x hardware
or its associated firmware. SIMtrace v1.x is based on a different CPU /
microcontroller architecture and uses a completely different software
@@ -16,12 +13,6 @@ stack and host software.
Supported Hardware
------------------
At this point, the primary development target is still the OWHW + sysmoQMOD
device, but we expect to add support for a SAM3 based SIMtrace hardware
board soon.
The goal is to support the following devices:
* Osmocom SIMtrace 1.x with SAM3 controller
** this is open hardware and schematics / PCB design is published
* sysmocom sysmoQMOD (with 4 Modems, 4 SIM slots and 2 SAM3)
@@ -37,3 +28,11 @@ This repository contains several directory
* firmware - the firmware to run on the actual devices
* hardware - some information related to the hardware
* host - Programs to use on the USB host to interface with the hardware
The host software includes
* libosmo-simtrace2 - a shared library to talk to devices running the simtrace2 firmware
* simtrace2-list - list any USB-attached devices running simtrace2 firmware
* simtrace2-sniff - interface the 'trace' firmware to obtain card protocol traces
* simtrace2-cardem-pcsc - interface the 'cardem' fimrware to use a SIM in a PC/SC reader

10
TODO-RELEASE Normal file
View File

@@ -0,0 +1,10 @@
# When cleaning up this file: bump API version in corresponding Makefile.am and rename corresponding debian/lib*.install
# according to https://osmocom.org/projects/cellular-infrastructure/wiki/Make_a_new_release
# In short: https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html#Updating-version-info
# LIBVERSION=c:r:a
# If the library source code has changed at all since the last update, then increment revision: c:r + 1:a.
# If any interfaces have been added, removed, or changed since the last update: c + 1:0:0.
# If any interfaces have been added since the last public release: c:r:a + 1.
# If any interfaces have been removed or changed since the last public release: c:r:0.
#library what description / commit summary line
simtrace2 API/ABI change osmo_st2_transport new member

View File

@@ -31,6 +31,7 @@ BUILDS=""
BUILDS+="simtrace/dfu simtrace/trace simtrace/cardem "
BUILDS+="qmod/dfu qmod/cardem "
BUILDS+="owhw/dfu owhw/cardem "
BUILDS+="octsimtest/cardem "
cd $TOPDIR/firmware
for build in $BUILDS; do
@@ -66,15 +67,16 @@ make dist
if [ "x$publish" = "x--publish" ]; then
echo
echo "=============== UPLOAD BUILD =============="
$TOPDIR/contrib/prepare_upload.sh
cat > "/build/known_hosts" <<EOF
[rita.osmocom.org]:48 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDgQ9HntlpWNmh953a2Gc8NysKE4orOatVT1wQkyzhARnfYUerRuwyNr1GqMyBKdSI9amYVBXJIOUFcpV81niA7zQRUs66bpIMkE9/rHxBd81SkorEPOIS84W4vm3SZtuNqa+fADcqe88Hcb0ZdTzjKILuwi19gzrQyME2knHY71EOETe9Yow5RD2hTIpB5ecNxI0LUKDq+Ii8HfBvndPBIr0BWYDugckQ3Bocf+yn/tn2/GZieFEyFpBGF/MnLbAAfUKIdeyFRX7ufaiWWz5yKAfEhtziqdAGZaXNaLG6gkpy3EixOAy6ZXuTAk3b3Y0FUmDjhOHllbPmTOcKMry9
[rita.osmocom.org]:48 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPdWn1kEousXuKsZ+qJEZTt/NSeASxCrUfNDW3LWtH+d8Ust7ZuKp/vuyG+5pe5pwpPOgFu7TjN+0lVjYJVXH54=
[rita.osmocom.org]:48 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK8iivY70EiR5NiGChV39gRLjNpC8lvu1ZdHtdMw2zuX
[ftp.osmocom.org]:48 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDgQ9HntlpWNmh953a2Gc8NysKE4orOatVT1wQkyzhARnfYUerRuwyNr1GqMyBKdSI9amYVBXJIOUFcpV81niA7zQRUs66bpIMkE9/rHxBd81SkorEPOIS84W4vm3SZtuNqa+fADcqe88Hcb0ZdTzjKILuwi19gzrQyME2knHY71EOETe9Yow5RD2hTIpB5ecNxI0LUKDq+Ii8HfBvndPBIr0BWYDugckQ3Bocf+yn/tn2/GZieFEyFpBGF/MnLbAAfUKIdeyFRX7ufaiWWz5yKAfEhtziqdAGZaXNaLG6gkpy3EixOAy6ZXuTAk3b3Y0FUmDjhOHllbPmTOcKMry9
[ftp.osmocom.org]:48 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPdWn1kEousXuKsZ+qJEZTt/NSeASxCrUfNDW3LWtH+d8Ust7ZuKp/vuyG+5pe5pwpPOgFu7TjN+0lVjYJVXH54=
[ftp.osmocom.org]:48 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK8iivY70EiR5NiGChV39gRLjNpC8lvu1ZdHtdMw2zuX
EOF
SSH_COMMAND="ssh -o 'UserKnownHostsFile=/build/known_hosts' -p 48"
rsync --archive --verbose --compress --delete --rsh "$SSH_COMMAND" $TOPDIR/firmware/bin/*-latest.{bin,elf} binaries@rita.osmocom.org:web-files/simtrace2/firmware/latest/
rsync --archive --verbose --compress --rsh "$SSH_COMMAND" --exclude $TOPDIR/firmware/bin/*-latest.{bin,elf} $TOPDIR/firmware/bin/*-*-*-*.{bin,elf} binaries@rita.osmocom.org:web-files/simtrace2/firmware/all/
rsync --archive --verbose --compress --delete --rsh "$SSH_COMMAND" $TOPDIR/firmware/bin/*-latest.{bin,elf} binaries@ftp.osmocom.org:web-files/simtrace2/firmware/latest/
rsync --archive --verbose --compress --rsh "$SSH_COMMAND" --exclude $TOPDIR/firmware/bin/*-latest.{bin,elf} $TOPDIR/firmware/bin/*-*-*-*.{bin,elf} binaries@ftp.osmocom.org:web-files/simtrace2/firmware/all/
fi
echo

16
contrib/prepare_upload.sh Executable file
View File

@@ -0,0 +1,16 @@
#!/bin/sh -e
# Create copies of binaries with -latest, -$GIT_VERSION (OS#4413, OS#3452)
cd "$(dirname "$0")/.."
GIT_VERSION="$(./git-version-gen .tarball-version)"
echo "Copying binaries with "-latest" and "-$GIT_VERSION" appended..."
cd firmware/bin
for ext in bin elf; do
for file in *."$ext"; do
without_ext="${file%.*}"
cp -v "$file" "$without_ext-latest.$ext"
cp -v "$file" "$without_ext-$GIT_VERSION.$ext"
done
done

1
debian/source/format vendored Normal file
View File

@@ -0,0 +1 @@
3.0 (native)

View File

@@ -28,7 +28,7 @@
# Makefile for compiling the Getting Started with SAM3S Microcontrollers project
GIT_VERSION=$(shell $(TOP)/git-version-gen $(TOP)/.tarvers)
GIT_VERSION=$(shell $(TOP)/git-version-gen $(TOP)/.tarball-version)
#-------------------------------------------------------------------------------
# User-modifiable options
#-------------------------------------------------------------------------------
@@ -108,7 +108,7 @@ C_LIBUSB = USBDescriptors.c USBRequests.c USBD.c USBDCallbacks.c USBDDriver.
C_LIBUSB_RT = dfu.c dfu_runtime.c
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 \
main_common.c tc_etu.c
main_common.c stack_check.c
C_BOARD = $(notdir $(wildcard libboard/common/source/*.c))
C_BOARD += $(notdir $(wildcard libboard/$(BOARD)/source/*.c))
@@ -178,6 +178,14 @@ CFLAGS += -ffunction-sections -g $(OPTIMIZATION) $(INCLUDES) -D$(CHIP) -DTRACE_L
CFLAGS += -DGIT_VERSION=\"$(GIT_VERSION)\"
CFLAGS += -DBOARD=\"$(BOARD)\" -DBOARD_$(BOARD)
CFLAGS += -DAPPLICATION=\"$(APP)\" -DAPPLICATION_$(APP)
# Disable stack protector by default (OS#5081)
ifeq ($(STACK_PROTECTOR), 1)
CFLAGS += -fstack-protector
else
CFLAGS += -fno-stack-protector
endif
ASFLAGS = -mcpu=cortex-m3 -mthumb -Wall -g $(OPTIMIZATION) $(INCLUDES) -D$(CHIP) -D__ASSEMBLY__
LDFLAGS = -mcpu=cortex-m3 -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--entry=ResetException -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--print-memory-usage -Wl,--no-undefined $(LIB)
#LD_OPTIONAL=-Wl,--print-gc-sections -Wl,--stats
@@ -219,12 +227,8 @@ ASM_OBJECTS_$(1) = $(addprefix $(OBJ)/$(1)_, $(ASM_OBJECTS))
$(1): $$(ASM_OBJECTS_$(1)) $$(C_OBJECTS_$(1))
$(SILENT)$(CC) $(LDFLAGS) $(LD_OPTIONAL) -T"libboard/common/resources/$(CHIP)/$$@.ld" -Wl,-Map,$(OUTPUT)-$$@.map -o $(OUTPUT)-$$@.elf $$^ $(LIBS)
cp $(OUTPUT)-$$@.elf $(OUTPUT)-$$@-$(GIT_VERSION).elf
cp $(OUTPUT)-$$@.elf $(OUTPUT)-$$@-latest.elf
$(SILENT)$(NM) $(OUTPUT)-$$@.elf >$(OUTPUT)-$$@.elf.txt
$(SILENT)$(OBJCOPY) -O binary $(OUTPUT)-$$@.elf $(OUTPUT)-$$@.bin
cp $(OUTPUT)-$$@.bin $(OUTPUT)-$$@-$(GIT_VERSION).bin
cp $(OUTPUT)-$$@.bin $(OUTPUT)-$$@-latest.bin
$(SILENT)$(SIZE) $$^ $(OUTPUT)-$$@.elf
$$(C_OBJECTS_$(1)): $(OBJ)/$(1)_%.o: %.c Makefile $(OBJ) $(BIN)

View File

@@ -1,3 +1,3 @@
C_FILES += $(C_LIBUSB_RT)
C_FILES += card_emu.c iso7816_fidi.c iso7816_3.c iso7816_4.c mode_cardemu.c simtrace_iso7816.c usb.c
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 usb.c

View File

@@ -165,7 +165,7 @@ extern int main(void)
while (USBD_GetState() < USBD_STATE_CONFIGURED) {
WDT_Restart(WDT);
check_exec_dbg_cmd();
#if 1
#if 0
if (i >= MAX_USB_ITER * 3) {
TRACE_ERROR("Resetting board (USB could "
"not be configured)\n\r");
@@ -221,6 +221,7 @@ extern int main(void)
}
last_simtrace_config = simtrace_config;
} else {
//FIXME: usb_proces() for every interface in this configuration?
if (config_func_ptrs[simtrace_config].run) {
config_func_ptrs[simtrace_config].run();
}

View File

@@ -243,6 +243,17 @@ static void check_exec_dbg_cmd(void)
//board_exec_dbg_cmd(ch);
}
/* print a horizontal line of '=' characters; Doing this in a loop vs. using a 'const'
* string saves us ~60 bytes of executable size (matters particularly for DFU loader) */
static void print_line(void)
{
int i;
for (i = 0; i < 78; i++)
fputc('=', stdout);
fputc('\n', stdout);
fputc('\r', stdout);
}
/*------------------------------------------------------------------------------
* Main
*------------------------------------------------------------------------------*/
@@ -265,16 +276,14 @@ extern int main(void)
PIO_Clear(&pinsLeds[LED_NUM_GREEN]);
#endif
PIO_InitializeInterrupts(0);
EEFC_ReadUniqueID(g_unique_id);
printf("\n\r\n\r"
"=============================================================================\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",
printf("\n\r\n\r");
print_line();
printf("DFU bootloader %s for board %s\n\r"
"(C) 2010-2017 by Harald Welte, 2018-2019 by Kevin Redon\n\r",
manifest_revision, manifest_board);
print_line();
#if (TRACE_LEVEL >= TRACE_LEVEL_INFO)
TRACE_INFO("Chip ID: 0x%08lx (Ext 0x%08lx)\n\r", CHIPID->CHIPID_CIDR, CHIPID->CHIPID_EXID);

View File

@@ -1,3 +1,3 @@
C_FILES += $(C_LIBUSB_RT)
C_FILES += iso7816_4.c iso7816_fidi.c simtrace_iso7816.c sniffer.c usb.c
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 usb.c

View File

@@ -1,3 +1,3 @@
C_FILES += $(C_LIBUSB_RT)
C_FILES += card_emu.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_4.c iso7816_fidi.c mitm.c mode_cardemu.c mode_ccid.c simtrace_iso7816.c sniffer.c usb.c

View File

@@ -1672,6 +1672,10 @@ uint8_t USBD_HAL_Halt(uint8_t bEndpoint, uint8_t ctl)
UDP->UDP_RST_EP |= 1 << bEndpoint;
UDP->UDP_RST_EP &= ~(1 << bEndpoint);
}
/* This fixes a weird bug with regard to ping-pong OUT endpoints */
UDP->UDP_RST_EP |= 1 << bEndpoint;
UDP->UDP_RST_EP &= ~(1 << bEndpoint);
}
/* Return Halt status */

View File

@@ -39,8 +39,8 @@ struct dfu_desc {
#define DFU_FUNC_DESC { \
.bLength = USB_DT_DFU_SIZE, \
.bDescriptorType = USB_DT_DFU, \
.bmAttributes = USB_DFU_CAN_UPLOAD | USB_DFU_CAN_DOWNLOAD, \
.wDetachTimeOut = 0xff00, \
.bmAttributes = USB_DFU_CAN_UPLOAD | USB_DFU_CAN_DOWNLOAD | USB_DFU_WILL_DETACH, \
.wDetachTimeOut = 0x00, \
.wTransferSize = BOARD_DFU_PAGE_SIZE, \
.bcdDFUVersion = 0x0100, \
}

View File

@@ -165,6 +165,8 @@ void USBDFU_Runtime_RequestHandler(const USBGenericRequest *request)
* will then trigger DFURT_SwitchToDFU() below */
TRACE_DEBUG("\r\n====dfu_detach\n\r");
g_dfu->state = DFU_STATE_appDETACH;
USBD_Write(0, 0, 0, 0, 0);
DFURT_SwitchToDFU();
ret = DFU_RET_ZLP;
goto out;
break;
@@ -209,13 +211,14 @@ out:
void DFURT_SwitchToDFU(void)
{
__disable_irq();
/* store the magic value that the DFU loader can detect and
* activate itself, rather than boot into the application */
g_dfu->magic = USB_DFU_MAGIC;
__DMB();
/* Disconnect the USB by removing the pull-up */
USBD_Disconnect();
__disable_irq();
/* reset the processor, we will start execution with the
* ResetVector of the bootloader */

View File

@@ -50,81 +50,28 @@
/* Button to force bootloader start (shorted to ground when pressed */
#define PIN_BOOTLOADER_SW {PIO_PA5, PIOA, ID_PIOA, PIO_INPUT, PIO_PULLUP}
//FIXME SIM_PWEN_PIN collides with PA5/bootloader_sw on octsimtest
/* Enable powering the card using the second 3.3 V output of the LDO (active high) */
#define SIM_PWEN_PIN {PIO_PA12, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT}
/* Enable powering the SIM card */
#define PWR_PINS SIM_PWEN_PIN
// FIXME PA8 is 32khz xtal on octsimtest
/* Card presence pin */
#define SW_SIM PIO_PA11
/* Pull card presence pin high (shorted to ground in card slot when card is present) */
#define SMARTCARD_CONNECT_PIN {SW_SIM, PIOA, ID_PIOA, PIO_INPUT, PIO_PULLUP | PIO_DEBOUNCE | PIO_DEGLITCH | PIO_IT_EDGE }
/** Smart card connection **/
//FIXME
/* Card RST reset signal input (active low; RST_SIM in schematic) */
#define PIN_SIM_RST {PIO_PA13, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
/* Card I/O data signal input/output (I/O_SIM in schematic) */
#define PIN_SIM_IO {PIO_PA6A_TXD0, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
/* Card CLK clock input (CLK_SIM in schematic) */
#define PIN_SIM_CLK {PIO_PA2B_SCK0, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
/* Pin to measure card I/O timing (to start measuring the ETU on I/O activity; connected I/O_SIM in schematic) */
#define PIN_SIM_IO_INPUT {PIO_PA1B_TIOB0, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
//FIXME PIO_PA4B_TCLK0 PA4 is LED on octsimtest
/* Pin used as clock input (to measure the ETU duration; connected to CLK_SIM in schematic) */
#define PIN_SIM_CLK_INPUT {PIO_PA14, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
/* Pins used to measure ETU timing (using timer counter) */
#define PINS_TC PIN_SIM_IO_INPUT, PIN_SIM_CLK_INPUT
/** Phone connection **/
/* Phone USIM slot 1 VCC pin (VCC_PHONE in schematic) */
#define PIN_USIM1_VCC {PIO_PA25, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT}
/* 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) */
#define PIN_PHONE_IO {PIO_PA22A_TXD1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
/* Phone CLK clock input (CLK_PHONE in schematic) */
#define PIN_PHONE_CLK {PIO_PA23A_SCK1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
/* Pin used to switch level shifter in I/O line between rx (0) and tx (1) */
#define PIN_USIM1_IO_DIR {PIO_PA26, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
/* 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_PHONE_IO, PIN_PHONE_CLK, PIN_PHONE_CLK_INPUT, PIN_USIM1_VCC, PIN_PHONE_IO_INPUT, PIN_USIM1_nRST, PIN_USIM1_IO_DIR
/* 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}
/* Pin used as clock input (to measure the ETU duration; connected to CLK_PHONE in schematic) */
#define PIN_PHONE_CLK_INPUT {PIO_PA29B_TCLK2, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
/** Default pin configuration **/
/* Disconnect VPP, CLK, and RST lines between card and phone using bus switch (high sets bus switch to high-impedance) */
#define PIN_SC_SW_DEFAULT {PIO_PA20, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT}
/* Disconnect I/O line between card and phone using bus switch (high sets bus switch to high-impedance) */
#define PIN_IO_SW_DEFAULT {PIO_PA19, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT}
/* Disconnect all lines (VPP, CLK, RST, and I/O) between card and phone */
#define PINS_BUS_DEFAULT PIN_SC_SW_DEFAULT, PIN_IO_SW_DEFAULT
/** Sniffer configuration **/
/* Connect VPP, CLK, and RST lines between card and phone using bus switch (low connects signals on bus switch) */
#define PIN_SC_SW_SNIFF {PIO_PA20, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
/* Connect I/O line between card and phone using bus switch (low connects signals on bus switch) */
#define PIN_IO_SW_SNIFF {PIO_PA19, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
/* Connect all lines (VPP, CLK, RST, and I/O) between card and phone */
#define PINS_BUS_SNIFF PIN_SC_SW_SNIFF, PIN_IO_SW_SNIFF
/* Card RST reset signal input (use as input since the phone will drive it) */
#define PIN_SIM_RST_SNIFF {PIO_PA7, PIOA, ID_PIOA, PIO_INPUT, PIO_DEGLITCH | PIO_IT_EDGE}
/* Pins used to sniff phone-card communication */
#define PINS_SIM_SNIFF PIN_SIM_IO, PIN_SIM_CLK, PIN_SIM_RST_SNIFF
/* Disable power converter 4.5-6V to 3.3V (active high) */
#define PIN_SIM_PWEN_SNIFF {SIM_PWEN, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
/* Enable power switch to forward VCC_PHONE to VCC_SIM (active high) */
#define PIN_VCC_FWD_SNIFF {VCC_FWD, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT}
/* Use phone VCC to power card */
#define PINS_PWR_SNIFF PIN_SIM_PWEN_SNIFF, PIN_VCC_FWD_SNIFF
/** CCID configuration */
/* Card RST reset signal input (active low; RST_SIM in schematic) */
#define PIN_ISO7816_RSTMC {PIO_PA7, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
/* 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
/** External SPI flash interface **/
/* SPI MISO pin definition */
@@ -149,21 +96,32 @@
/* OpenMoko SIMtrace 2 USB vendor ID */
#define BOARD_USB_VENDOR_ID USB_VENDOR_OPENMOKO
/* OpenMoko SIMtrace 2 USB product ID (main application/runtime mode) */
#define BOARD_USB_PRODUCT_ID USB_PRODUCT_SIMTRACE2
#define BOARD_USB_PRODUCT_ID USB_PRODUCT_OCTSIMTEST
/* OpenMoko SIMtrace 2 DFU USB product ID (DFU bootloader/DFU mode) */
#define BOARD_DFU_USB_PRODUCT_ID USB_PRODUCT_SIMTRACE2_DFU
#define BOARD_DFU_USB_PRODUCT_ID USB_PRODUCT_OCTSIMTEST
/* USB release number (bcdDevice, shown as 0.00) */
#define BOARD_USB_RELEASE 0x000
/* Indicate SIMtrace is bus power in USB attributes */
#define BOARD_USB_BMATTRIBUTES USBConfigurationDescriptor_BUSPOWERED_NORWAKEUP
#define DETECT_VCC_BY_ADC
/* we have a resistive voltage divider of 47 + 30 kOhms to also detect 5V supply power */
#define VCC_UV_THRESH_1V8 (1500000*47)/(47+30)
#define VCC_UV_THRESH_3V (2500000*47)/(47+30)
#define HAVE_SLOT_MUX
#define HAVE_BOARD_CARDINSERT
struct cardem_inst;
void board_set_card_insert(struct cardem_inst *ci, bool card_insert);
/** Supported modes */
/* SIMtrace board supports sniffer mode */
//#define HAVE_SNIFFER
/* SIMtrace board supports CCID mode */
//#define HAVE_CCID
/* SIMtrace board supports card emulation mode */
//#define HAVE_CARDEM
#define HAVE_CARDEM
/* SIMtrace board supports man-in-the-middle mode */
//#define HAVE_MITM
/* octsimtest board supports gpio_test mode */

View File

@@ -18,8 +18,10 @@
#define MCP23017_ADDRESS 0x20
int mcp23017_init(uint8_t slave);
int mcp23017_init(uint8_t slave, uint8_t iodira, uint8_t iodirb);
int mcp23017_test(uint8_t slave);
int mcp23017_toggle(uint8_t slave);
int mcp23017_set_output_a(uint8_t slave, uint8_t val);
int mcp23017_set_output_b(uint8_t slave, uint8_t val);
//int mcp23017_write_byte(uint8_t slave, uint8_t addr, uint8_t byte);
//int mcp23017_read_byte(uint8_t slave, uint8_t addr);

View File

@@ -0,0 +1,17 @@
#pragma once
void mux_init(void);
int mux_set_slot(uint8_t s);
int mux_get_slot(void);
void mux_set_freq(uint8_t s);
/* this reflects the wiring between U5 and U4 */
#define MUX_FREQ_DIV_2 0
#define MUX_FREQ_DIV_4 1
#define MUX_FREQ_DIV_16 2
#define MUX_FREQ_DIV_32 3
#define MUX_FREQ_DIV_32 3
#define MUX_FREQ_DIV_128 4
#define MUX_FREQ_DIV_512 5
#define MUX_FREQ_DIV_2048 6
#define MUX_FREQ_DIV_4096 7

View File

@@ -17,6 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdbool.h>
#include "board.h"
#include "simtrace.h"
#include "utils.h"
@@ -25,16 +26,29 @@
#include "usb_buf.h"
#include "i2c.h"
#include "mcp23017.h"
#include "mux.h"
static bool mcp2317_present = false;
void board_exec_dbg_cmd(int ch)
{
switch (ch) {
case '?':
printf("\t?\thelp\n\r");
printf("\t0-8\tselect physical SIM slot\n\r");
printf("\tR\treset SAM3\n\r");
printf("\tm\trun mcp23017 test\n\r");
printf("\tR\ttoggle MSB of gpio on mcp23017\n\r");
printf("\ti\tset card insert via I2C\n\r");
printf("\tI\tdisable card insert\n\r");
break;
case '0': mux_set_slot(0); break;
case '1': mux_set_slot(1); break;
case '2': mux_set_slot(2); break;
case '3': mux_set_slot(3); break;
case '4': mux_set_slot(4); break;
case '5': mux_set_slot(5); break;
case '6': mux_set_slot(6); break;
case '7': mux_set_slot(7); break;
case 'R':
printf("Asking NVIC to reset us\n\r");
USBD_Disconnect();
@@ -43,8 +57,13 @@ void board_exec_dbg_cmd(int ch)
case 'm':
mcp23017_test(MCP23017_ADDRESS);
break;
case 't':
mcp23017_toggle(MCP23017_ADDRESS);
case 'i':
printf("Setting card insert (slot=%u)\r\n", mux_get_slot());
mcp23017_set_output_a(MCP23017_ADDRESS, (1 << mux_get_slot()));
break;
case 'I':
printf("Releasing card insert (slot=%u)\r\n", mux_get_slot());
mcp23017_set_output_a(MCP23017_ADDRESS, 0);
break;
default:
printf("Unknown command '%c'\n\r", ch);
@@ -57,9 +76,13 @@ void board_main_top(void)
#ifndef APPLICATION_dfu
usb_buf_init();
mux_init();
i2c_pin_init();
if (!mcp23017_init(MCP23017_ADDRESS))
printf("mcp23017 not found!\n\r");
/* PORT A: all outputs, Port B0 output, B1..B7 unused */
if (mcp23017_init(MCP23017_ADDRESS, 0x00, 0xfe) == 0) {
mcp2317_present = true;
mcp23017_set_output_a(MCP23017_ADDRESS, 0);
}
/* Initialize checking for card insert/remove events */
//card_present_init();
#endif
@@ -79,3 +102,23 @@ int board_override_enter_dfu(void)
} else
return 0;
}
void board_set_card_insert(struct cardem_inst *ci, bool card_insert)
{
int s = mux_get_slot();
/* A0 .. A7 of the MCP are each connected to the gate of a FET which closes
* the sim-present signal of the respective slot */
if (mcp2317_present) {
if (card_insert) {
/* we must enable card-presence of the active slot and disable it on all others */
mcp23017_set_output_a(MCP23017_ADDRESS, (1 << s));
} else {
/* we disable all card insert signals */
mcp23017_set_output_a(MCP23017_ADDRESS, 0);
}
} else {
TRACE_WARNING("No MCP23017 present; cannot set CARD_INSERT\r\n");
}
}

View File

@@ -92,19 +92,25 @@ out_stop:
return 0;
}
int mcp23017_init(uint8_t slave)
int mcp23017_init(uint8_t slave, uint8_t iodira, uint8_t iodirb)
{
printf("mcp23017_init\n\r");
TRACE_DEBUG("mcp23017_init\n\r");
// all gpio input
if (mcp23017_write_byte(slave, MCP23017_IODIRA, 0xff))
return false;
if (mcp23017_write_byte(slave, MCP23017_IODIRA, iodira))
goto out_err;
// msb of portb output, rest input
if (mcp23017_write_byte(slave, MCP23017_IODIRB, 0x7f))
return false;
if (mcp23017_write_byte(slave, MCP23017_IODIRB, iodirb))
goto out_err;
if (mcp23017_write_byte(slave, MCP23017_IOCONA, 0x20)) //disable SEQOP (autoinc addressing)
return false;
printf("mcp23017 found\n\r");
return true;
goto out_err;
TRACE_DEBUG("mcp23017 found\n\r");
return 0;
out_err:
TRACE_WARNING("mcp23017 NOT found!\n\r");
return -1;
}
int mcp23017_test(uint8_t slave)
@@ -120,6 +126,16 @@ int mcp23017_test(uint8_t slave)
return 0;
}
int mcp23017_set_output_a(uint8_t slave, uint8_t val)
{
return mcp23017_write_byte(slave, MCP23017_OLATA, val);
}
int mcp23017_set_output_b(uint8_t slave, uint8_t val)
{
return mcp23017_write_byte(slave, MCP23017_OLATB, val);
}
int mcp23017_toggle(uint8_t slave)
{
// example writing MSB of gpio

View File

@@ -0,0 +1,113 @@
/* sysmoOCTSIMTEST support for multiplexers
*
* (C) 2021 by Harald Welte <laforge@gnumonks.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#include "board.h"
#include "mux.h"
#include <stdbool.h>
#include <errno.h>
/* 3-bit S0..S2 signal for slot selection */
static const Pin pin_in_sel[3] = {
{ PIO_PA1, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT },
{ PIO_PA2, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT },
{ PIO_PA3, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT },
};
/* 3-bit S0..S2 signal for frequency divider selection */
static const Pin pin_freq_sel[3] = {
{ PIO_PA16, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT },
{ PIO_PA17, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT },
{ PIO_PA18, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT },
};
/* low-active output enable for all muxes */
static const Pin pin_oe = { PIO_PA19, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT };
static uint8_t g_mux_slot = 0;
/* initialize the external 1:8 multiplexers */
void mux_init(void)
{
PIO_Configure(&pin_oe, PIO_LISTSIZE(pin_oe));
PIO_Configure(pin_in_sel, PIO_LISTSIZE(pin_in_sel));
PIO_Configure(pin_freq_sel, PIO_LISTSIZE(pin_freq_sel));
mux_set_slot(0);
}
/* set the slot selection mux */
int mux_set_slot(uint8_t s)
{
TRACE_INFO("%s(%u)\r\n", __func__, s);
if (s > 7)
return -EINVAL;
/* !OE = H: disconnect input and output of muxes */
PIO_Set(&pin_oe);
if (s & 1)
PIO_Set(&pin_in_sel[0]);
else
PIO_Clear(&pin_in_sel[0]);
if (s & 2)
PIO_Set(&pin_in_sel[1]);
else
PIO_Clear(&pin_in_sel[1]);
if (s & 4)
PIO_Set(&pin_in_sel[2]);
else
PIO_Clear(&pin_in_sel[2]);
/* !OE = L: (re-)enable the output of muxes */
PIO_Clear(&pin_oe);
g_mux_slot = s;
return s;
}
int mux_get_slot(void)
{
return g_mux_slot;
}
/* set the frequency divider mux */
void mux_set_freq(uint8_t s)
{
TRACE_INFO("%s(%u)\r\n", __func__, s);
/* no need for 'break before make' here, this would also affect
* the SIM card I/O signals which we don't want to disturb */
if (s & 1)
PIO_Set(&pin_freq_sel[0]);
else
PIO_Clear(&pin_freq_sel[0]);
if (s & 2)
PIO_Set(&pin_freq_sel[1]);
else
PIO_Clear(&pin_freq_sel[1]);
if (s & 4)
PIO_Set(&pin_freq_sel[2]);
else
PIO_Clear(&pin_freq_sel[2]);
/* !OE = L: ensure enable the output of muxes */
PIO_Clear(&pin_oe);
}

View File

@@ -0,0 +1,37 @@
/* Code to switch between local (physical) and remote (emulated) SIM
*
* (C) 2021 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 "sim_switch.h"
int sim_switch_use_physical(unsigned int nr, int physical)
{
if (physical) {
TRACE_ERROR("%u: Use local/physical SIM - UNSUPPORTED!\r\n", nr);
} else {
TRACE_INFO("%u: Use remote/emulated SIM\r\n", nr);
}
return 0;
}
int sim_switch_init(void)
{
return 1; // SIMtrace hardware has only one switchable interface
}

View File

@@ -91,8 +91,8 @@
#define PINS_WWAN_IN { PIN_WWAN1, PIN_WWAN2 }
/* outputs controlling RESET input of modems */
#define PIN_PERST1 {PIO_PA25, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_PULLUP}
#define PIN_PERST2 {PIO_PA26, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_PULLUP}
#define PIN_PERST1 {PIO_PA25, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_PULLUP}
#define PIN_PERST2 {PIO_PA26, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_PULLUP}
#define PINS_PERST { PIN_PERST1, PIN_PERST2 }
#define PIN_VERSION_DET {PIO_PA19, PIOA, ID_PIOA, PIO_PERIPH_D, PIO_DEFAULT}
@@ -109,9 +109,9 @@
#define BOARD_USB_RELEASE 0x010
#define CARDEMU_SECOND_UART
#define DETECT_VCC_BY_ADC
/** sysmoQMOD only supports card emulation */
#ifdef APPLICATION_cardem
#define DETECT_VCC_BY_ADC
#define VCC_UV_THRESH_1V8 1500000
#define VCC_UV_THRESH_3V 2500000
#define HAVE_CARDEM
#endif

View File

@@ -80,9 +80,9 @@
/* Phone I/O data signal input/output (I/O_PHONE in schematic) */
#define PIN_USIM1_IO {PIO_PA22A_TXD1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
/* 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_USIM1_CLK {PIO_PA23A_SCK1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
/* Pin used for phone USIM slot 1 communication */
#define PINS_USIM1 PIN_USIM1_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_USIM1_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) */
#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) */
@@ -120,14 +120,6 @@
/* 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
/** card emulation configuration */
/* Disable power converter 4.5-6V to 3.3V (active high) */
#define PIN_SIM_PWEN_CARDEMU {PIO_PA5, 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 {PIO_PA26, 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 **/
/* SPI MISO pin definition */
#define PIN_SPI_MISO {PIO_PA12A_MISO, PIOA, PIOA, PIO_PERIPH_A, PIO_PULLUP}
@@ -165,14 +157,10 @@
#define HAVE_SNIFFER
#endif
/* SIMtrace board supports CCID mode */
#ifdef APPLICATION_ccid
//#define HAVE_CCID
#endif
/* SIMtrace board supports card emulation mode */
#ifdef APPLICATION_cardem
#define HAVE_CARDEM
#endif
/* SIMtrace board supports man-in-the-middle mode */
#ifdef APPLICATION_mitm
//#define HAVE_MITM
#endif

View File

@@ -22,15 +22,6 @@
#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

View File

@@ -89,7 +89,7 @@
/// \param condition Condition to verify.
#define ASSERT(condition) { \
if (!(condition)) { \
printf("-F- ASSERT: %s %s:%d\n\r", #condition, __BASE_FILE__, __LINE__); \
printf_sync("-F- ASSERT: %s %s:%d\n\r", #condition, __BASE_FILE__, __LINE__); \
while (1); \
} \
}

View File

@@ -31,7 +31,6 @@ enum card_io {
/** initialise card slot
* @param[in] slot_num slot number (arbitrary number)
* @param[in] tc_chan timer counter channel (to measure the ETU)
* @param[in] uart_chan UART peripheral channel
* @param[in] in_ep USB IN end point number
* @param[in] irq_ep USB INTerrupt end point number
@@ -40,7 +39,7 @@ enum card_io {
* @param[in] clocked initial CLK signat state (true = active)
* @return main card handle reference
*/
struct card_handle *card_emu_init(uint8_t slot_num, uint8_t tc_chan, uint8_t uart_chan, uint8_t in_ep, uint8_t irq_ep, bool vcc_active, bool in_reset, bool clocked);
struct card_handle *card_emu_init(uint8_t slot_num, uint8_t uart_chan, uint8_t in_ep, uint8_t irq_ep, bool vcc_active, bool in_reset, bool clocked);
/* process a single byte received from the reader */
void card_emu_process_rx_byte(struct card_handle *ch, uint8_t byte);
@@ -58,43 +57,17 @@ 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_report_status(struct card_handle *ch, bool report_on_irq);
/*! call when the waiting time has half-expired
* param[in] ch card for which the waiting time half expired
*/
void card_emu_wt_halfed(void *ch);
/*! call when the waiting time has expired
* param[in] ch card for which the waiting time expired
*/
void card_emu_wt_expired(void *ch);
void card_emu_wtime_half_expired(void *ch);
void card_emu_wtime_expired(void *ch);
#define ENABLE_TX 0x01
#define ENABLE_RX 0x02
// the following functions are callbacks implement in mode_cardemu.c
#define ENABLE_TX 0x01
#define ENABLE_RX 0x02
#define ENABLE_TX_TIMER_ONLY 0x03
int card_emu_uart_update_fidi(uint8_t uart_chan, unsigned int fidi);
/*! 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);
void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx);
void card_emu_uart_wait_tx_idle(uint8_t uart_chan);

View File

@@ -1,98 +0,0 @@
/*
* 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

@@ -21,10 +21,10 @@
#include <stdint.h>
/* Table 7 of ISO 7816-3:2006 */
extern const uint16_t fi_table[];
extern const uint16_t iso7816_3_fi_table[16];
/* Table 8 from ISO 7816-3:2006 */
extern const uint8_t di_table[];
extern const uint8_t iso7816_3_di_table[16];
/* compute the F/D ratio based on Fi and Di values */
int compute_fidi_ratio(uint8_t fi, uint8_t di);
/* compute the F/D ratio based on F_index and D_index values */
int iso7816_3_compute_fd_ratio(uint8_t f_index, uint8_t d_index);

View File

@@ -230,10 +230,17 @@ struct cardemu_usb_msg_status {
uint32_t flags;
/* phone-applied target voltage in mV */
uint16_t voltage_mv;
uint8_t f; /*!< index of F and f_max values as encoded in ISO/IEC 7816-3:2006(E) Table 7 */
uint8_t d; /*!< index of D value as encoded in ISO/IEC 7816-3:2006(E) Table 8 */
uint8_t wi; /*!< Waiting Integer as defined in ISO/IEC 7816-3:2006(E) Section 10.2 */
uint32_t wt; /*!< Waiting Time in ETU as defined in ISO/IEC 7816-3:2006(E) Section 8.1 */
/* F/D related information. Not actual Fn/Dn values but indexes into tables! */
union {
uint8_t F_index; /* <! Index to ISO7816-3 Table 7 (F and f_max values) */
uint8_t fi; /* <! old, wrong name for API compatibility */
};
union {
uint8_t D_index; /* <! Index to ISO7816-3 Table 8 (D value) */
uint8_t di; /* <! old, wrong name for API compatibility */
};
uint8_t wi; /* <! Waiting Integer as defined in ISO7816-3 Section 10.2 */
uint32_t waiting_time; /* <! Waiting Time in etu as defined in ISO7816-3 Section 8.1 */
} __attribute__ ((packed));
/* CEMU_USB_MSGT_DO_PTS */
@@ -262,6 +269,8 @@ struct cardemu_usb_msg_error {
struct cardemu_usb_msg_config {
/* bit-mask of CEMU_FEAT_F flags */
uint32_t features;
/* the selected slot number (if an external mux is present) */
uint8_t slot_mux_nr;
} __attribute__ ((packed));
/***********************************************************************

View File

@@ -25,6 +25,7 @@
#define USB_PRODUCT_QMOD_SAM3 0x4004
#define USB_PRODUCT_SIMTRACE2_DFU 0x60e3 /* was 0x60e2 */
#define USB_PRODUCT_SIMTRACE2 0x60e3
#define USB_PRODUCT_OCTSIMTEST 0x616d
/* USB proprietary class */
#define USB_CLASS_PROPRIETARY 0xff

View File

@@ -7,3 +7,5 @@ void tc_etu_init(uint8_t chan_nr, void *handle);
void tc_etu_enable(uint8_t chan_nr);
void tc_etu_disable(uint8_t chan_nr);
extern void tc_etu_wtime_half_expired(void *handle);
extern void tc_etu_wtime_expired(void *handle);

View File

@@ -42,5 +42,15 @@ int usb_drain_queue(uint8_t ep);
void usb_buf_init(void);
struct usb_buffered_ep *usb_get_buf_ep(uint8_t ep);
int usb_refill_to_host(uint8_t ep);
int usb_refill_from_host(uint8_t ep);
struct usb_if {
uint8_t if_num; /* interface number */
uint8_t ep_out; /* OUT endpoint (0 if none) */
uint8_t ep_in; /* IN endpint (0 if none) */
uint8_t ep_int; /* INT endpoint (0 if none) */
void *data; /* opaque data, passed through */
struct {
/* call-back to be called for inclming messages on OUT EP */
void (*rx_out)(struct msgb *msg, const struct usb_if *usb_if);
} ops;
};
void usb_process(const struct usb_if *usb_if);

View File

@@ -1,7 +1,7 @@
/* ISO7816-3 state machine for the card side
*
* (C) 2010-2019 by Harald Welte <laforge@gnumonks.org>
* (C) 2018-2019 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
* (C) 2010-2021 by Harald Welte <laforge@gnumonks.org>
* (C) 2018 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
* it under the terms of the GNU General Public License as published by
@@ -26,15 +26,16 @@
#include "utils.h"
#include "trace.h"
#include "iso7816_3.h"
#include "iso7816_fidi.h"
#include "tc_etu.h"
#include "card_emu.h"
#include "simtrace_prot.h"
#include "usb_buf.h"
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/msgb.h>
#ifdef HAVE_SLOT_MUX
#include "mux.h"
#endif
#define NUM_SLOTS 2
@@ -155,54 +156,34 @@ struct card_handle {
bool in_reset; /*< if card is in reset (true = RST low/asserted, false = RST high/ released) */
bool clocked; /*< if clock is active ( true = active, false = inactive) */
uint8_t tc_chan; /* TC channel number */
/* All below variables with _index suffix are indexes from 0..15 into Tables 7 + 8
* of ISO7816-3. */
/*! Index to clock rate conversion integer Fi (ISO7816-3 Table 7).
* \note this represents the maximum value supported by the card, and can be indicated in TA1 */
uint8_t Fi_index;
/*! Current value of index to clock rate conversion integer F (ISO 7816-3 Section 7.1). */
uint8_t F_index;
/*! Index to baud rate adjustment factor Di (ISO7816-3 Table 8).
* \note this represents the maximum value supported by the card, and can be indicated in TA1 */
uint8_t Di_index;
/*! Current value of index to baud rate adjustment factor D (ISO 7816-3 Section 7.1). */
uint8_t D_index;
/*! Waiting Integer (ISO7816-3 Section 10.2).
* \note this value can be set in TA2 */
uint8_t wi;
/*! Waiting Time, in ETU (ISO7816-3 Section 8.1).
* \note this depends on Fi, Di, and WI if T=0 is used */
uint32_t waiting_time; /* in etu */
uint8_t uart_chan; /* UART channel */
uint8_t in_ep; /* USB IN EP */
uint8_t irq_ep; /* USB IN EP */
/*! 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 */
struct {
uint8_t idx;
@@ -242,9 +223,7 @@ static void card_handle_reset(struct card_handle *ch)
{
struct msgb *msg;
#ifndef BOARD_simtrace
tc_etu_disable(ch->tc_chan);
#endif
card_emu_uart_update_wt(ch->uart_chan, 0);
/* release any buffers we may still own */
if (ch->uart_tx_msg) {
@@ -399,16 +378,14 @@ static void emu_update_fidi(struct card_handle *ch)
{
int rc;
rc = compute_fidi_ratio(ch->fi, ch->di);
rc = iso7816_3_compute_fd_ratio(ch->F_index, ch->D_index);
if (rc > 0 && rc < 0x400) {
TRACE_INFO("%u: computed Fi(%u) Di(%u) ratio: %d\r\n",
ch->num, ch->fi, ch->di, rc);
TRACE_INFO("%u: computed F(%u)/D(%u) ratio: %d\r\n", ch->num,
ch->F_index, ch->D_index, 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",
TRACE_INFO("%u: computed F/D ratio %d unsupported\r\n",
ch->num, rc);
}
@@ -428,66 +405,35 @@ static void card_set_state(struct card_handle *ch,
case ISO_S_WAIT_POWER:
case ISO_S_WAIT_CLK:
case ISO_S_WAIT_RST:
card_emu_uart_enable(ch->uart_chan, 0); // disable Rx and Tx of UART
#ifdef BOARD_simtrace
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
}
#endif
/* disable Rx and Tx of UART */
card_emu_uart_enable(ch->uart_chan, 0);
/* disable timeout */
card_emu_uart_update_wt(ch->uart_chan, 0);
break;
case ISO_S_WAIT_ATR:
// reset the ETU-related values
ch->f = ISO7816_3_DEFAULT_FD;
ch->d = ISO7816_3_DEFAULT_DD;
#ifdef BOARD_simtrace
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;
/* Reset to initial Fi / Di ratio */
ch->Fi_index = ch->F_index = 1;
ch->Di_index = ch->D_index = 1;
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
ch->waiting_time = ISO7816_3_INIT_WTIME;
emu_update_fidi(ch);
/* enable TX to be able to use the timeout */
card_emu_uart_enable(ch->uart_chan, ENABLE_TX_TIMER_ONLY);
/* the ATR should only be sent 400 to 40k clock cycles after the RESET.
* we use the UART timeout mechanism to wait this time.
* since the initial ETU is Fd=372/Dd=1 clock cycles long, we have to wait 2-107 ETU.
*/
card_emu_uart_update_wt(ch->uart_chan, 2);
#else
/* Reset to initial Fi / Di ratio */
ch->f = 1;
ch->d = 1;
emu_update_fidi(ch);
/* the ATR should only be sent 400 to 40k clock cycles after the RESET.
* 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.
*/
tc_etu_set_wtime(ch->tc_chan, 2);
/* enable the TC/ETU counter once reset has been released */
tc_etu_enable(ch->tc_chan);
#endif
break;
case ISO_S_IN_ATR:
#ifndef BOARD_simtrace
/* initialize to default WI, this will be overwritten if we
* 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->wt = ISO7816_3_INIT_WTIME;
ch->waiting_time = ISO7816_3_INIT_WTIME;
/* set initial waiting time */
tc_etu_set_wtime(ch->tc_chan, ch->wt);
#endif
card_emu_uart_update_wt(ch->uart_chan, ch->waiting_time);
/* Set ATR sub-state to initial state */
ch->atr.idx = 0;
/* enable USART transmission to reader */
@@ -562,15 +508,11 @@ static int tx_byte_atr(struct card_handle *ch)
}
}
}
#ifdef BOARD_simtrace
/* FIXME update waiting time in case of card is specific mode */
/* reset PTS to initial state */
set_pts_state(ch, PTS_S_WAIT_REQ_PTSS);
#else
/* update waiting time (see ISO 7816-3 10.2) */
ch->wt = ch->wi * 960 * ch->fi;
tc_etu_set_wtime(ch->tc_chan, ch->wt);
#endif
/* update waiting time (see ISO 7816-3 10.2). We can drop the Fi
* multiplier as we store the waiting time in units of 'etu', and
* don't really care what the number of clock cycles or the absolute
* wall clock time is */
ch->waiting_time = ch->wi * 960;
/* go to next state */
card_set_state(ch, ISO_S_WAIT_TPDU);
return 0;
@@ -636,12 +578,9 @@ from_pts3:
return PTS_S_WAIT_REQ_PCK | is_resp;
}
/*! process incoming PTS byte
* @param[in] ch card handle on which the byte has been received
* @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)
static int
process_byte_pts(struct card_handle *ch, uint8_t byte)
{
switch (ch->pts.state) {
case PTS_S_WAIT_REQ_PTSS:
@@ -707,17 +646,12 @@ static int tx_byte_pts(struct card_handle *ch)
break;
case PTS_S_WAIT_RESP_PTS1:
byte = ch->pts.resp[_PTS1];
// TODO the value should have been validated when receiving the request
ch->f = iso7816_3_fi_table[byte >> 4]; // save selected Fn
if (0 == ch->f) {
TRACE_ERROR("%u: invalid F index in PPS response: %u\r\n", ch->num, byte >> 4);
// 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
}
/* This must be TA1 */
ch->F_index = byte >> 4;
ch->D_index = byte & 0xf;
TRACE_DEBUG("%u: found F=%u D=%u\r\n", ch->num,
iso7816_3_fi_table[ch->F_index], iso7816_3_di_table[ch->D_index]);
/* FIXME: if F or D are 0, become unresponsive to signal error condition */
break;
case PTS_S_WAIT_RESP_PTS2:
byte = ch->pts.resp[_PTS2];
@@ -742,20 +676,8 @@ static int tx_byte_pts(struct card_handle *ch)
switch (ch->pts.state) {
case PTS_S_WAIT_RESP_PCK:
card_emu_uart_wait_tx_idle(ch->uart_chan);
#ifdef BOARD_simtrace
card_emu_uart_update_fd(ch->uart_chan, ch->f, ch->d); // set selected baud rate
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
#else
/* update baud rate generator with Fi/Di */
/* update baud rate generator with F/D */
emu_update_fidi(ch);
#endif
/* Wait for the next TPDU */
card_set_state(ch, ISO_S_WAIT_TPDU);
set_pts_state(ch, PTS_S_WAIT_REQ_PTSS);
@@ -826,10 +748,6 @@ static void set_tpdu_state(struct card_handle *ch, enum tpdu_state new_ts)
{
if (ch->tpdu.state == new_ts)
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 %s -> %s\r\n", ch->num,
get_value_string(tpdu_state_names, ch->tpdu.state),
@@ -837,20 +755,29 @@ static void set_tpdu_state(struct card_handle *ch, enum tpdu_state new_ts)
ch->tpdu.state = new_ts;
switch (new_ts) {
case TPDU_S_WAIT_CLA: // we will be waiting for the next incoming TDPU
card_emu_uart_enable(ch->uart_chan, ENABLE_RX); // switch back to receiving mode
card_emu_uart_update_wt(ch->uart_chan, 0); // disable waiting time since we don't expect any data
case TPDU_S_WAIT_CLA:
/* switch back to receiving mode */
card_emu_uart_enable(ch->uart_chan, ENABLE_RX);
/* disable waiting time since we don't expect any data */
card_emu_uart_update_wt(ch->uart_chan, 0);
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
case TPDU_S_WAIT_INS:
/* start waiting for the rest of the header/body */
card_emu_uart_update_wt(ch->uart_chan, ch->waiting_time);
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
case TPDU_S_WAIT_RX:
/* switch to receive mode to receive the body */
card_emu_uart_enable(ch->uart_chan, ENABLE_RX);
/* start waiting for the body */
card_emu_uart_update_wt(ch->uart_chan, ch->waiting_time);
break;
case TPDU_S_WAIT_PB:
card_emu_uart_enable(ch->uart_chan, ENABLE_TX); // header is completely received, now we need to transmit the procedure byte
card_emu_uart_update_wt(ch->uart_chan, ch->wt); // prepare to extend the waiting time once half of it is reached
/* we just completed the TPDU header from reader to card
* and now need to disable the receiver, enable the
* transmitter and transmit the procedure byte */
card_emu_uart_enable(ch->uart_chan, ENABLE_TX);
/* prepare to extend the waiting time once half of it is reached */
card_emu_uart_update_wt(ch->uart_chan, ch->waiting_time);
break;
default:
break;
@@ -1134,11 +1061,11 @@ void card_emu_report_status(struct card_handle *ch, bool report_on_irq)
sts->flags |= CEMU_STATUS_F_CLK_ACTIVE;
if (ch->in_reset)
sts->flags |= CEMU_STATUS_F_RESET_ACTIVE;
/* FIXME set voltage and card insert values */
sts->f = ch->f;
sts->d = ch->d;
/* FIXME: voltage + card insert */
sts->F_index = ch->F_index;
sts->D_index = ch->D_index;
sts->wi = ch->wi;
sts->wt = ch->wt;
sts->waiting_time = ch->waiting_time;
usb_buf_upd_len_and_submit(msg);
}
@@ -1155,6 +1082,12 @@ static void card_emu_report_config(struct card_handle *ch)
cfg = (struct cardemu_usb_msg_config *) msgb_put(msg, sizeof(*cfg));
cfg->features = ch->features;
#ifdef HAVE_SLOT_MUX
cfg->slot_mux_nr = mux_get_slot();
#else
cfg->slot_mux_nr = 0;
#endif
usb_buf_upd_len_and_submit(msg);
}
@@ -1193,7 +1126,7 @@ void card_emu_io_statechg(struct card_handle *ch, enum card_io io, int active)
case CARD_IO_RST:
if (active == 0 && ch->in_reset) {
TRACE_INFO("%u: RST released\r\n", ch->num);
if (ch->vcc_active && ch->clocked && ISO_S_WAIT_RST == ch->state) {
if (ch->vcc_active && ch->clocked && ch->state == ISO_S_WAIT_RST) {
/* prepare to send the ATR */
card_set_state(ch, ISO_S_WAIT_ATR);
}
@@ -1202,14 +1135,10 @@ void card_emu_io_statechg(struct card_handle *ch, enum card_io io, int active)
TRACE_INFO("%u: RST asserted\r\n", ch->num);
card_handle_reset(ch);
chg_mask |= CEMU_STATUS_F_RESET_ACTIVE;
#ifdef BOARD_simtrace
card_set_state(ch, ISO_S_WAIT_RST);
#endif
}
ch->in_reset = active;
break;
default:
break;
}
switch (ch->state) {
@@ -1238,20 +1167,17 @@ int card_emu_set_atr(struct card_handle *ch, const uint8_t *atr, uint8_t len)
if (len > sizeof(ch->atr.atr))
return -1;
/* ignore new ATR for now since we PPS has not been tested
memcpy(ch->atr.atr, atr, len);
ch->atr.len = len;
ch->atr.idx = 0;
*/
#if TRACE_LEVEL >= TRACE_LEVEL_INFO
uint8_t i;
TRACE_INFO("%u: ATR set: ", ch->num);
for (i = 0; i < len; i++) {
for (i = 0; i < ch->atr.len; i++) {
TRACE_INFO_WP("%02x ", atr[i]);
}
TRACE_INFO_WP("\n\r");
TRACE_INFO("%u: ATR set currently ignored\n\r", ch->num);
#endif
/* FIXME: race condition with transmitting ATR to reader? */
@@ -1259,7 +1185,7 @@ int card_emu_set_atr(struct card_handle *ch, const uint8_t *atr, uint8_t len)
}
/* hardware driver informs us that one (more) ETU has expired */
void card_emu_wt_halfed(void *handle)
void card_emu_wtime_half_expired(void *handle)
{
struct card_handle *ch = handle;
/* transmit NULL procedure byte well before waiting time expires */
@@ -1269,8 +1195,10 @@ void card_emu_wt_halfed(void *handle)
case TPDU_S_WAIT_PB:
case TPDU_S_WAIT_TX:
putchar('N');
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
/* we are waiting for data from the user. Send a procedure byte to ask the
* reader to wait more time */
card_emu_uart_tx(ch->uart_chan, ISO7816_3_PB_NULL);
card_emu_uart_reset_wt(ch->uart_chan);
break;
default:
break;
@@ -1282,7 +1210,7 @@ void card_emu_wt_halfed(void *handle)
}
/* hardware driver informs us that one (more) ETU has expired */
void card_emu_wt_expired(void *handle)
void card_emu_wtime_expired(void *handle)
{
struct card_handle *ch = handle;
switch (ch->state) {
@@ -1291,7 +1219,6 @@ void card_emu_wt_expired(void *handle)
card_set_state(ch, ISO_S_IN_ATR);
break;
default:
// TODO become unresponsive
TRACE_ERROR("%u: wtime_exp\r\n", ch->num);
break;
}
@@ -1299,22 +1226,21 @@ void card_emu_wt_expired(void *handle)
/* reasonable ATR offering all protocols and voltages
* smartphones might not care, but other readers do
TS = 0x3B Direct Convention
T0 = 0x80 Y(1): b1000, K: 0 (historical bytes)
TD(1) = 0x80 Y(i+1) = b1000, Protocol T=0
----
TD(2) = 0x81 Y(i+1) = b1000, Protocol T=1
----
TD(3) = 0x1F Y(i+1) = b0001, Protocol T=15
----
TA(4) = 0xC7 Clock stop: no preference - Class accepted by the card: (3G) A 5V B 3V C 1.8V
----
Historical bytes
TCK = 0x59 correct checksum
* */
static const uint8_t default_atr[] = { 0x3B, 0x80, 0x80, 0x81 , 0x1F, 0xC7, 0x59};
*
* TS = 0x3B Direct Convention
* T0 = 0x80 Y(1): b1000, K: 0 (historical bytes)
* TD(1) = 0x80 Y(i+1) = b1000, Protocol T=0
* ----
* TD(2) = 0x81 Y(i+1) = b1000, Protocol T=1
* ----
* TD(3) = 0x1F Y(i+1) = b0001, Protocol T=15
* ----
* TA(4) = 0xC7 Clock stop: no preference - Class accepted by the card: (3G) A 5V B 3V C 1.8V
* ----
* Historical bytes
* TCK = 0x59 correct checksum
*/
static const uint8_t default_atr[] = { 0x3B, 0x80, 0x80, 0x81 , 0x1F, 0xC7, 0x59 };
static struct card_handle card_handles[NUM_SLOTS];
@@ -1324,13 +1250,19 @@ int card_emu_set_config(struct card_handle *ch, const struct cardemu_usb_msg_con
if (scfg_len >= sizeof(uint32_t))
ch->features = (scfg->features & SUPPORTED_FEATURES);
#ifdef HAVE_SLOT_MUX
if (scfg_len >= sizeof(uint32_t)+sizeof(uint8_t)) {
mux_set_slot(scfg->slot_mux_nr);
}
#endif
/* send back a report of our current configuration */
card_emu_report_config(ch);
return 0;
}
struct card_handle *card_emu_init(uint8_t slot_num, uint8_t tc_chan, uint8_t uart_chan, uint8_t in_ep, uint8_t irq_ep, bool vcc_active, bool in_reset, bool clocked)
struct card_handle *card_emu_init(uint8_t slot_num, uint8_t uart_chan, uint8_t in_ep, uint8_t irq_ep, bool vcc_active, bool in_reset, bool clocked)
{
struct card_handle *ch;
@@ -1343,7 +1275,6 @@ struct card_handle *card_emu_init(uint8_t slot_num, uint8_t tc_chan, uint8_t uar
INIT_LLIST_HEAD(&ch->uart_tx_queue);
/* initialize the card_handle with reasonable defaults */
ch->num = slot_num;
ch->irq_ep = irq_ep;
ch->in_ep = in_ep;
@@ -1352,13 +1283,12 @@ struct card_handle *card_emu_init(uint8_t slot_num, uint8_t tc_chan, uint8_t uar
ch->in_reset = in_reset;
ch->clocked = clocked;
ch->fi = ISO7816_3_DEFAULT_FI;
ch->di = ISO7816_3_DEFAULT_DI;
ch->Fi_index = ch->F_index = 1;
ch->Di_index = ch->D_index = 1;
ch->wi = ISO7816_3_DEFAULT_WI;
ch->wt = ISO7816_3_DEFAULT_WT;;
ch->tc_chan = tc_chan;
ch->uart_chan = uart_chan;
ch->waiting_time = ISO7816_3_INIT_WTIME;
ch->atr.idx = 0;
ch->atr.len = sizeof(default_atr);
@@ -1368,10 +1298,6 @@ struct card_handle *card_emu_init(uint8_t slot_num, uint8_t tc_chan, uint8_t uar
ch->tpdu.state = TPDU_S_WAIT_CLA;
card_handle_reset(ch);
#ifndef BOARD_simtrace
/* simtrace uses uart timer instead */
tc_etu_init(ch->tc_chan, ch);
#endif
return ch;
}

View File

@@ -57,7 +57,7 @@ static void usb_write_cb(uint8_t *arg, uint8_t status, uint32_t transferred,
}
/* check if the spcified IN endpoint is idle and submit the next buffer from queue */
int usb_refill_to_host(uint8_t ep)
static int usb_refill_to_host(uint8_t ep)
{
struct usb_buffered_ep *bep = usb_get_buf_ep(ep);
struct msgb *msg;
@@ -130,7 +130,7 @@ static void usb_read_cb(uint8_t *arg, uint8_t status, uint32_t transferred,
}
/* refill the read queue for data received from host PC on OUT EP, if needed */
int usb_refill_from_host(uint8_t ep)
static int usb_refill_from_host(uint8_t ep)
{
struct usb_buffered_ep *bep = usb_get_buf_ep(ep);
struct msgb *msg;
@@ -198,3 +198,45 @@ int usb_drain_queue(uint8_t ep)
return ret;
}
/* iterate over the queue of incoming USB commands and dispatch/execute
* them */
static void process_any_usb_commands(const struct usb_if *usb_if)
{
struct llist_head *queue = usb_get_queue(usb_if->ep_out);
struct llist_head *lh;
struct msgb *msg;
int i;
/* limit the number of iterations to 10, to ensure we don't get
* stuck here without returning to main loop processing */
for (i = 0; i < 10; i++) {
/* de-queue the list head in an irq-safe way */
lh = llist_head_dequeue_irqsafe(queue);
if (!lh)
break;
msg = llist_entry(lh, struct msgb, list);
usb_if->ops.rx_out(msg, usb_if);
}
}
/* perform any action related to USB processing (IRQ/INT/OUT EP refill, handling OUT) */
void usb_process(const struct usb_if *usb_if)
{
/* first try to send any pending messages on IRQ */
if (usb_if->ep_int)
usb_refill_to_host(usb_if->ep_int);
/* then try to send any pending messages on IN */
if (usb_if->ep_in)
usb_refill_to_host(usb_if->ep_in);
/* ensure we can handle incoming USB messages from the
* host */
if (usb_if->ep_out) {
usb_refill_from_host(usb_if->ep_out);
process_any_usb_commands(usb_if);
}
}

View File

@@ -1,123 +0,0 @@
/*
* 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

@@ -23,38 +23,38 @@
#include "iso7816_fidi.h"
/* Table 7 of ISO 7816-3:2006 */
const uint16_t fi_table[] = {
const uint16_t iso7816_3_fi_table[] = {
372, 372, 558, 744, 1116, 1488, 1860, 0,
0, 512, 768, 1024, 1536, 2048, 0, 0
};
/* Table 8 from ISO 7816-3:2006 */
const uint8_t di_table[] = {
const uint8_t iso7816_3_di_table[] = {
0, 1, 2, 4, 8, 16, 32, 64,
12, 20, 2, 4, 8, 16, 32, 64,
};
/* compute the F/D ratio based on Fi and Di values */
int compute_fidi_ratio(uint8_t fi, uint8_t di)
int iso7816_3_compute_fd_ratio(uint8_t f_index, uint8_t d_index)
{
uint16_t f, d;
int ret;
if (fi >= ARRAY_SIZE(fi_table) ||
di >= ARRAY_SIZE(di_table))
if (f_index >= ARRAY_SIZE(iso7816_3_fi_table) ||
d_index >= ARRAY_SIZE(iso7816_3_di_table))
return -EINVAL;
f = fi_table[fi];
f = iso7816_3_fi_table[f_index];
if (f == 0)
return -EINVAL;
d = di_table[di];
d = iso7816_3_di_table[d_index];
if (d == 0)
return -EINVAL;
/* See table 7 of ISO 7816-3: From 1000 on we divide by 1/d,
* which equals a multiplication by d */
if (di < 8)
if (d_index < 8)
ret = f / d;
else
ret = f * d;

View File

@@ -22,7 +22,6 @@
#include "simtrace.h"
#include "ringbuffer.h"
#include "card_emu.h"
#include "iso7816_3.h"
#include "iso7816_fidi.h"
#include "utils.h"
#include <osmocom/core/linuxlist.h>
@@ -35,6 +34,8 @@
#define TRACE_ENTRY() TRACE_DEBUG("%s entering\r\n", __func__)
static void dispatch_received_usb_msg(struct msgb *msg, const struct usb_if *usb_if);
#ifdef PINS_CARDSIM
static const Pin pins_cardsim[] = PINS_CARDSIM;
#endif
@@ -43,6 +44,10 @@ static const Pin pins_cardsim[] = PINS_CARDSIM;
static const Pin pins_usim1[] = {PINS_USIM1};
static const Pin pin_usim1_rst = PIN_USIM1_nRST;
static const Pin pin_usim1_vcc = PIN_USIM1_VCC;
#ifdef PIN_USIM1_IO_DIR
static const Pin pin_io_dir = PIN_USIM1_IO_DIR;
#endif
#ifdef CARDEMU_SECOND_UART
static const Pin pins_usim2[] = {PINS_USIM2};
@@ -55,15 +60,17 @@ struct cardem_inst {
struct card_handle *ch;
struct llist_head usb_out_queue;
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 {
/*! receiver waiting time to trigger timeout (0 to deactivate it) */
uint32_t total;
/*! remaining waiting time (we may need multiple timer runs to reach total */
uint32_t remaining;
/*! did we already notify about half the time having expired? */
bool half_time_notified;
} wt;
int usb_pending_old;
uint8_t ep_out;
uint8_t ep_in;
uint8_t ep_int;
const Pin pin_io;
struct usb_if usb_if;
const Pin pin_insert;
#ifdef DETECT_VCC_BY_ADC
uint32_t vcc_uv;
@@ -83,10 +90,16 @@ struct cardem_inst cardem_inst[] = {
.id = ID_USART1,
.state = USART_RCV
},
.ep_out = SIMTRACE_CARDEM_USB_EP_USIM1_DATAOUT,
.ep_in = SIMTRACE_CARDEM_USB_EP_USIM1_DATAIN,
.ep_int = SIMTRACE_CARDEM_USB_EP_USIM1_INT,
.pin_io = PIN_USIM1_IO,
.usb_if = {
.if_num = 0,
.ep_out = SIMTRACE_CARDEM_USB_EP_USIM1_DATAOUT,
.ep_in = SIMTRACE_CARDEM_USB_EP_USIM1_DATAIN,
.ep_int = SIMTRACE_CARDEM_USB_EP_USIM1_INT,
.data = &cardem_inst[0],
.ops = {
.rx_out = dispatch_received_usb_msg,
},
},
#ifdef PIN_SET_USIM1_PRES
.pin_insert = PIN_SET_USIM1_PRES,
#endif
@@ -99,10 +112,16 @@ struct cardem_inst cardem_inst[] = {
.id = ID_USART0,
.state = USART_RCV
},
.ep_out = SIMTRACE_CARDEM_USB_EP_USIM2_DATAOUT,
.ep_in = SIMTRACE_CARDEM_USB_EP_USIM2_DATAIN,
.ep_int = SIMTRACE_CARDEM_USB_EP_USIM2_INT,
.pin_io = PIN_USIM2_IO,
.usb_if = {
.if_num = 1,
.ep_out = SIMTRACE_CARDEM_USB_EP_USIM2_DATAOUT,
.ep_in = SIMTRACE_CARDEM_USB_EP_USIM2_DATAIN,
.ep_int = SIMTRACE_CARDEM_USB_EP_USIM2_INT,
.data = &cardem_inst[1],
.ops = {
.rx_out = dispatch_received_usb_msg,
},
},
#ifdef PIN_SET_USIM2_PRES
.pin_insert = PIN_SET_USIM2_PRES,
#endif
@@ -142,22 +161,44 @@ void card_emu_uart_wait_tx_idle(uint8_t uart_chan)
wait_tx_idle(usart);
}
static void card_emu_uart_set_direction(uint8_t uart_chan, bool tx)
{
/* only on some boards (octsimtest) we hae an external level
* shifter that requires us to switch the direction between RX and TX */
#ifdef PIN_USIM1_IO_DIR
if (uart_chan == 0) {
if (tx)
PIO_Set(&pin_io_dir);
else
PIO_Clear(&pin_io_dir);
}
#endif
}
/* call-back from card_emu.c to enable/disable transmit and/or receive */
void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx)
{
Usart *usart = get_usart_by_chan(uart_chan);
switch (rxtx) {
case ENABLE_TX:
USART_DisableIt(usart, ~US_IER_TXRDY);
card_emu_uart_set_direction(uart_chan, true);
USART_DisableIt(usart, ~(US_IER_TXRDY | US_IER_TIMEOUT));
/* as irritating as it is, we actually want to keep the
* receiver enabled during transmit */
USART_SetReceiverEnabled(usart, 1);
usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
#ifdef BOARD_simtrace
USART_EnableIt(usart, US_IER_TXRDY | US_IER_TIMEOUT);
#else
USART_EnableIt(usart, US_IER_TXRDY);
#endif
USART_SetTransmitterEnabled(usart, 1);
break;
case ENABLE_TX_TIMER_ONLY:
/* enable the transmitter without generating TXRDY interrupts
* just so that the timer can run */
USART_DisableIt(usart, ~US_IER_TIMEOUT);
/* as irritating as it is, we actually want to keep the
* receiver enabled during transmit */
USART_SetReceiverEnabled(usart, 1);
usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
USART_EnableIt(usart, US_IER_TIMEOUT);
USART_SetTransmitterEnabled(usart, 1);
break;
case ENABLE_RX:
@@ -166,12 +207,9 @@ void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx)
* transmitter enabled during receive */
USART_SetTransmitterEnabled(usart, 1);
wait_tx_idle(usart);
card_emu_uart_set_direction(uart_chan, false);;
usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
#ifdef BOARD_simtrace
USART_EnableIt(usart, US_IER_RXRDY | US_IER_TIMEOUT);
#else
USART_EnableIt(usart, US_IER_RXRDY);
#endif
USART_SetReceiverEnabled(usart, 1);
break;
case 0:
@@ -209,63 +247,101 @@ int card_emu_uart_tx(uint8_t uart_chan, uint8_t byte)
return 1;
}
static uint16_t compute_next_timeout(struct cardem_inst *ci)
{
uint32_t want_to_expire;
/* FIXME: integrate this with actual irq handler */
if (ci->wt.total == 0)
return 0;
if (!ci->wt.half_time_notified) {
/* we need to make sure to expire after half the total waiting time */
OSMO_ASSERT(ci->wt.remaining > (ci->wt.total / 2));
want_to_expire = ci->wt.remaining - (ci->wt.total / 2);
} else
want_to_expire = ci->wt.remaining;
/* if value exceeds the USART TO range, use the maximum possible value for one round */
return OSMO_MIN(want_to_expire, 0xffff);
}
/*! common handler if interrupt was received.
* \param[in] inst_num Instance number, range 0..1 (some boards only '0' permitted) */
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;
}
OSMO_ASSERT(inst_num < ARRAY_SIZE(cardem_inst));
Usart *usart = get_usart_by_chan(inst_num);
struct cardem_inst *ci = &cardem_inst[inst_num];
uint32_t csr;
uint8_t byte = 0;
uint32_t errflags = (US_CSR_OVRE | US_CSR_FRAME | US_CSR_PARE | US_CSR_NACK | (1 << 10));
#ifndef BOARD_simtrace
errflags |= US_CSR_TIMEOUT;
#endif
csr = usart->US_CSR & usart->US_IMR; // save state/flags before they get changed
/* get one atomic snapshot of state/flags before they get changed */
csr = usart->US_CSR & usart->US_IMR;
if (csr & US_CSR_RXRDY) { // bytes has been received
byte = (usart->US_RHR) & 0xFF; // ready out byte
if (rbuf_write(&ci->rb, byte) < 0) // store byte in buffer
TRACE_ERROR("rbuf overrun\r\n"); // error if could not store in buffer
/* check if one byte has been completely received and is now in the holding register */
if (csr & US_CSR_RXRDY) {
/* read the bye from the holding register */
byte = (usart->US_RHR) & 0xFF;
/* append it to the buffer */
if (rbuf_write(&ci->rb, byte) < 0)
TRACE_ERROR("rbuf overrun\r\n");
}
if (csr & US_CSR_TXRDY) { // ready to transmit the next byte
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); // stop the TX ready signal if not byte has been transmitted
/* check if the transmitter is ready for the next byte */
if (csr & US_CSR_TXRDY) {
/* transmit next byte and check if more bytes are to be transmitted */
if (card_emu_tx_byte(ci->ch) == 0) {
/* stop the TX ready interrupt of no more bytes to transmit */
USART_DisableIt(usart, US_IER_TXRDY);
}
}
if (csr & errflags) { // error flag set
usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK; // reset UART state to clear flag
TRACE_ERROR("%u USART error on 0x%x status: 0x%lx\n", ci->num, byte, csr); // warn user about error
/* check if any error flags are set */
if (csr & (US_CSR_OVRE|US_CSR_FRAME|US_CSR_PARE|US_CSR_NACK|(1<<10))) {
/* clear any error flags */
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);
}
#ifdef BOARD_simtrace
// 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)
/* check if the timeout has expired. We "abuse" the receive timer for tracking
* how many etu have expired since we last sent a byte. See section
* 33.7.3.11 "Receiver Time-out" of the SAM3S8 Data Sheet */
if (csr & US_CSR_TIMEOUT) {
/* clear timeout flag (and stop timeout until next character is received) */
usart->US_CR |= US_CR_STTTO;
/* RX has been inactive for some time */
if (ci->wt.remaining <= (usart->US_RTOR & 0xffff)) {
/* waiting time is over; will stop the timer */
ci->wt.remaining = 0;
} 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
/* subtract the actual timeout since the new might not have been set and
* reloaded yet */
ci->wt.remaining -= (usart->US_RTOR & 0xffff);
}
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
if (ci->wt.remaining == 0) {
/* let the FSM know that WT has expired */
card_emu_wtime_expired(ci->ch);
/* don't automatically re-start in this case */
} else {
usart->US_RTOR = ci->wt_remaining;
bool half_time_just_reached = false;
if (ci->wt.remaining <= ci->wt.total / 2 && !ci->wt.half_time_notified) {
ci->wt.half_time_notified = true;
/* don't immediately call card_emu_wtime_half_expired(), as that
* in turn may calls card_emu_uart_update_wt() which will change
* the timeout but would be overridden 4 lines below */
half_time_just_reached = true;
}
/* update the counter no matter if we reached half time or not */
usart->US_RTOR = compute_next_timeout(ci);
/* restart the counter (if wt is 0, the timeout is not started) */
usart->US_CR |= US_CR_RETTO;
if (half_time_just_reached)
card_emu_wtime_half_expired(ci->ch);
}
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)
}
#endif
}
/*! ISR called for USART0 */
@@ -294,89 +370,39 @@ int card_emu_uart_update_fidi(uint8_t uart_chan, unsigned int fidi)
return 0;
}
// call-back from card_emu.c to change UART baud rate
void card_emu_uart_update_fd(uint8_t uart_chan, uint16_t f, uint8_t d)
{
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;
}
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
}
}
/*! Update WT on USART peripheral. Will automatically re-start timer with new value.
* \param[in] usart USART peripheral to configure
* \param[in] wt inactivity Waiting Time before card_emu_wtime_expired is called (0 to disable) */
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;
}
OSMO_ASSERT(uart_chan < ARRAY_SIZE(cardem_inst));
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;
Usart *usart = get_usart_by_chan(uart_chan);
if (ci->wt.total != wt) {
TRACE_DEBUG("%u: USART WT changed from %lu to %lu ETU\r\n", uart_chan,
ci->wt.total, wt);
}
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);
ci->wt.total = wt;
/* reset and start the timer */
card_emu_uart_reset_wt(uart_chan);
}
/*! Reset and re-start waiting timeout count down on USART peripheral.
* \param[in] usart USART peripheral to configure */
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;
}
OSMO_ASSERT(uart_chan < ARRAY_SIZE(cardem_inst));
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;
}
Usart *usart = get_usart_by_chan(uart_chan);
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);
}
/* FIXME: guard against race with interrupt handler */
ci->wt.remaining = ci->wt.total;
ci->wt.half_time_notified = false;
usart->US_RTOR = compute_next_timeout(ci);
/* restart the counter (if wt is 0, the timeout is not started) */
usart->US_CR |= US_CR_RETTO;
}
/* call-back from card_emu.c to force a USART interrupt */
@@ -398,6 +424,9 @@ void card_emu_uart_interrupt(uint8_t uart_chan)
***********************************************************************/
#ifdef DETECT_VCC_BY_ADC
#if !defined(VCC_UV_THRESH_1V8) || !defined(VCC_UV_THRESH_3V)
#error "You must define VCC_UV_THRESH_{1V1,3V} if you use ADC VCC detection"
#endif
static volatile int adc_triggered = 0;
static int adc_sam3s_reva_errata = 0;
@@ -446,9 +475,6 @@ static int card_vcc_adc_init(void)
return 0;
}
#define VCC_UV_THRESH_1V8 1500000
#define VCC_UV_THRESH_3V 2500000
static void process_vcc_adc(struct cardem_inst *ci)
{
if (ci->vcc_uv >= VCC_UV_THRESH_3V &&
@@ -546,20 +572,12 @@ void mode_cardemu_init(void)
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
PIO_Configure(pins_cardsim, PIO_LISTSIZE(pins_cardsim));
#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
card_vcc_adc_init(); // configure the ADC to measure VCC
card_vcc_adc_init();
#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);
rbuf_reset(&cardem_inst[0].rb);
@@ -567,20 +585,7 @@ void mode_cardemu_init(void)
/* configure USART as ISO-7816 slave (e.g. card) */
ISO7816_Init(&cardem_inst[0].usart_info, CLK_SLAVE);
#ifdef BOARD_simtrace
/* simtrace board uses uart timeouts */
/* don't use receive timeout timer for now */
cardem_inst[0].usart_info.base->US_RTOR = 0;
/* enable interrupts to indicate when data has been received or timeout occurred */
USART_EnableIt(cardem_inst[0].usart_info.base, US_IER_RXRDY | US_IER_TIMEOUT);
#else
/* enable interrupts to indicate when data has been received */
USART_EnableIt(cardem_inst[0].usart_info.base, US_IER_RXRDY );
#endif
/* enable interrupt requests for the USART peripheral */
NVIC_EnableIRQ(USART1_IRQn);
PIO_ConfigureIt(&pin_usim1_rst, usim1_rst_irqhandler);
PIO_EnableIt(&pin_usim1_rst);
@@ -596,21 +601,17 @@ void mode_cardemu_init(void)
do {} while (!adc_triggered); /* wait for first ADC reading */
#endif /* DETECT_VCC_BY_ADC */
cardem_inst[0].ch = card_emu_init(0, 2, 0, SIMTRACE_CARDEM_USB_EP_USIM1_DATAIN,
cardem_inst[0].ch = card_emu_init(0, 0, SIMTRACE_CARDEM_USB_EP_USIM1_DATAIN,
SIMTRACE_CARDEM_USB_EP_USIM1_INT, cardem_inst[0].vcc_active,
cardem_inst[0].rst_active, cardem_inst[0].vcc_active);
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
INIT_LLIST_HEAD(&cardem_inst[1].usb_out_queue);
rbuf_reset(&cardem_inst[1].rb);
PIO_Configure(pins_usim2, PIO_LISTSIZE(pins_usim2));
ISO7816_Init(&cardem_inst[1].usart_info, CLK_SLAVE);
// TODO enable timeout
/* TODO enable timeout */
NVIC_EnableIRQ(USART0_IRQn);
PIO_ConfigureIt(&pin_usim2_rst, usim2_rst_irqhandler);
PIO_EnableIt(&pin_usim2_rst);
@@ -623,11 +624,11 @@ void mode_cardemu_init(void)
do {} while (!adc_triggered); /* wait for first ADC reading */
#endif /* DETECT_VCC_BY_ADC */
cardem_inst[1].ch = card_emu_init(1, 0, 1, SIMTRACE_CARDEM_USB_EP_USIM2_DATAIN,
cardem_inst[1].ch = card_emu_init(1, 1, SIMTRACE_CARDEM_USB_EP_USIM2_DATAIN,
SIMTRACE_CARDEM_USB_EP_USIM2_INT, cardem_inst[1].vcc_active,
cardem_inst[1].rst_active, cardem_inst[1].vcc_active);
sim_switch_use_physical(1, 1);
// TODO check rst and vcc
/* TODO check RST and VCC */
#endif /* CARDEMU_SECOND_UART */
}
@@ -671,6 +672,26 @@ static void dispatch_usb_command_generic(struct msgb *msg, struct cardem_inst *c
usb_buf_free(msg);
}
static void process_card_insert(struct cardem_inst *ci, bool card_insert)
{
TRACE_INFO("%u: set card_insert to %s\r\n", ci->num, card_insert ? "INSERTED" : "REMOVED");
#ifdef HAVE_BOARD_CARDINSERT
board_set_card_insert(ci, card_insert);
#else
if (!ci->pin_insert.pio) {
TRACE_INFO("%u: skipping unsupported card_insert to %s\r\n",
ci->num, card_insert ? "INSERTED" : "REMOVED");
return;
}
if (card_insert)
PIO_Set(&ci->pin_insert);
else
PIO_Clear(&ci->pin_insert);
#endif
}
/* handle a single USB command as received from the USB host */
static void dispatch_usb_command_cardem(struct msgb *msg, struct cardem_inst *ci)
{
@@ -694,18 +715,7 @@ static void dispatch_usb_command_cardem(struct msgb *msg, struct cardem_inst *ci
break;
case SIMTRACE_MSGT_DT_CEMU_CARDINSERT:
cardins = (struct cardemu_usb_msg_cardinsert *) msg->l2h;
if (!ci->pin_insert.pio) {
TRACE_INFO("%u: skipping unsupported card_insert to %s\r\n",
ci->num, cardins->card_insert ? "INSERTED" : "REMOVED");
usb_buf_free(msg);
break;
}
TRACE_INFO("%u: set card_insert to %s\r\n", ci->num,
cardins->card_insert ? "INSERTED" : "REMOVED");
if (cardins->card_insert)
PIO_Set(&ci->pin_insert);
else
PIO_Clear(&ci->pin_insert);
process_card_insert(ci, cardins->card_insert);
usb_buf_free(msg);
break;
case SIMTRACE_MSGT_BD_CEMU_STATUS:
@@ -791,8 +801,9 @@ static void dispatch_usb_command_modem(struct msgb *msg, struct cardem_inst *ci)
}
/* handle a single USB command as received from the USB host */
static void dispatch_usb_command(struct msgb *msg, struct cardem_inst *ci)
static void dispatch_usb_command(struct msgb *msg, const struct usb_if *usb_if)
{
struct cardem_inst *ci = usb_if->data;
struct simtrace_msg_hdr *sh = (struct simtrace_msg_hdr *) msg->l1h;
if (msgb_length(msg) < sizeof(*sh)) {
@@ -821,7 +832,8 @@ static void dispatch_usb_command(struct msgb *msg, struct cardem_inst *ci)
}
}
static void dispatch_received_msg(struct msgb *msg, struct cardem_inst *ci)
/* handle a single USB transfer as received from the USB host */
static void dispatch_received_usb_msg(struct msgb *msg, const struct usb_if *usb_if)
{
struct msgb *segm;
struct simtrace_msg_hdr *mh;
@@ -832,7 +844,7 @@ static void dispatch_received_msg(struct msgb *msg, struct cardem_inst *ci)
mh = (struct simtrace_msg_hdr *) msg->data;
if (mh->msg_len == msgb_length(msg)) {
/* fast path: only one message in buffer */
dispatch_usb_command(msg, ci);
dispatch_usb_command(msg, usb_if);
return;
}
@@ -841,23 +853,23 @@ static void dispatch_received_msg(struct msgb *msg, struct cardem_inst *ci)
while (1) {
mh = (struct simtrace_msg_hdr *) msg->data;
segm = usb_buf_alloc(ci->ep_out);
segm = usb_buf_alloc(usb_if->ep_out);
if (!segm) {
TRACE_ERROR("%u: ENOMEM during msg segmentation\r\n",
ci->num);
usb_if->if_num);
break;
}
if (mh->msg_len > msgb_length(msg)) {
TRACE_ERROR("%u: Unexpected large message (%u bytes)\r\n",
ci->num, mh->msg_len);
usb_if->if_num, mh->msg_len);
usb_buf_free(segm);
break;
} else {
uint8_t *cur = msgb_put(segm, mh->msg_len);
segm->l1h = segm->head;
memcpy(cur, mh, mh->msg_len);
dispatch_usb_command(segm, ci);
dispatch_usb_command(segm, usb_if);
}
/* pull this message */
msgb_pull(msg, mh->msg_len);
@@ -869,35 +881,14 @@ static void dispatch_received_msg(struct msgb *msg, struct cardem_inst *ci)
usb_buf_free(msg);
}
/* iterate over the queue of incoming USB commands and dispatch/execute
* them */
static void process_any_usb_commands(struct llist_head *main_q,
struct cardem_inst *ci)
{
struct llist_head *lh;
struct msgb *msg;
int i;
/* limit the number of iterations to 10, to ensure we don't get
* stuck here without returning to main loop processing */
for (i = 0; i < 10; i++) {
/* de-queue the list head in an irq-safe way */
lh = llist_head_dequeue_irqsafe(main_q);
if (!lh)
break;
msg = llist_entry(lh, struct msgb, list);
dispatch_received_msg(msg, ci);
}
}
/* main loop function, called repeatedly */
void mode_cardemu_run(void)
{
struct llist_head *queue;
unsigned int i;
for (i = 0; i < ARRAY_SIZE(cardem_inst); i++) {
struct cardem_inst *ci = &cardem_inst[i];
struct usb_if *usb_if = &ci->usb_if;
/* drain the ring buffer from UART into card_emu */
while (1) {
@@ -914,16 +905,6 @@ void mode_cardemu_run(void)
process_io_statechg(ci);
/* first try to send any pending messages on IRQ */
usb_refill_to_host(ci->ep_int);
/* then try to send any pending messages on IN */
usb_refill_to_host(ci->ep_in);
/* ensure we can handle incoming USB messages from the
* host */
usb_refill_from_host(ci->ep_out);
queue = usb_get_queue(ci->ep_out);
process_any_usb_commands(queue, ci);
usb_process(&ci->usb_if);
}
}

View File

@@ -125,7 +125,7 @@ void update_fidi(Usart_info *usart, uint8_t fidi)
uint8_t fi = fidi >> 4;
uint8_t di = fidi & 0xf;
int ratio = compute_fidi_ratio(fi, di);
int ratio = iso7816_3_compute_fd_ratio(fi, di);
if (ratio > 0 && ratio < 0x8000) {
/* make sure USART uses new F/D ratio */

View File

@@ -658,9 +658,10 @@ static void process_byte_pps(uint8_t byte)
fn = 1;
dn = 1;
}
TRACE_INFO("PPS negotiation successful: Fn=%u Dn=%u\n\r", fi_table[fn], di_table[dn]);
TRACE_INFO("PPS negotiation successful: Fn=%u Dn=%u\n\r",
iso7816_3_fi_table[fn], iso7816_3_di_table[dn]);
update_fidi(&sniff_usart, pps_cur[2]);
update_wt(0, di_table[dn]);
update_wt(0, iso7816_3_di_table[dn]);
usb_send_fidi(pps_cur[2]); /* send Fi/Di change notification to host software over USB */
} else { /* checksum is invalid */
TRACE_INFO("PPS negotiation failed\n\r");
@@ -974,20 +975,42 @@ static void usb_send_change(uint32_t flags)
usb_msg_upd_len_and_submit(usb_msg);
}
/* handle incoming message from USB OUT EP */
static void dispatch_usb_out(struct msgb *msg, const struct usb_if *usb_if)
{
struct simtrace_msg_hdr *sh = (struct simtrace_msg_hdr *) msg->l1h;
if (msgb_length(msg) < sizeof(*sh)) {
usb_buf_free(msg);
return;
}
msg->l2h = msg->l1h + sizeof(*sh);
switch (sh->msg_class) {
case SIMTRACE_MSGC_GENERIC:
break;
default:
break;
}
usb_buf_free(msg);
}
static const struct usb_if sniffer_usb_if = {
.if_num = 0,
.ep_in = SIMTRACE_USB_EP_CARD_DATAIN,
.ep_int = SIMTRACE_USB_EP_CARD_INT,
.ep_out = SIMTRACE_USB_EP_CARD_DATAOUT,
.ops = {
.rx_out = dispatch_usb_out,
}
};
/* Main (idle/busy) loop of this USB configuration */
void Sniffer_run(void)
{
/* Handle USB queue */
/* first try to send any pending messages on INT */
usb_refill_to_host(SIMTRACE_USB_EP_CARD_INT);
/* then try to send any pending messages on IN */
usb_refill_to_host(SIMTRACE_USB_EP_CARD_DATAIN);
/* ensure we can handle incoming USB messages from the host */
/* currently we don't need any incoming data
usb_refill_from_host(SIMTRACE_USB_EP_CARD_DATAOUT);
struct llist_head *queue = usb_get_queue(SIMTRACE_USB_EP_CARD_DATAOUT);
process_any_usb_commands(queue);
*/
usb_process(&sniffer_usb_if);
/* WARNING: the signal data and flags are not synchronized. We have to hope
* the processing is fast enough to not land in the wrong state while data

View File

@@ -0,0 +1,14 @@
#include <stdint.h>
#include <osmocom/core/panic.h>
/* This is what's minimally required to fix builds on Ubuntu 20.04,
* where stack smashing protection is enabled by default when using dpkg
* - even when cross-compiling: https://osmocom.org/issues/4687
*/
uintptr_t __stack_chk_guard = 0xdeadbeef;
void __stack_chk_fail(void)
{
osmo_panic("Stack smashing detected!\r\n");
}

View File

@@ -23,9 +23,6 @@
#include "chip.h"
void card_emu_wt_halfed(void *handle);
void card_emu_wt_expired(void *handle);
/* pins for Channel 0 of TC-block 0, we only use TCLK + TIOB */
#define PIN_TCLK0 {PIO_PA4, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT }
#define PIN_TIOA0 {PIO_PA0, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
@@ -88,7 +85,7 @@ static void tc_etu_irq(struct tc_etu_state *te)
te->nr_events++;
if (te->nr_events == te->wait_events/2) {
/* Indicate that half the waiting tim has expired */
card_emu_wt_halfed(te->handle);
tc_etu_wtime_half_expired(te->handle);
}
if (te->nr_events >= te->wait_events) {
TcChannel *chan = te->chan;
@@ -99,7 +96,7 @@ static void tc_etu_irq(struct tc_etu_state *te)
chan->TC_CCR = TC_CCR_CLKEN;
/* Indicate that the waiting tim has expired */
card_emu_wt_expired(te->handle);
tc_etu_wtime_expired(te->handle);
}
}
}

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

View File

@@ -46,7 +46,7 @@ static osmo_panic_handler_t osmo_panic_handler = (void*)0;
__attribute__ ((format (printf, 1, 0)))
static void osmo_panic_default(const char *fmt, va_list args)
{
vfprintf(stderr, fmt, args);
vfprintf_sync(stderr, fmt, args);
osmo_generate_backtrace();
assert(0);
}

View File

@@ -13,6 +13,20 @@
#define PHONE_INT 2
#define PHONE_DATAOUT 3
/* stub for stdio */
signed int printf_sync(const char *pFormat, ...)
{
va_list ap;
signed int result;
va_start(ap, pFormat);
result = vprintf(pFormat, ap);
va_end(ap);
return result;
}
/***********************************************************************
* stub functions required by card_emu.c
***********************************************************************/
@@ -50,6 +64,9 @@ void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx)
case ENABLE_TX:
rts = "TX";
break;
case ENABLE_TX_TIMER_ONLY:
rts = "TX-TIMER-ONLY";
break;
case ENABLE_RX:
rts = "RX";
break;
@@ -66,29 +83,14 @@ void card_emu_uart_interrupt(uint8_t uart_chan)
printf("uart_interrupt(uart_chan=%u)\n", uart_chan);
}
void tc_etu_set_wtime(uint8_t tc_chan, uint16_t wtime)
void card_emu_uart_update_wt(uint8_t uart_chan, uint32_t wt)
{
printf("tc_etu_set_wtime(tc_chan=%u, wtime=%u)\n", tc_chan, wtime);
printf("%s(uart_chan=%u, wtime=%u)\n", __func__, uart_chan, wt);
}
void tc_etu_set_etu(uint8_t tc_chan, uint16_t etu)
void card_emu_uart_reset_wt(uint8_t uart_chan)
{
printf("tc_etu_set_etu(tc_chan=%u, etu=%u)\n", tc_chan, etu);
}
void tc_etu_init(uint8_t chan_nr, void *handle)
{
printf("tc_etu_init(tc_chan=%u)\n", chan_nr);
}
void tc_etu_enable(uint8_t chan_nr)
{
printf("tc_etu_enable(tc_chan=%u)\n", chan_nr);
}
void tc_etu_disable(uint8_t chan_nr)
{
printf("tc_etu_disable(tc_chan=%u)\n", chan_nr);
printf("%s(uart_chan=%u\n", __func__, uart_chan);
}
@@ -136,7 +138,7 @@ static void io_start_card(struct card_handle *ch)
/* release from reset and verify th ATR */
card_emu_io_statechg(ch, CARD_IO_RST, 0);
/* simulate waiting time before ATR expired */
tc_etu_wtime_expired(ch);
card_emu_wtime_expired(ch);
verify_atr(ch);
}
@@ -408,7 +410,7 @@ int main(int argc, char **argv)
struct card_handle *ch;
unsigned int i;
ch = card_emu_init(0, 23, 42, PHONE_DATAIN, PHONE_INT, false, true, false);
ch = card_emu_init(0, 42, PHONE_DATAIN, PHONE_INT, false, true, false);
assert(ch);
usb_buf_init();

3
host/.gitignore vendored
View File

@@ -34,5 +34,4 @@ libtool
simtrace2-list
simtrace2-sniff
simtrace2-remsim
simtrace2-remsim-usb2udp
simtrace2-cardem-pcsc

View File

@@ -3,7 +3,7 @@ AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include
SUBDIRS = include lib src contrib #tests examples doc
EXTRA_DIST = .version git-version-gen
EXTRA_DIST = .version
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libosmo-simtrace2.pc

View File

@@ -1,28 +0,0 @@
LDFLAGS+=`pkg-config --libs libusb-1.0 libosmocore` -pthread
CFLAGS=-Wall -g
APPS=simtrace2-remsim simtrace2-remsim-usb2udp simtrace2-list simtrace2-sniff
all: $(APPS)
simtrace2-remsim: simtrace2-remsim.o apdu_dispatch.o simtrace2-discovery.o simtrace2_api.o libusb_util.o
$(CC) -o $@ $^ $(LDFLAGS) `pkg-config --libs libosmosim libpcsclite`
simtrace2-remsim-usb2udp: usb2udp.o simtrace2-discovery.o
$(CC) -o $@ $^ $(LDFLAGS)
simtrace2-list: simtrace2_usb.o libusb_util.o
$(CC) -o $@ $^ $(LDFLAGS)
simtrace2-sniff: simtrace2-sniff.o simtrace2-discovery.o libusb_util.o
$(CC) -o $@ $^ $(LDFLAGS)
%.o: %.c
$(CC) $(CFLAGS) `pkg-config --cflags libusb-1.0 libosmocore` -o $@ -c $^
clean:
@rm -f *.o $(APPS)
install: $(APPS)
mkdir -p $(DESTDIR)/usr/bin
cp $(APPS) $(DESTDIR)/usr/bin/

View File

@@ -1,5 +1,5 @@
AC_INIT([simtrace2],
m4_esyscmd([./git-version-gen .tarball-version]),
m4_esyscmd([../git-version-gen ../.tarball-version]),
[simtrace@lists.osmocom.org])
dnl *This* is the root dir, even if an install-sh exists in ../ or ../../
@@ -100,4 +100,5 @@ AC_OUTPUT(
src/Makefile
lib/Makefile
contrib/Makefile
contrib/simtrace2.spec
Makefile)

View File

@@ -0,0 +1,99 @@
#
# spec file for package simtrace2
#
# Copyright (c) 2018, Martin Hauke <mardnh@gmx.de>
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
# upon. The license for this file, and modifications and additions to the
# file, is the same license as for the pristine package itself (unless the
# license for the pristine package is not an Open Source License, in which
# case the license is the MIT License). An "Open Source License" is a
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.
Name: simtrace2
Version: @VERSION@
Release: 0
Summary: Osmocom SIMtrace host utility
License: GPL-2.0-or-later
Group: Productivity/Telephony/Utilities
URL: https://osmocom.org/projects/simtrace2/wiki
Source: %{name}-%{version}.tar.xz
BuildRequires: autoconf
BuildRequires: automake
BuildRequires: libtool
BuildRequires: pkgconfig
BuildRequires: pkgconfig(libosmocore)
BuildRequires: pkgconfig(libosmosim)
BuildRequires: pkgconfig(libpcsclite)
BuildRequires: pkgconfig(libusb-1.0)
BuildRequires: pkgconfig(libosmousb) >= 0.0.0
BuildRequires: pkgconfig(udev)
%description
Osmocom SIMtrace 2 is a software and hardware system for passively
tracing SIM-ME communication between the SIM card and the mobile phone,
and remote SIM operation.
This package contains SIMtrace 2 host utility.
%package -n libosmo-simtrace2-0
Summary: Shared Library part of libosmo-simtrace2
Group: System/Libraries
%description -n libosmo-simtrace2-0
This library contains core "driver" functionality to interface with the
Osmocom SIMtrace2 (and compatible) USB device firmware. It enables
applications to implement SIM card / smart card tracing as well as
SIM / smart card emulation functions.
%package -n libosmo-simtrace2-devel
Summary: Development files for the Osmocom SIMtrace2 library
Group: Development/Libraries/C and C++
Requires: libosmo-simtrace2-0 = %{version}
%description -n libosmo-simtrace2-devel
Osmocom SIMtrace2 (and compatible) USB device firmware. It enables
applications to implement SIM card / smart card tracing as well as
SIM / smart card emulation functions.
This subpackage contains libraries and header files for developing
applications that want to make use of libosmo-simtrace2.
%prep
%setup -q
%build
cd host
echo "%{version}" >.tarball-version
autoreconf -fiv
%configure --disable-static
make %{?_smp_mflags}
%install
%make_install -C host
install -Dm0644 host/contrib/99-simtrace2.rules %{buildroot}/%{_udevrulesdir}/99-simtrace2.rules
find %{buildroot} -type f -name "*.la" -delete -print
%post -n libosmo-simtrace2-0 -p /sbin/ldconfig
%postun -n libosmo-simtrace2-0 -p /sbin/ldconfig
%files
%doc README.md
%{_bindir}/simtrace2-cardem-pcsc
%{_bindir}/simtrace2-list
%{_bindir}/simtrace2-sniff
%{_udevrulesdir}/99-simtrace2.rules
%files -n libosmo-simtrace2-0
%{_libdir}/libosmo-simtrace2.so.0*
%files -n libosmo-simtrace2-devel
%dir %{_includedir}/osmocom/
%dir %{_includedir}/osmocom/simtrace2/
%{_includedir}/osmocom/simtrace2/*.h
%{_libdir}/libosmo-simtrace2.so
%{_libdir}/pkgconfig/libosmo-simtrace2.pc
%changelog

View File

@@ -1,151 +0,0 @@
#!/bin/sh
# Print a version string.
scriptversion=2010-01-28.01
# Copyright (C) 2007-2010 Free Software Foundation, Inc.
#
# 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 3 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, see <http://www.gnu.org/licenses/>.
# This script is derived from GIT-VERSION-GEN from GIT: http://git.or.cz/.
# It may be run two ways:
# - from a git repository in which the "git describe" command below
# produces useful output (thus requiring at least one signed tag)
# - from a non-git-repo directory containing a .tarball-version file, which
# presumes this script is invoked like "./git-version-gen .tarball-version".
# In order to use intra-version strings in your project, you will need two
# separate generated version string files:
#
# .tarball-version - present only in a distribution tarball, and not in
# a checked-out repository. Created with contents that were learned at
# the last time autoconf was run, and used by git-version-gen. Must not
# be present in either $(srcdir) or $(builddir) for git-version-gen to
# give accurate answers during normal development with a checked out tree,
# but must be present in a tarball when there is no version control system.
# Therefore, it cannot be used in any dependencies. GNUmakefile has
# hooks to force a reconfigure at distribution time to get the value
# correct, without penalizing normal development with extra reconfigures.
#
# .version - present in a checked-out repository and in a distribution
# tarball. Usable in dependencies, particularly for files that don't
# want to depend on config.h but do want to track version changes.
# Delete this file prior to any autoconf run where you want to rebuild
# files to pick up a version string change; and leave it stale to
# minimize rebuild time after unrelated changes to configure sources.
#
# It is probably wise to add these two files to .gitignore, so that you
# don't accidentally commit either generated file.
#
# Use the following line in your configure.ac, so that $(VERSION) will
# automatically be up-to-date each time configure is run (and note that
# since configure.ac no longer includes a version string, Makefile rules
# should not depend on configure.ac for version updates).
#
# AC_INIT([GNU project],
# m4_esyscmd([build-aux/git-version-gen .tarball-version]),
# [bug-project@example])
#
# Then use the following lines in your Makefile.am, so that .version
# will be present for dependencies, and so that .tarball-version will
# exist in distribution tarballs.
#
# BUILT_SOURCES = $(top_srcdir)/.version
# $(top_srcdir)/.version:
# echo $(VERSION) > $@-t && mv $@-t $@
# dist-hook:
# echo $(VERSION) > $(distdir)/.tarball-version
case $# in
1) ;;
*) echo 1>&2 "Usage: $0 \$srcdir/.tarball-version"; exit 1;;
esac
tarball_version_file=$1
nl='
'
# First see if there is a tarball-only version file.
# then try "git describe", then default.
if test -f $tarball_version_file
then
v=`cat $tarball_version_file` || exit 1
case $v in
*$nl*) v= ;; # reject multi-line output
[0-9]*) ;;
*) v= ;;
esac
test -z "$v" \
&& echo "$0: WARNING: $tarball_version_file seems to be damaged" 1>&2
fi
if test -n "$v"
then
: # use $v
elif
v=`git describe --abbrev=4 --match='v*' HEAD 2>/dev/null \
|| git describe --abbrev=4 HEAD 2>/dev/null` \
&& case $v in
[0-9]*) ;;
v[0-9]*) ;;
*) (exit 1) ;;
esac
then
# Is this a new git that lists number of commits since the last
# tag or the previous older version that did not?
# Newer: v6.10-77-g0f8faeb
# Older: v6.10-g0f8faeb
case $v in
*-*-*) : git describe is okay three part flavor ;;
*-*)
: git describe is older two part flavor
# Recreate the number of commits and rewrite such that the
# result is the same as if we were using the newer version
# of git describe.
vtag=`echo "$v" | sed 's/-.*//'`
numcommits=`git rev-list "$vtag"..HEAD | wc -l`
v=`echo "$v" | sed "s/\(.*\)-\(.*\)/\1-$numcommits-\2/"`;
;;
esac
# Change the first '-' to a '.', so version-comparing tools work properly.
# Remove the "g" in git describe's output string, to save a byte.
v=`echo "$v" | sed 's/-/./;s/\(.*\)-g/\1-/'`;
else
v=UNKNOWN
fi
v=`echo "$v" |sed 's/^v//'`
# Don't declare a version "dirty" merely because a time stamp has changed.
git status > /dev/null 2>&1
dirty=`sh -c 'git diff-index --name-only HEAD' 2>/dev/null` || dirty=
case "$dirty" in
'') ;;
*) # Append the suffix only if there isn't one already.
case $v in
*-dirty) ;;
*) v="$v-dirty" ;;
esac ;;
esac
# Omit the trailing newline, so that m4_esyscmd can use the result directly.
echo "$v" | tr -d '\012'
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-end: "$"
# End:

View File

@@ -12,6 +12,8 @@ struct osmo_st2_transport {
uint8_t out;
uint8_t irq_in;
} usb_ep;
/* use non-blocking / asynchronous libusb I/O */
bool usb_async;
/* UDP */
int udp_fd;
@@ -39,8 +41,6 @@ struct osmo_st2_cardem_inst {
void *priv;
};
int osmo_st2_transp_tx_msg(struct osmo_st2_transport *transp, struct msgb *msg);
int osmo_st2_slot_tx_msg(struct osmo_st2_slot *slot, struct msgb *msg,
uint8_t msg_class, uint8_t msg_type);

View File

@@ -44,9 +44,13 @@
#include <osmocom/core/utils.h>
#include <osmocom/core/socket.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/logging.h>
#include <osmocom/sim/class_tables.h>
#include <osmocom/sim/sim.h>
#define LOGSLOT(slot, lvl, fmt, args...) \
LOGP(DLINP, lvl, "[%u] " fmt, (slot)->slot_nr, ## args)
/***********************************************************************
* SIMTRACE core protocol
***********************************************************************/
@@ -57,23 +61,60 @@ static struct msgb *st_msgb_alloc(void)
return msgb_alloc_headroom(1024+32, 32, "SIMtrace");
}
/*! \brief Transmit a given command to the SIMtrace2 device */
int osmo_st2_transp_tx_msg(struct osmo_st2_transport *transp, struct msgb *msg)
static void usb_out_xfer_cb(struct libusb_transfer *xfer)
{
int rc;
struct msgb *msg = xfer->user_data;
printf("<- %s\n", msgb_hexdump(msg));
if (transp->udp_fd < 0) {
int xfer_len;
rc = libusb_bulk_transfer(transp->usb_devh, transp->usb_ep.out,
msgb_data(msg), msgb_length(msg),
&xfer_len, 100000);
} else {
rc = write(transp->udp_fd, msgb_data(msg), msgb_length(msg));
switch (xfer->status) {
case LIBUSB_TRANSFER_COMPLETED:
break;
case LIBUSB_TRANSFER_NO_DEVICE:
fprintf(stderr, "USB device disappeared\n");
exit(1);
break;
default:
fprintf(stderr, "USB OUT transfer failed, status=%u\n", xfer->status);
exit(1);
break;
}
msgb_free(msg);
libusb_free_transfer(xfer);
}
static int st2_transp_tx_msg_usb_async(struct osmo_st2_transport *transp, struct msgb *msg)
{
struct libusb_transfer *xfer;
int rc;
xfer = libusb_alloc_transfer(0);
OSMO_ASSERT(xfer);
xfer->dev_handle = transp->usb_devh;
xfer->flags = 0;
xfer->type = LIBUSB_TRANSFER_TYPE_BULK;
xfer->endpoint = transp->usb_ep.out;
xfer->timeout = 100000;
xfer->user_data = msg;
xfer->length = msgb_length(msg);
xfer->buffer = msgb_data(msg);
xfer->callback = usb_out_xfer_cb;
rc = libusb_submit_transfer(xfer);
OSMO_ASSERT(rc == 0);
return rc;
}
/*! \brief Transmit a given command to the SIMtrace2 device */
static int st2_transp_tx_msg_usb_sync(struct osmo_st2_transport *transp, struct msgb *msg)
{
int rc;
int xfer_len;
rc = libusb_bulk_transfer(transp->usb_devh, transp->usb_ep.out,
msgb_data(msg), msgb_length(msg),
&xfer_len, 100000);
msgb_free(msg);
return rc;
}
@@ -98,9 +139,23 @@ static struct simtrace_msg_hdr *st_push_hdr(struct msgb *msg, uint8_t msg_class,
int osmo_st2_slot_tx_msg(struct osmo_st2_slot *slot, struct msgb *msg,
uint8_t msg_class, uint8_t msg_type)
{
struct osmo_st2_transport *transp = slot->transp;
int rc;
OSMO_ASSERT(transp);
st_push_hdr(msg, msg_class, msg_type, slot->slot_nr);
return osmo_st2_transp_tx_msg(slot->transp, msg);
if (transp->udp_fd < 0) {
if (transp->usb_async)
rc = st2_transp_tx_msg_usb_async(transp, msg);
else
rc = st2_transp_tx_msg_usb_sync(transp, msg);
} else {
rc = write(transp->udp_fd, msgb_data(msg), msgb_length(msg));
msgb_free(msg);
}
return rc;
}
/***********************************************************************
@@ -114,6 +169,8 @@ int osmo_st2_cardem_request_card_insert(struct osmo_st2_cardem_inst *ci, bool in
struct msgb *msg = st_msgb_alloc();
struct cardemu_usb_msg_cardinsert *cins;
LOGSLOT(ci->slot, LOGL_NOTICE, "<= %s(inserted=%d)\n", __func__, inserted);
cins = (struct cardemu_usb_msg_cardinsert *) msgb_put(msg, sizeof(*cins));
memset(cins, 0, sizeof(*cins));
if (inserted)
@@ -129,7 +186,7 @@ int osmo_st2_cardem_request_pb_and_rx(struct osmo_st2_cardem_inst *ci, uint8_t p
struct cardemu_usb_msg_tx_data *txd;
txd = (struct cardemu_usb_msg_tx_data *) msgb_put(msg, sizeof(*txd));
printf("<= %s(%02x, %d)\n", __func__, pb, le);
LOGSLOT(ci->slot, LOGL_DEBUG, "<= %s(pb=%02x, le=%u)\n", __func__, pb, le);
memset(txd, 0, sizeof(*txd));
txd->data_len = 1;
@@ -150,7 +207,7 @@ int osmo_st2_cardem_request_pb_and_tx(struct osmo_st2_cardem_inst *ci, uint8_t p
txd = (struct cardemu_usb_msg_tx_data *) msgb_put(msg, sizeof(*txd));
printf("<= %s(%02x, %s, %d)\n", __func__, pb,
LOGSLOT(ci->slot, LOGL_DEBUG, "<= %s(pb=%02x, tx=%s, len=%d)\n", __func__, pb,
osmo_hexdump(data, data_len_in), data_len_in);
memset(txd, 0, sizeof(*txd));
@@ -174,7 +231,7 @@ int osmo_st2_cardem_request_sw_tx(struct osmo_st2_cardem_inst *ci, const uint8_t
txd = (struct cardemu_usb_msg_tx_data *) msgb_put(msg, sizeof(*txd));
printf("<= %s(%02x %02x)\n", __func__, sw[0], sw[1]);
LOGSLOT(ci->slot, LOGL_DEBUG, "<= %s(sw=%02x%02x)\n", __func__, sw[0], sw[1]);
memset(txd, 0, sizeof(*txd));
txd->data_len = 2;
@@ -194,7 +251,7 @@ int osmo_st2_cardem_request_set_atr(struct osmo_st2_cardem_inst *ci, const uint8
satr = (struct cardemu_usb_msg_set_atr *) msgb_put(msg, sizeof(*satr));
printf("<= %s(%s)\n", __func__, osmo_hexdump(atr, atr_len));
LOGSLOT(ci->slot, LOGL_NOTICE, "<= %s(%s)\n", __func__, osmo_hexdump(atr, atr_len));
memset(satr, 0, sizeof(*satr));
satr->atr_len = atr_len;
@@ -211,7 +268,7 @@ int osmo_st2_cardem_request_config(struct osmo_st2_cardem_inst *ci, uint32_t fea
cfg = (struct cardemu_usb_msg_config *) msgb_put(msg, sizeof(*cfg));
printf("<= %s(%08x)\n", __func__, features);
LOGSLOT(ci->slot, LOGL_NOTICE, "<= %s(features=%08x)\n", __func__, features);
memset(cfg, 0, sizeof(*cfg));
cfg->features = features;
@@ -228,6 +285,9 @@ static int _modem_reset(struct osmo_st2_slot *slot, uint8_t asserted, uint16_t p
struct msgb *msg = st_msgb_alloc();
struct st_modem_reset *sr ;
LOGSLOT(slot, LOGL_NOTICE, "<= %s(asserted=%u, pulse_ms=%u)\n", __func__,
asserted, pulse_ms);
sr = (struct st_modem_reset *) msgb_put(msg, sizeof(*sr));
sr->asserted = asserted;
sr->pulse_duration_msec = pulse_ms;
@@ -258,6 +318,8 @@ static int _modem_sim_select(struct osmo_st2_slot *slot, uint8_t remote_sim)
struct msgb *msg = st_msgb_alloc();
struct st_modem_sim_select *ss;
LOGSLOT(slot, LOGL_NOTICE, "<= %s(remote_sim=%u)\n", __func__, remote_sim);
ss = (struct st_modem_sim_select *) msgb_put(msg, sizeof(*ss));
ss->remote_sim = remote_sim;

View File

@@ -32,5 +32,6 @@ const struct dev_id osmo_st2_compatible_dev_ids[] = {
{ USB_VENDOR_OPENMOKO, USB_PRODUCT_OWHW_SAM3 },
{ USB_VENDOR_OPENMOKO, USB_PRODUCT_QMOD_SAM3 },
{ USB_VENDOR_OPENMOKO, USB_PRODUCT_SIMTRACE2 },
{ USB_VENDOR_OPENMOKO, USB_PRODUCT_OCTSIMTEST },
{ 0, 0 }
};

View File

@@ -5,12 +5,12 @@ AM_LDFLAGS=$(COVERAGE_LDFLAGS)
LDADD= $(top_builddir)/lib/libosmo-simtrace2.la \
$(LIBOSMOCORE_LIBS) $(LIBOSMOSIM_LIBS) $(LIBOSMOUSB_LIBS) $(LIBUSB_LIBS)
bin_PROGRAMS = simtrace2-remsim simtrace2-remsim-usb2udp simtrace2-list simtrace2-sniff
bin_PROGRAMS = simtrace2-cardem-pcsc simtrace2-list simtrace2-sniff simtrace2-tool
simtrace2_remsim_SOURCES = simtrace2-remsim.c
simtrace2_remsim_usb2udp_SOURCES = usb2udp.c
simtrace2_cardem_pcsc_SOURCES = simtrace2-cardem-pcsc.c
simtrace2_list_SOURCES = simtrace2_usb.c
simtrace2_sniff_SOURCES = simtrace2-sniff.c
simtrace2_tool_SOURCES = simtrace2-tool.c

View File

@@ -1,7 +1,7 @@
/* simtrace2-remsim - main program for the host PC to provide a remote SIM
/* simtrace2-cardem-pcsc - main program for the host PC to provide a remote SIM
* using the SIMtrace 2 firmware in card emulation mode
*
* (C) 2016-2017 by Harald Welte <hwelte@hmw-consulting.de>
* (C) 2016-2021 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
@@ -47,28 +47,13 @@
#include <osmocom/core/utils.h>
#include <osmocom/core/socket.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/select.h>
#include <osmocom/core/logging.h>
#include <osmocom/core/application.h>
#include <osmocom/sim/class_tables.h>
#include <osmocom/sim/sim.h>
/*
reasonable ATR offering all protocols and voltages
smartphones might not care, but other readers do
TS = 0x3B Direct Convention
T0 = 0x80 Y(1): b1000, K: 0 (historical bytes)
TD(1) = 0x80 Y(i+1) = b1000, Protocol T=0
----
TD(2) = 0x81 Y(i+1) = b1000, Protocol T=1
----
TD(3) = 0x1F Y(i+1) = b0001, Protocol T=15
----
TA(4) = 0xC7 Clock stop: no preference - Class accepted by the card: (3G) A 5V B 3V C 1.8V
----
Historical bytes
TCK = 0x59 correct checksum
*/
static uint8_t real_atr[] = { 0x3B, 0x80, 0x80, 0x81 , 0x1F, 0xC7, 0x59};
#define LOGCI(ci, lvl, fmt, args ...) printf(fmt, ## args)
static void atr_update_csum(uint8_t *atr, unsigned int atr_len)
{
@@ -81,6 +66,37 @@ static void atr_update_csum(uint8_t *atr, unsigned int atr_len)
atr[atr_len-1] = csum;
}
static void cemu_flags2str(char *out, unsigned int out_len, uint32_t flags)
{
snprintf(out, out_len, "%s%s%s%s%s",
flags & CEMU_STATUS_F_RESET_ACTIVE ? "RESET " : "",
flags & CEMU_STATUS_F_VCC_PRESENT ? "VCC " : "",
flags & CEMU_STATUS_F_CLK_ACTIVE ? "CLK " : "",
flags & CEMU_STATUS_F_CARD_INSERT ? "CARD_PRES " : "",
flags & CEMU_STATUS_F_RCEMU_ACTIVE ? "RCEMU " : "");
}
static uint32_t last_flags = 0;
static void update_flags(struct osmo_st2_cardem_inst *ci, uint32_t flags)
{
struct osim_card_hdl *card = ci->chan->card;
if ((flags & CEMU_STATUS_F_VCC_PRESENT) && (flags & CEMU_STATUS_F_CLK_ACTIVE) &&
!(flags & CEMU_STATUS_F_RESET_ACTIVE)) {
if (last_flags & CEMU_STATUS_F_RESET_ACTIVE) {
/* a reset has just ended, forward it to the real card */
bool cold_reset = true;
if (last_flags & CEMU_STATUS_F_VCC_PRESENT)
cold_reset = false;
LOGCI(ci, LOGL_NOTICE, "%s Resetting card in reader...\n",
cold_reset ? "Cold" : "Warm");
osim_card_reset(card, cold_reset);
}
}
last_flags = flags;
}
/***********************************************************************
* Incoming Messages
***********************************************************************/
@@ -88,12 +104,15 @@ static void atr_update_csum(uint8_t *atr, unsigned int atr_len)
/*! \brief Process a STATUS message from the SIMtrace2 */
static int process_do_status(struct osmo_st2_cardem_inst *ci, uint8_t *buf, int len)
{
struct cardemu_usb_msg_status *status;
status = (struct cardemu_usb_msg_status *) buf;
struct cardemu_usb_msg_status *status = (struct cardemu_usb_msg_status *) buf;
char fbuf[80];
printf("=> STATUS: flags=0x%x, F=%u, D=%u, WI=%u WT=%u\n",
status->flags, status->f, status->d, status->wi,
status->wt);
cemu_flags2str(fbuf, sizeof(fbuf), status->flags);
printf("=> STATUS: flags=0x%x, fi=%u, di=%u, wi=%u wtime=%u (%s)\n",
status->flags, status->fi, status->di, status->wi,
status->waiting_time, fbuf);
update_flags(ci, status->flags);
return 0;
}
@@ -178,6 +197,9 @@ static int process_usb_msg(struct osmo_st2_cardem_inst *ci, uint8_t *buf, int le
case SIMTRACE_MSGT_DO_CEMU_RX_DATA:
rc = process_do_rx_da(ci, buf, len);
break;
case SIMTRACE_MSGT_BD_CEMU_CONFIG:
/* firmware confirms configuration change; ignore */
break;
default:
printf("unknown simtrace msg type 0x%02x\n", sh->msg_type);
rc = -1;
@@ -187,20 +209,161 @@ static int process_usb_msg(struct osmo_st2_cardem_inst *ci, uint8_t *buf, int le
return rc;
}
/*! \brief Process a STATUS message on IRQ endpoint from the SIMtrace2 */
static int process_irq_status(struct osmo_st2_cardem_inst *ci, const uint8_t *buf, int len)
{
const struct cardemu_usb_msg_status *status = (struct cardemu_usb_msg_status *) buf;
char fbuf[80];
cemu_flags2str(fbuf, sizeof(fbuf), status->flags);
LOGCI(ci, LOGL_INFO, "SIMtrace IRQ STATUS: flags=0x%x, fi=%u, di=%u, wi=%u wtime=%u (%s)\n",
status->flags, status->fi, status->di, status->wi,
status->waiting_time, fbuf);
update_flags(ci, status->flags);
return 0;
}
static int process_usb_msg_irq(struct osmo_st2_cardem_inst *ci, const uint8_t *buf, unsigned int len)
{
struct simtrace_msg_hdr *sh = (struct simtrace_msg_hdr *)buf;
int rc;
LOGCI(ci, LOGL_INFO, "SIMtrace IRQ %s\n", osmo_hexdump(buf, len));
buf += sizeof(*sh);
switch (sh->msg_type) {
case SIMTRACE_MSGT_BD_CEMU_STATUS:
rc = process_irq_status(ci, buf, len);
break;
default:
LOGCI(ci, LOGL_ERROR, "unknown simtrace msg type 0x%02x\n", sh->msg_type);
rc = -1;
break;
}
return rc;
}
static void usb_in_xfer_cb(struct libusb_transfer *xfer)
{
struct osmo_st2_cardem_inst *ci = xfer->user_data;
int rc;
switch (xfer->status) {
case LIBUSB_TRANSFER_COMPLETED:
/* hand the message up the stack */
process_usb_msg(ci, xfer->buffer, xfer->actual_length);
break;
case LIBUSB_TRANSFER_NO_DEVICE:
LOGCI(ci, LOGL_FATAL, "USB device disappeared\n");
exit(1);
break;
default:
LOGCI(ci, LOGL_FATAL, "USB IN transfer failed, status=%u\n", xfer->status);
exit(1);
break;
}
/* re-submit the IN transfer */
rc = libusb_submit_transfer(xfer);
OSMO_ASSERT(rc == 0);
}
static void allocate_and_submit_in(struct osmo_st2_cardem_inst *ci)
{
struct osmo_st2_transport *transp = ci->slot->transp;
struct libusb_transfer *xfer;
int rc;
xfer = libusb_alloc_transfer(0);
OSMO_ASSERT(xfer);
xfer->dev_handle = transp->usb_devh;
xfer->flags = 0;
xfer->type = LIBUSB_TRANSFER_TYPE_BULK;
xfer->endpoint = transp->usb_ep.in;
xfer->timeout = 0;
xfer->user_data = ci;
xfer->length = 16*256;
xfer->buffer = libusb_dev_mem_alloc(xfer->dev_handle, xfer->length);
OSMO_ASSERT(xfer->buffer);
xfer->callback = usb_in_xfer_cb;
/* submit the IN transfer */
rc = libusb_submit_transfer(xfer);
OSMO_ASSERT(rc == 0);
}
static void usb_irq_xfer_cb(struct libusb_transfer *xfer)
{
struct osmo_st2_cardem_inst *ci = xfer->user_data;
int rc;
switch (xfer->status) {
case LIBUSB_TRANSFER_COMPLETED:
process_usb_msg_irq(ci, xfer->buffer, xfer->actual_length);
break;
case LIBUSB_TRANSFER_NO_DEVICE:
LOGCI(ci, LOGL_FATAL, "USB device disappeared\n");
exit(1);
break;
default:
LOGCI(ci, LOGL_FATAL, "USB IN transfer failed, status=%u\n", xfer->status);
exit(1);
break;
}
/* re-submit the IN transfer */
rc = libusb_submit_transfer(xfer);
OSMO_ASSERT(rc == 0);
}
static void allocate_and_submit_irq(struct osmo_st2_cardem_inst *ci)
{
struct osmo_st2_transport *transp = ci->slot->transp;
struct libusb_transfer *xfer;
int rc;
xfer = libusb_alloc_transfer(0);
OSMO_ASSERT(xfer);
xfer->dev_handle = transp->usb_devh;
xfer->flags = 0;
xfer->type = LIBUSB_TRANSFER_TYPE_INTERRUPT;
xfer->endpoint = transp->usb_ep.irq_in;
xfer->timeout = 0;
xfer->user_data = ci;
xfer->length = 64;
xfer->buffer = libusb_dev_mem_alloc(xfer->dev_handle, xfer->length);
OSMO_ASSERT(xfer->buffer);
xfer->callback = usb_irq_xfer_cb;
/* submit the IN transfer */
rc = libusb_submit_transfer(xfer);
OSMO_ASSERT(rc == 0);
}
static void print_welcome(void)
{
printf("simtrace2-remsim - Remote SIM card forwarding\n"
"(C) 2010-2017, Harald Welte <laforge@gnumonks.org>\n"
printf("simtrace2-cardem-pcsc - Using PC/SC reader as SIM\n"
"(C) 2010-2020, 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)
{
printf( "\t-r\t--remote-udp-host HOST\n"
"\t-p\t--remote-udp-port PORT\n"
"\t-h\t--help\n"
printf( "\t-h\t--help\n"
"\t-i\t--gsmtap-ip\tA.B.C.D\n"
"\t-a\t--skip-atr\n"
"\t-t\t--set-atr\tATR-STRING in HEX\n"
"\t-k\t--keep-running\n"
"\t-n\t--pcsc-reader-num\n"
"\t-V\t--usb-vendor\tVENDOR_ID\n"
@@ -215,10 +378,9 @@ static void print_help(void)
}
static const struct option opts[] = {
{ "remote-udp-host", 1, 0, 'r' },
{ "remote-udp-port", 1, 0, 'p' },
{ "gsmtap-ip", 1, 0, 'i' },
{ "skip-atr", 0, 0, 'a' },
{ "set-atr", 1, 0, 't' },
{ "help", 0, 0, 'h' },
{ "keep-running", 0, 0, 'k' },
{ "pcsc-reader-num", 1, 0, 'n' },
@@ -234,40 +396,9 @@ static const struct option opts[] = {
static void run_mainloop(struct osmo_st2_cardem_inst *ci)
{
struct osmo_st2_transport *transp = ci->slot->transp;
unsigned int msg_count, byte_count = 0;
uint8_t buf[16*265];
int xfer_len;
int rc;
printf("Entering main loop\n");
while (1) {
/* read data from SIMtrace2 device (local or via USB) */
if (transp->udp_fd < 0) {
rc = libusb_bulk_transfer(transp->usb_devh, transp->usb_ep.in,
buf, sizeof(buf), &xfer_len, 100);
if (rc < 0 && rc != LIBUSB_ERROR_TIMEOUT &&
rc != LIBUSB_ERROR_INTERRUPTED &&
rc != LIBUSB_ERROR_IO) {
fprintf(stderr, "BULK IN transfer error; rc=%d\n", rc);
return;
}
} else {
rc = read(transp->udp_fd, buf, sizeof(buf));
if (rc <= 0) {
fprintf(stderr, "shor read from UDP\n");
return;
}
xfer_len = rc;
}
/* dispatch any incoming data */
if (xfer_len > 0) {
printf("URB: %s\n", osmo_hexdump(buf, xfer_len));
process_usb_msg(ci, buf, xfer_len);
msg_count++;
byte_count += xfer_len;
}
osmo_select_main(0);
}
}
@@ -296,6 +427,8 @@ static void signal_handler(int signal)
}
}
static struct log_info log_info = {};
int main(int argc, char **argv)
{
struct osmo_st2_transport *transp = ci->slot->transp;
@@ -303,31 +436,34 @@ int main(int argc, char **argv)
int rc;
int c, ret = 1;
int skip_atr = 0;
char *atr = NULL;
uint8_t override_atr[OSIM_MAX_ATR_LEN];
int override_atr_len = 0;
int keep_running = 0;
int remote_udp_port = 52342;
int if_num = 0, vendor_id = -1, product_id = -1;
int config_id = -1, altsetting = 0, addr = -1;
int reader_num = 0;
char *remote_udp_host = NULL;
char *path = NULL;
struct osim_reader_hdl *reader;
struct osim_card_hdl *card;
print_welcome();
rc = osmo_libusb_init(NULL);
if (rc < 0) {
fprintf(stderr, "libusb initialization failed\n");
return rc;
}
osmo_init_logging2(NULL, &log_info);
while (1) {
int option_index = 0;
c = getopt_long(argc, argv, "r:p:hi:V:P:C:I:S:A:H:akn:", opts, &option_index);
c = getopt_long(argc, argv, "hi:V:P:C:I:S:A:H:akn:t:", opts, &option_index);
if (c == -1)
break;
switch (c) {
case 'r':
remote_udp_host = optarg;
break;
case 'p':
remote_udp_port = atoi(optarg);
break;
case 'h':
print_help();
exit(0);
@@ -338,6 +474,9 @@ int main(int argc, char **argv)
case 'a':
skip_atr = 1;
break;
case 't':
atr = optarg;
break;
case 'k':
keep_running = 1;
break;
@@ -368,29 +507,26 @@ int main(int argc, char **argv)
}
}
if (!remote_udp_host && (vendor_id < 0 || product_id < 0)) {
if (atr) {
override_atr_len = osmo_hexparse(atr, override_atr, sizeof(override_atr));
if (override_atr_len < 2) {
fprintf(stderr, "Invalid ATR - please omit a leading 0x and only use valid hex "
"digits and whitespace. ATRs need to be between 2 and 33 bytes long.\n");
goto do_exit;
}
}
if (vendor_id < 0 || product_id < 0) {
fprintf(stderr, "You have to specify the vendor and product ID\n");
goto do_exit;
}
transp->udp_fd = -1;
ci->card_prof = &osim_uicc_sim_cic_profile;
if (!remote_udp_host) {
rc = libusb_init(NULL);
if (rc < 0) {
fprintf(stderr, "libusb initialization failed\n");
goto do_exit;
}
} else {
transp->udp_fd = osmo_sock_init(AF_INET, SOCK_DGRAM, IPPROTO_UDP,
remote_udp_host, remote_udp_port+if_num,
OSMO_SOCK_F_CONNECT);
if (transp->udp_fd < 0) {
fprintf(stderr, "error binding UDP port\n");
goto do_exit;
}
rc = libusb_init(NULL);
if (rc < 0) {
fprintf(stderr, "libusb initialization failed\n");
goto do_exit;
}
rc = osmo_st2_gsmtap_init(gsmtap_host);
@@ -420,36 +556,43 @@ int main(int argc, char **argv)
signal(SIGINT, &signal_handler);
do {
if (transp->udp_fd < 0) {
struct usb_interface_match _ifm, *ifm = &_ifm;
ifm->vendor = vendor_id;
ifm->product = product_id;
ifm->configuration = config_id;
ifm->interface = if_num;
ifm->altsetting = altsetting;
ifm->addr = addr;
if (path)
osmo_strlcpy(ifm->path, path, sizeof(ifm->path));
transp->usb_devh = osmo_libusb_open_claim_interface(NULL, NULL, ifm);
if (!transp->usb_devh) {
fprintf(stderr, "can't open USB device\n");
goto close_exit;
}
rc = libusb_claim_interface(transp->usb_devh, if_num);
if (rc < 0) {
fprintf(stderr, "can't claim interface %d; rc=%d\n", if_num, rc);
goto close_exit;
}
rc = osmo_libusb_get_ep_addrs(transp->usb_devh, if_num, &transp->usb_ep.out,
&transp->usb_ep.in, &transp->usb_ep.irq_in);
if (rc < 0) {
fprintf(stderr, "can't obtain EP addrs; rc=%d\n", rc);
goto close_exit;
}
struct usb_interface_match _ifm, *ifm = &_ifm;
ifm->vendor = vendor_id;
ifm->product = product_id;
ifm->configuration = config_id;
ifm->interface = if_num;
ifm->altsetting = altsetting;
ifm->addr = addr;
if (path)
osmo_strlcpy(ifm->path, path, sizeof(ifm->path));
transp->udp_fd = -1;
transp->usb_async = true;
transp->usb_devh = osmo_libusb_open_claim_interface(NULL, NULL, ifm);
if (!transp->usb_devh) {
fprintf(stderr, "can't open USB device\n");
goto close;
}
rc = libusb_claim_interface(transp->usb_devh, if_num);
if (rc < 0) {
fprintf(stderr, "can't claim interface %d; rc=%d\n", if_num, rc);
goto close;
}
rc = osmo_libusb_get_ep_addrs(transp->usb_devh, if_num, &transp->usb_ep.out,
&transp->usb_ep.in, &transp->usb_ep.irq_in);
if (rc < 0) {
fprintf(stderr, "can't obtain EP addrs; rc=%d\n", rc);
goto close;
}
allocate_and_submit_irq(ci);
for (int i = 0; i < 4; i++)
allocate_and_submit_in(ci);
/* request firmware to generate STATUS on IRQ endpoint */
osmo_st2_cardem_request_config(ci, CEMU_FEAT_F_STATUS_IRQ);
/* simulate card-insert to modem (owhw, not qmod) */
osmo_st2_cardem_request_card_insert(ci, true);
@@ -457,8 +600,15 @@ int main(int argc, char **argv)
osmo_st2_modem_sim_select_remote(ci->slot);
if (!skip_atr) {
atr_update_csum(real_atr, sizeof(real_atr));
osmo_st2_cardem_request_set_atr(ci, real_atr, sizeof(real_atr));
/* set the ATR */
if (override_atr_len) {
/* user has specified an override-ATR */
atr_update_csum(override_atr, override_atr_len);
osmo_st2_cardem_request_set_atr(ci, override_atr, override_atr_len);
} else {
/* use the real ATR of the card */
osmo_st2_cardem_request_set_atr(ci, card->atr, card->atr_len);
}
}
/* select remote (forwarded) SIM */
@@ -467,17 +617,22 @@ int main(int argc, char **argv)
run_mainloop(ci);
ret = 0;
if (transp->udp_fd < 0)
libusb_release_interface(transp->usb_devh, 0);
close_exit:
if (transp->usb_devh)
libusb_release_interface(transp->usb_devh, 0);
close:
if (transp->usb_devh) {
libusb_close(transp->usb_devh);
transp->usb_devh = NULL;
}
if (keep_running)
sleep(1);
} while (keep_running);
if (transp->udp_fd < 0)
libusb_exit(NULL);
close_exit:
if (transp->usb_devh)
libusb_close(transp->usb_devh);
libusb_exit(NULL);
do_exit:
return ret;
}

338
host/src/simtrace2-tool.c Normal file
View File

@@ -0,0 +1,338 @@
/* simtrace2-tool - main program for the host PC to provide a remote SIM
* using the SIMtrace 2 firmware in card emulation mode
*
* (C) 2019 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <signal.h>
#define _GNU_SOURCE
#include <getopt.h>
#include <sys/types.h>
#include <libusb.h>
#include <osmocom/usb/libusb.h>
#include <osmocom/simtrace2/simtrace2_api.h>
#include <osmocom/simtrace2/simtrace_prot.h>
#include <osmocom/simtrace2/gsmtap.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/msgb.h>
/***********************************************************************
* Incoming Messages
***********************************************************************/
static void print_welcome(void)
{
printf("simtrace2-tool\n"
"(C) 2019 Harald Welte <laforge@gnumonks.org>\n");
}
static void print_help(void)
{
printf( "simtrace2-tool [OPTIONS] COMMAND\n\n");
printf( "Options:\n"
"\t-h\t--help\n"
"\t-V\t--usb-vendor\tVENDOR_ID\n"
"\t-P\t--usb-product\tPRODUCT_ID\n"
"\t-C\t--usb-config\tCONFIG_ID\n"
"\t-I\t--usb-interface\tINTERFACE_ID\n"
"\t-S\t--usb-altsetting ALTSETTING_ID\n"
"\t-A\t--usb-address\tADDRESS\n"
"\t-H\t--usb-path\tPATH\n"
"\n"
);
printf( "Commands:\n"
"\tmodem reset (enable|disable|cycle)\n"
"\tmodem sim-switch (local|remote)\n"
"\n");
}
static const struct option opts[] = {
{ "help", 0, 0, 'h' },
{ "usb-vendor", 1, 0, 'V' },
{ "usb-product", 1, 0, 'P' },
{ "usb-config", 1, 0, 'C' },
{ "usb-interface", 1, 0, 'I' },
{ "usb-altsetting", 1, 0, 'S' },
{ "usb-address", 1, 0, 'A' },
{ "usb-path", 1, 0, 'H' },
{ NULL, 0, 0, 0 }
};
static void run_mainloop(struct osmo_st2_cardem_inst *ci)
{
struct osmo_st2_transport *transp = ci->slot->transp;
uint8_t buf[16*265];
int xfer_len;
int rc;
while (1) {
/* read data from SIMtrace2 device */
rc = libusb_bulk_transfer(transp->usb_devh, transp->usb_ep.in,
buf, sizeof(buf), &xfer_len, 100);
if (rc < 0 && rc != LIBUSB_ERROR_TIMEOUT &&
rc != LIBUSB_ERROR_INTERRUPTED &&
rc != LIBUSB_ERROR_IO) {
fprintf(stderr, "BULK IN transfer error; rc=%d\n", rc);
return;
}
/* break the loop if no new messages arrive within 100ms */
if (rc == LIBUSB_ERROR_TIMEOUT)
return;
}
}
static struct osmo_st2_transport _transp;
static struct osmo_st2_slot _slot = {
.transp = &_transp,
.slot_nr = 0,
};
struct osmo_st2_cardem_inst _ci = {
.slot = &_slot,
};
struct osmo_st2_cardem_inst *ci = &_ci;
/* perform a modem reset */
static int do_modem_reset(int argc, char **argv)
{
char *command;
if (argc < 1)
command = "cycle";
else {
command = argv[0];
argc--;
argv++;
}
if (!strcmp(command, "enable")) {
printf("Activating Modem RESET\n");
return osmo_st2_modem_reset_active(ci->slot);
} else if (!strcmp(command, "disable")) {
printf("Deactivating Modem RESET\n");
return osmo_st2_modem_reset_inactive(ci->slot);
} else if (!strcmp(command, "cycle")) {
printf("Pulsing Modem RESET (1s)\n");
return osmo_st2_modem_reset_pulse(ci->slot, 1000);
} else {
fprintf(stderr, "Unsupported modem reset command: '%s'\n", command);
return -EINVAL;
}
return 0;
}
/* switch between local and remote (emulated) SIM */
static int do_modem_sim_switch(int argc, char **argv)
{
char *command;
if (argc < 1)
return -EINVAL;
command = argv[0];
argc--;
argv++;
if (!strcmp(command, "local")) {
printf("Setting SIM=LOCAL; Modem reset recommended\n");
return osmo_st2_modem_sim_select_local(ci->slot);
} else if (!strcmp(command, "remote")) {
printf("Setting SIM=REMOTE; Modem reset recommended\n");
return osmo_st2_modem_sim_select_remote(ci->slot);
} else {
fprintf(stderr, "Unsupported modem sim-switch command: '%s'\n", command);
return -EINVAL;
}
return 0;
}
static int do_subsys_modem(int argc, char **argv)
{
char *command;
int rc;
if (argc < 1)
return -EINVAL;
command = argv[0];
argc--;
argv++;
if (!strcmp(command, "reset")) {
rc = do_modem_reset(argc, argv);
} else if (!strcmp(command, "sim-switch")) {
rc = do_modem_sim_switch(argc, argv);
} else {
fprintf(stderr, "Unsupported command for subsystem modem: '%s'\n", command);
return -EINVAL;
}
return rc;
}
static int do_command(int argc, char **argv)
{
char *subsys;
int rc;
if (argc < 1)
return -EINVAL;
subsys = argv[0];
argc--;
argv++;
if (!strcmp(subsys, "modem"))
rc = do_subsys_modem(argc, argv);
else {
fprintf(stderr, "Unsupported subsystem '%s'\n", subsys);
rc = -EINVAL;
}
return rc;
}
int main(int argc, char **argv)
{
struct osmo_st2_transport *transp = ci->slot->transp;
int rc;
int c, ret = 1;
int if_num = 0, vendor_id = -1, product_id = -1;
int config_id = -1, altsetting = 0, addr = -1;
char *path = NULL;
while (1) {
int option_index = 0;
c = getopt_long(argc, argv, "hV:P:C:I:S:A:H:", opts, &option_index);
if (c == -1)
break;
switch (c) {
case 'h':
print_help();
exit(0);
break;
case 'V':
vendor_id = strtol(optarg, NULL, 16);
break;
case 'P':
product_id = strtol(optarg, NULL, 16);
break;
case 'C':
config_id = atoi(optarg);
break;
case 'I':
if_num = atoi(optarg);
break;
case 'S':
altsetting = atoi(optarg);
break;
case 'A':
addr = atoi(optarg);
break;
case 'H':
path = optarg;
break;
}
}
if ((vendor_id < 0 || product_id < 0)) {
fprintf(stderr, "You have to specify the vendor and product ID\n");
goto do_exit;
}
transp->udp_fd = -1;
rc = libusb_init(NULL);
if (rc < 0) {
fprintf(stderr, "libusb initialization failed\n");
goto do_exit;
}
print_welcome();
do {
if (transp->udp_fd < 0) {
struct usb_interface_match _ifm, *ifm = &_ifm;
ifm->vendor = vendor_id;
ifm->product = product_id;
ifm->configuration = config_id;
ifm->interface = if_num;
ifm->altsetting = altsetting;
ifm->addr = addr;
if (path)
osmo_strlcpy(ifm->path, path, sizeof(ifm->path));
transp->usb_devh = osmo_libusb_open_claim_interface(NULL, NULL, ifm);
if (!transp->usb_devh) {
fprintf(stderr, "can't open USB device\n");
goto close_exit;
}
rc = libusb_claim_interface(transp->usb_devh, if_num);
if (rc < 0) {
fprintf(stderr, "can't claim interface %d; rc=%d\n", if_num, rc);
goto close_exit;
}
rc = osmo_libusb_get_ep_addrs(transp->usb_devh, if_num, &transp->usb_ep.out,
&transp->usb_ep.in, &transp->usb_ep.irq_in);
if (rc < 0) {
fprintf(stderr, "can't obtain EP addrs; rc=%d\n", rc);
goto close_exit;
}
}
if (argc - optind <= 0) {
fprintf(stderr, "You have to specify a command to execute\n");
exit(1);
}
rc = do_command(argc-optind, argv+optind);
switch (rc) {
case 0:
break;
case -EINVAL:
fprintf(stderr, "Error: Invalid command/syntax\n");
exit(1);
break;
default:
fprintf(stderr, "Error executing command: %d\n", rc);
exit(1);
break;
}
run_mainloop(ci);
ret = 0;
libusb_release_interface(transp->usb_devh, 0);
close_exit:
if (transp->usb_devh)
libusb_close(transp->usb_devh);
} while (0);
libusb_exit(NULL);
do_exit:
return ret;
}

View File

@@ -25,13 +25,7 @@
#include <osmocom/usb/libusb.h>
#include <osmocom/simtrace2/simtrace_usb.h>
static const struct dev_id compatible_dev_ids[] = {
{ USB_VENDOR_OPENMOKO, USB_PRODUCT_OWHW_SAM3 },
{ USB_VENDOR_OPENMOKO, USB_PRODUCT_QMOD_SAM3 },
{ USB_VENDOR_OPENMOKO, USB_PRODUCT_SIMTRACE2 },
{ 0, 0 }
};
#include <osmocom/simtrace2/usb_util.h>
static int find_devices(void)
{
@@ -39,7 +33,7 @@ static int find_devices(void)
int rc, i, num_interfaces;
/* scan for USB devices matching SIMtrace USB ID with proprietary class */
rc = osmo_libusb_find_matching_interfaces(NULL, compatible_dev_ids,
rc = osmo_libusb_find_matching_interfaces(NULL, osmo_st2_compatible_dev_ids,
USB_CLASS_PROPRIETARY, -1, -1, ifm, ARRAY_SIZE(ifm));
printf("USB matches: %d\n", rc);
if (rc < 0)

View File

@@ -1,285 +0,0 @@
/* simtrace - main program for the host PC
*
* (C) 2010-2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <time.h>
#define _GNU_SOURCE
#include <getopt.h>
#include <poll.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <libusb.h>
#include <osmocom/usb/libusb.h>
#include <osmocom/simtrace2/simtrace_usb.h>
#include <osmocom/simtrace2/simtrace_prot.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/socket.h>
#include <osmocom/core/select.h>
struct libusb_device_handle *g_devh;
static struct sockaddr_in g_sa_remote;
static struct osmo_fd g_udp_ofd;
static void print_welcome(void)
{
printf("usb2udp - UDP/IP forwarding of SIMtrace card emulation\n"
"(C) 2016 by Harald Welte <laforge@gnumonks.org>\n\n");
}
static void print_help(void)
{
printf( "\t-h\t--help\n"
"\t-i\t--interface <0-255>\n"
"\n"
);
}
struct ep_buf {
uint8_t ep;
uint8_t buf[1024];
struct libusb_transfer *xfer;
};
static struct ep_buf g_buf_in;
static struct ep_buf g_buf_out;
static void usb_in_xfer_cb(struct libusb_transfer *xfer)
{
int rc;
printf("xfer_cb(ep=%02x): status=%d, flags=0x%x, type=%u, len=%u, act_len=%u\n",
xfer->endpoint, xfer->status, xfer->flags, xfer->type, xfer->length, xfer->actual_length);
switch (xfer->status) {
case LIBUSB_TRANSFER_COMPLETED:
if (xfer->endpoint == g_buf_in.ep) {
/* process the data */
printf("read %d bytes from SIMTRACE, forwarding to UDP\n", xfer->actual_length);
rc = sendto(g_udp_ofd.fd, xfer->buffer, xfer->actual_length, 0, (struct sockaddr *)&g_sa_remote, sizeof(g_sa_remote));
if (rc <= 0) {
fprintf(stderr, "error writing to UDP\n");
}
/* and re-submit the URB */
libusb_submit_transfer(xfer);
} else if (xfer->endpoint == g_buf_out.ep) {
/* re-enable reading from the UDP side */
g_udp_ofd.when |= BSC_FD_READ;
}
break;
default:
fprintf(stderr, "xfer_cb(ERROR '%s')\n", osmo_hexdump_nospc(xfer->buffer, xfer->actual_length));
break;
}
}
static void init_ep_buf(struct ep_buf *epb)
{
if (!epb->xfer)
epb->xfer = libusb_alloc_transfer(0);
epb->xfer->flags = 0;
libusb_fill_bulk_transfer(epb->xfer, g_devh, epb->ep, epb->buf, sizeof(epb->buf), usb_in_xfer_cb, NULL, 0);
}
/***********************************************************************
* libosmocore main loop integration of libusb async I/O
***********************************************************************/
static int g_libusb_pending = 0;
static int ofd_libusb_cb(struct osmo_fd *ofd, unsigned int what)
{
/* FIXME */
g_libusb_pending = 1;
return 0;
}
/* call-back when libusb adds a FD */
static void libusb_fd_added_cb(int fd, short events, void *user_data)
{
struct osmo_fd *ofd = talloc_zero(NULL, struct osmo_fd);
printf("%s(%u, %x)\n", __func__, fd, events);
ofd->fd = fd;
ofd->cb = &ofd_libusb_cb;
if (events & POLLIN)
ofd->when |= BSC_FD_READ;
if (events & POLLOUT)
ofd->when |= BSC_FD_WRITE;
osmo_fd_register(ofd);
}
/* call-back when libusb removes a FD */
static void libusb_fd_removed_cb(int fd, void *user_data)
{
printf("%s(%u)\n", __func__, fd);
#if 0
struct osmo_fd *ofd;
/* FIXME: This needs new export in libosmocore! */
ofd = osmo_fd_get_by_fd(fd);
if (ofd) {
osmo_fd_unregister(ofd);
talloc_free(ofd);
}
#endif
}
/* call-back when the UDP socket is readable */
static int ofd_udp_cb(struct osmo_fd *ofd, unsigned int what)
{
int rc;
socklen_t addrlen = sizeof(g_sa_remote);
rc = recvfrom(ofd->fd, g_buf_out.buf, sizeof(g_buf_out.buf), 0,
(struct sockaddr *)&g_sa_remote, &addrlen);
if (rc <= 0) {
fprintf(stderr, "error reading from UDP\n");
return 0;
}
printf("read %d bytes from UDP, forwarding to SIMTRACE\n", rc);
g_buf_out.xfer->length = rc;
/* disable further READ interest for the UDP socket */
ofd->when &= ~BSC_FD_READ;
/* submit the URB on the OUT end point */
libusb_submit_transfer(g_buf_out.xfer);
return 0;
}
static void run_mainloop(void)
{
int rc;
printf("Entering main loop\n");
while (1) {
osmo_select_main(0);
if (g_libusb_pending) {
struct timeval tv;
memset(&tv, 0, sizeof(tv));
rc = libusb_handle_events_timeout_completed(NULL, &tv, NULL);
if (rc != 0) {
fprintf(stderr, "handle_events_timeout_completed == %d\n", rc);
break;
}
}
}
}
int main(int argc, char **argv)
{
int rc;
int c, ret = 1;
int local_udp_port = 52342;
unsigned int if_num = 0;
print_welcome();
while (1) {
int option_index = 0;
static const struct option opts[] = {
{ "udp-port", 1, 0, 'u' },
{ "interface", 1, 0, 'I' },
{ "help", 0, 0, 'h' },
{ NULL, 0, 0, 0 }
};
c = getopt_long(argc, argv, "u:I:h", opts, &option_index);
if (c == -1)
break;
switch (c) {
case 'u':
local_udp_port = atoi(optarg);
break;
case 'I':
if_num = atoi(optarg);
break;
case 'h':
print_help();
exit(0);
break;
}
}
rc = libusb_init(NULL);
if (rc < 0) {
fprintf(stderr, "libusb initialization failed\n");
goto close_exit;
}
libusb_set_pollfd_notifiers(NULL, &libusb_fd_added_cb, &libusb_fd_removed_cb, NULL);
g_devh = libusb_open_device_with_vid_pid(NULL, USB_VENDOR_OPENMOKO, USB_PRODUCT_OWHW_SAM3);
if (!g_devh) {
fprintf(stderr, "can't open USB device\n");
goto close_exit;
}
rc = libusb_claim_interface(g_devh, if_num);
if (rc < 0) {
fprintf(stderr, "can't claim interface %u; rc=%d\n", if_num, rc);
goto close_exit;
}
/* open UDP socket, register with select handling and mark it
* readable */
g_udp_ofd.cb = ofd_udp_cb;
osmo_sock_init_ofd(&g_udp_ofd, AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, local_udp_port + if_num, OSMO_SOCK_F_BIND);
rc = osmo_libusb_get_ep_addrs(g_devh, if_num, &g_buf_out.ep, &g_buf_in.ep, NULL);
if (rc < 0) {
fprintf(stderr, "couldn't find enpdoint addresses; rc=%d\n", rc);
goto close_exit;
}
/* initialize USB buffers / transfers */
init_ep_buf(&g_buf_out);
init_ep_buf(&g_buf_in);
/* submit the first transfer for the IN endpoint */
libusb_submit_transfer(g_buf_in.xfer);
run_mainloop();
ret = 0;
libusb_release_interface(g_devh, 0);
close_exit:
if (g_devh)
libusb_close(g_devh);
libusb_exit(NULL);
return ret;
}