135 Commits

Author SHA1 Message Date
Harald Welte
774330d413 WIP: introduce support for new ngff_cardem board
This adds support for the new ngff_cardem board, a board that
basically combines a ngff breakout board with a built-in SIMtrace2.

The firmware support added by this ptach is currently untested,
and serves as a basis for testing the ngff_cardem prototypes.

Change-Id: I9649c853271c22d5403cdf3a7ec9029c9cecfa32
2021-07-07 11:34:41 +02:00
Harald Welte
9d0d20c253 contrib/flash.py: Add OCTSIMTEST support
Change-Id: Id906d955f45a204ac0b00f56d8f5149c64c62f32
2021-07-07 11:34:26 +02:00
Harald Welte
f7b7f41d2f 99-simtrace2.rules: Add OCTSIMTEST
Change-Id: I226ee21e0937f851428578578f81075fa703dd54
2021-07-07 11:34:26 +02:00
Harald Welte
07f94342be 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-07-01 23:28:52 +02:00
Harald Welte
d0c420055d board_gpio.gnumeric: Add ngff-cardem pin-out
Change-Id: Ie1a7be85200e331232ad52aa0468c748ff053142
2021-07-01 23:28:52 +02:00
Harald Welte
3ef40d1ca6 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-30 08:17:58 +00:00
Harald Welte
dcfea28a4f 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-30 08:17:58 +00:00
Eric Wild
264f615b65 cardemu: support 1v8 for the tester
The tester has shifters, while the original simtrace relies upon the
reader restarting the powerup attempt with > 1v8 after not respondig due
to a lack of shifters and therefore 1v8 support.

Change-Id: I520aa26c6e0fb34568a4f632943efa59a0da831c
2021-06-26 02:54:20 +02:00
Eric Wild
017e10e9ef cardem: free the buf
This leak was probably hard to notice since config commands are usually
rarely sent.

Change-Id: I21411ef78a32a5258a7008272774cdb83119b413
2021-06-21 23:46:38 +02:00
Eric Wild
f0653533cc contrib: add a basic simtrace lua dissector for wireshark
See Help->About Wireshark->Folders tab,the usual place this should go is
~/.local/lib/wireshark/plugins
Hot reload possible after editing using Analyze->Reload Lua Plugins

Change-Id: I360ab522dabc3a378969df36efd3b48fc4cade3c
2021-06-21 17:38:53 +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
Harald Welte
f46de7b70f simtrace2_siff: getopt_long() returns int, not char
This may be causing unwanted behavior while parsing the command
line arguments, as reported by some Raspi users.

Change-Id: I5b7db0795d16ab071e255c2c689e3b4872a933bb
Related: OS#4223
2020-03-19 09:18:31 +01:00
Harald Welte
e42492971e pio_it.c: Permit repeated calls to PIO_ConfigureIt()
The original code assumes that calls to PIO_ConfigureIt() are only
made once e.g. during board start-up.  Hoewever, we call those
at USB SetConfiguration time, when we know which particular hardware
function we are supposed to perform.   This means that after the host
has issued SetConfiguration more than a given number of times, the
code will assert() due to overflow of the static array.

Let's check if we already have allocated an array slot for a given pin
and reuse that allocated array bucket rather than allocating new ones
for the same pin.

Change-Id: I0c46d4b51eeebd58a8786d65e31e7a84e65b6a8e
Related: OS#4454
2020-03-13 15:28:40 +01:00
Harald Welte
a625ef0d9b USBD.c: Don't reset EP0 on SetConfiguration(0)
If we do this, the resulting USB code will fail on any of the
USB-IF Chapter 9 tests.  EP0 should not be reset.

Change-Id: I070faf4cb7029d3ccfa6c63f8f04aa0f02657536
2020-03-13 12:56:49 +01:00
Harald Welte
823f453d83 cosmetic: Add missing CR to LF in dispatch_received_usb_msg()
Change-Id: Ie1fc38ed4412b806e37688e0f9719573df06fd9f
2020-03-03 21:09:50 +01:00
Harald Welte
13cb311c06 extend osmo_st2_cardem_inst with fields required by osmo-remsim
Change-Id: Ib568e5212abfd1269a12c9e5672cdf23b4abff91
2020-03-03 21:09:50 +01:00
Harald Welte
e6806e58c2 cardem: Fix infinite loop + watchdog reset on long OUT message
In dispatch_received_usb_msg(), we ran into an infinite loop if a
too long messages was received on the OUT EP.  Let's break the loop.

Change-Id: I5325ed15d3dd79a42f8dac34d618e86b9334c301
Closes: OS#4429
2020-03-01 19:19:53 +00:00
Harald Welte
37220cce25 Disable interrupts during EEFC_ReadUniqueID()
Reading the Unique ID from flash is a rather tricky procedure: After the
STUI command has been issued, we cannot read normal flash anymore.
Rather, the unique ID is mapped at 0x00000000. This is unfortuantely
also where the exception vector table is stored.

EEFC_ReadUniqueID() is already linked to RAM, which is good.  Hoewver,
if an Interrupt happens between STUI and SPUI, then we try to access
the vector table and code from flash, which is illegal.  We run into
a hardfault and stay there until the watchdog resets the processor.

Change-Id: I3c4fad55b47e9013f6615a331983b3989ca805a7
Closes: OS#4428
2020-03-01 15:47:42 +01:00
Harald Welte
02712376df simtrace2_api: Add osmo_st2_cardem_request_config()
In Change-Id I7cdd3f9171dbed45de0089defe29d2b59044bd84 we introduced
firmware support for SIMTRACE_MSGT_BD_CEMU_CONFIG.  The respective
host part was so far only implemented in osmo-remsim-client-st2,
but not in libosmo-simtrace2.  Let's fix that.

Change-Id: Ia4822d360a271d2ce9725f761cb95de58663ac3b
2020-02-22 22:13:24 +01:00
Eric Wild
baa62777c8 cardem: disable upload for simtrace2
cardem on the st2 has been broken forever and still does not work, so
stop uploading cardem binaries

Change-Id: I33828f799d41386afb3f8dcd9bb510902877e03f
2020-01-30 17:22:40 +01:00
Eric Wild
1fad9229bf remsim: allow selecting pcsc reader number
The number can be queried using pcsc_scan -n

Change-Id: I9d347501a9f181f68e74799ad04a810553eb2c9e
2020-01-30 10:21:36 +00:00
Harald Welte
c7173bcc69 increase ringbuffer size from 512 to 1024 bytes
As reported in https://osmocom.org/issues/4335, there appear to
be some cards / use cases in which the 512 byte sized ringbuffer is
insufficient.  As we do have free RAM available, we can easily
increase the buffer size, despite not entirely knowing yet why
it needs to be *that* large.

Change-Id: Ie713d614ec5b334e9058d5d430e4bb660f5b8b69
Closes: OS#4335
2020-01-17 16:33:59 +01:00
Harald Welte
02f01e859c host/lib/gsmtap.c: Add GPLv2 disclaimer
Change-Id: Ie163af869c6aa2f3e2bd9007432dc6945384aaf2
2020-01-17 10:29:03 +01:00
Harald Welte
575214f248 host: Add COPYING file for host software (GPLv2)
Change-Id: I0f89a204939b0648eed94cc4f6e7c4f735c118fa
2020-01-17 10:23:31 +01:00
Kévin Redon
e88be9e782 add script to flash latest firmware
this python script lists the SIMtrace 2 devices connected to USB
and will flash the latest version of the application (if necessary).
it requires pyusb and dfu-util.
it is intended for end users so they don't need to read the length
and error-prone instructions provided in the wiki.

TODO:
- support updating bootloader (once dfu-ram image exists)
- use python implementation of dfu-util to be python only

Change-Id: I3ebe0f54b6e3b7b45478603cc0a5b56e87b1f461
2020-01-16 20:36:23 +00:00
Kévin Redon
b6e2f0f8e7 DFU: add DFU application
this adds the DFU as application, allowing to flash the bootloader.
a USB DFU alternative is added to flash the bootloader partition.

when the DFU is started as bootloader, the partition/alternative
to flash the bootloader is marked as "not available", and
ineffective.
the same happens for the application partition when DFU is started
as application.

this distinction is make at compile time, not at runtime, because
of size restrictions (the bootloader was already close to the
16 kB limit).
*_dfu_flash.bin should not be mixed with *_dfu_dfu.bin.
*_dfu_dfu.bin should be flashed as application using the already
existing DFU bootloader.
once this images is started (as application), the *_dfu_flash.bin
should be flashed as bootloader using the DFU application.

once the DFU bootloader has been flashed, soft resetting
(not re-powering) will cause the bootloader to start, allowing to
flash the application with a normal image (e.g. not DFU),
replacing the DFU application.
this switch to DFU only happens after downloading (e.g. flashing).

it is planned to have the DFU application erase itself after
flashing, but this is currently not implemented.

Change-Id: Ic273bb593a7669111b0219fe301d7897419167c8
2020-01-16 20:35:04 +00:00
Harald Welte
34200e4676 firmware: apps/cardem/main.c: Synchronize with apps/trace/main.c
In the end we want to share most of this, irrespective of the "APP".
Let's avoid unnecessary differences.

Change-Id: Icf063d4ca79edf66ffbe8e87a915deb77dec478a
2020-01-11 17:52:44 +01:00
Harald Welte
e3b2de45c4 firmware: move printing of welcome banner to common function print_banner()
This unifies the printing of the welcome banner, and it also ensures
that all modes print all information (serial number, reset cause).

Furthermore the APP and BOARD #defines from the make environment are
also printed.

Change-Id: I7e6bc05cee4b9ec0fd9a05dc90ce0b26a5763e5a
2020-01-11 17:52:36 +01:00
Harald Welte
ce4b5c25e8 library: Add osmo_st2_compatible_dev_idsp[]
This is a list of known-compatible USB VID/PID pairs.

Change-Id: I3ef66ebba307899c57077bfd633f84f30190f4dc
2019-12-26 08:07:59 +01:00
Harald Welte
7f7de1ec1d migrate to libosmousb
the code we used to have in libusb_util.c has been migrated to
libosmousb, a new part of libosmocore.git.  Let's remove our historic
copy and use the new shared library instead.

Change-Id: Ib588c08f873c4da8f3a02815ee2767674a6a5061
2019-12-26 08:07:19 +01:00
Harald Welte
8591495d74 Update .gitignore file for host
Change-Id: Id6449ea1c3e918e8c7748b9af7c8c354c1b607d5
2019-12-26 08:07:19 +01:00
Harald Welte
b566ea3e83 OSMO_ASSERT() on double-free or invalid pointer
Change-Id: I2ab8fb7b86b6f608bbd9c4f79369c64cbad88bdf
2019-12-25 08:51:44 +01:00
Harald Welte
563601cff2 [lib] apdu_dispatch: Don't print APDU state to stdout
The printing was always only done at the end of osmo_apdu_segment_in(),
so let's leave the decision up to the user if he wants to print the
state at every iteration or not.

We now provide osmo_apdu_dump_context_buf() to the user so he can obtain
a string representation of the internal state for logging at any time he
requires.

Change-Id: Id3e3cf1605dec84077b158c1c5715f8eef2641d5
2019-12-17 12:46:21 +00:00
Harald Welte
e9556efe88 [lib] apdu_dispatch: Use DLGLOBAL and don't printf() directly
Change-Id: I2f3ec49d34b6806e13af185fb629cabc486891fb
2019-12-17 12:46:21 +00:00
Harald Welte
cdc0853777 jenkins.sh: Add verify_value_string_arrays_are_terminated.py
Change-Id: I15f13e12711b87ce71b38b16ef17620850fd8eb7
2019-12-17 13:28:15 +01:00
Harald Welte
bfd27afd5f firmware: Reformat value_string to pass our validation scripts
This is a purely cosmetic change in terms of coding style, but it
fixes an [invalid] detection for unterminated value_string arrays
by our verify_value_string_arrays_are_terminated.py script:

Change-Id: I2f2370a673074f6bf5380106b6254b4aa1e8a792
ERROR: file contains unterminated value_string 'struct value_string iso7816_3_card_state_names[]': './deps/simtrace2/firmware/libcommon/source/card_emu.c'
ERROR: file contains unterminated value_string 'struct value_string tpdu_state_names[]': './deps/simtrace2/firmware/libcommon/source/card_emu.c'
2019-12-17 12:57:09 +01:00
Harald Welte
17cda3db8a simtrace2-sniff: Reformat value_string to pass our validation scripts
This is a purely cosmetic change in terms of coding style, but it
fixes an [invalid] detection for unterminated value_string arrays
by our verify_value_string_arrays_are_terminated.py script:

Change-Id: Iee905c744065df1dc54f04be752a65700897a92c
ERROR: file contains unterminated value_string 'struct value_string change_flags[]': './deps/simtrace2/host/src/simtrace2-sniff.c'
ERROR: file contains unterminated value_string 'struct value_string data_flags[]': './deps/simtrace2/host/src/simtrace2-sniff.c'
2019-12-17 12:04:56 +01:00
Harald Welte
e213cc4f59 cardem: Implement support for CEMU_FEAT_F_STATUS_IRQ
If this feature flag is set by the host application, we will start
generating SIMTRACE_MSGT_BD_CEMU_STATUS towards the interrupt endpoint
on any changes to the SIM card status, such as change of VCC/CLK/RST

Change-Id: I832b4ac4aeb6152195d985067ffdd64fa5a7d4cc
Related: OS#4330
2019-12-16 14:51:49 +01:00
Harald Welte
a5bbe78d2d cardem: Add SIMTRACE_MSGT_BD_CEMU_CONFIG
The new SIMTRACE_MSGT_BD_CEMU_CONFIG command can be used to set/change
a bitmask of optional features that can be enabled in the simtrace
by the host software.  This is useful for enabling features in the
firmware which are not supported by older host utilities.

The firmware will return the actually set/configured features in
response.

The feature bitmask is not yet used anywhere; it will be by subequent
patches.

Change-Id: I7cdd3f9171dbed45de0089defe29d2b59044bd84
2019-12-16 14:51:49 +01:00
Harald Welte
140f007c3e cardem: Make card_emu_report_status() optionally use IRQ endpoint
This just introduces the capability to report on IRQ, but we don't
actually use it yet.

Change-Id: I83db4463b7010ba243a8adbda3ac9393975b4814
2019-12-16 14:51:49 +01:00
Harald Welte
12c9b7ba02 card_emu: Remove extraneous initialization of ch->pts.state
ch->pts.state is initialized every time we enter ISO_S_WAIT_TPDU
state, so there's no need to reset it at other locations. KISS.

Change-Id: I5ff8b2671c3c893cc5f6542d48b65487ae8c5be1
2019-12-16 14:51:29 +01:00
Harald Welte
4d4405ff3a card_emu: Remove extraneous code
card_set_state(ch, ISO_S_WAIT_ATR) internally calls tc_etu_enable(),
so there's no need for the caller to do the same, too.

Change-Id: I2a2b4d64c40264623313a867957ffcefe57748f9
2019-12-16 14:51:28 +01:00
Harald Welte
6a3a714e2f card_emu: Always print state names in string representation
Change-Id: I81469e40f3720afdcb47048b45c63d6474887640
2019-12-16 14:49:56 +01:00
Harald Welte
e9f429d34c card_emu: Avoid recursive calls to card_set_state()
A function that is called to set the state should not in itself
contain logic to issue further state changes.

Let's shift the related block out to the end of card_emu_io_statechg(),
which is the only source of card_set_state() calls for the
WAIT_{POWER,CLK,RST} states anyway.

As an added benefit, the block of statements is now also executed if
there's no state change - something that was prevented by the
"if old == new" state guard at the top of card_set_state().  I believe
this may help us to cover more (non-standard) card activation sequences.

Change-Id: Ieefa1807099eb234cfd994bca83caaa0dcc919b6
2019-12-16 14:49:56 +01:00
Harald Welte
02d0d73cf1 card_emu: Initialize PTSS state every time we start PTS
Let's shift the responsibility from the caller side to the calee side.

Change-Id: I39661ca93c87b2e2071765f69578eec5aaf90ce4
2019-12-16 00:08:46 +01:00
Harald Welte
5b136021d8 host_communication: Send zero-length-packet on wMaxPacketSize
We need to send zero-length packets on bulk endpoints whenever the
transfer size is exactly a multiple of the wMaxPacketSize.

See USB 2.0 Specification Section 5.8.3 titled "Bulk Transfer Packet
Size constraints."

Change-Id: Ice3842399d5a5c4a18383860f81074497c6e7c9b
Closes: OS#4331
2019-12-16 00:08:46 +01:00
Harald Welte
81f4ef7750 cardem: RST resets all state (including release of buffers)
When the Modem is asserting RST, the emulated card should set all
of its state back to default/initial values and release any buffers
it may still hold in its state.

Change-Id: I66eca6afe4ff7d900c5b75df1e3ec6d52f6ef214
Related: OS#4251
2019-12-15 17:53:01 +01:00
Harald Welte
fa197ca343 cardem: Move card_emu_io_statechg() calls out of interrupt context
So far, we called card_emu_io_statechg() from interrupt context, which
was safe with the current code.  However, as we want to trigger a more
comprehensive reset of data structures, including the flushing of
message queues, it is best to shift this processing from interrupt
context to main loop context.

Change-Id: I3983078396538f32bdff55611c41d2163be4d796
Related: OS#4251
2019-12-15 17:52:00 +01:00
Harald Welte
e92cb50a6e card_emu: Factor out card_handle_reset() from card_emu_init()
Let's move all initialization of state that may change at runtime
to a separate function: card_handle_reset().

This has the advantage that the related function may also be called
at later/other instances, not just during initialization of card_emu.

Change-Id: I0954d192d001a3af5592010cc84a3a22aaf4b030
Related: OS#4251
2019-12-15 17:51:47 +01:00
Harald Welte
1714679106 pseudo_talloc: Increment number of buffers from 10 to 20
We need at least one per IN/IRQ endpoint, as well as at least 3 for
every OUT endpoint.  Plus some more depending on the application,
in case of cardem there could be one in uart_tx and one in uart_rx.

So for cardem, it should be 7 per slot, resulting 14 for dual-slot
devices like OWHW and QMOD.

Given that we have plenty of RAM available (utilization up from 49%
to 56% with this change), we can be on the comfortable size and
easily have 20 buffers for now.

Future MITM / triple-play applications likely need more.

Change-Id: I022ba3bb3e1f5fd0c364aafe1a23f8fd9b2d8499
Related: OS#4251
2019-12-15 17:39:26 +01:00
Harald Welte
a812de808d usb_buf: Properly initialize buffered_endpoint->ep number
The number is used only in print statements, and it's always '0' so far.

Change-Id: Id147e24d9d50c274fec963f00494cb20e2360b33
2019-12-15 17:25:14 +01:00
Harald Welte
b0b457df63 USBD_HAL: Don't disable UDP peripheral clock on suspend
Change-Id: I2169e2140762b37661f4567bb148326afd85cddc
Closes: OS#4329
2019-12-15 17:25:13 +01:00
Harald Welte
ad117091ca usb_buf: Actually limit queue to 3 elements, not 4
In Change-ID Ie15183f16b22193ffdaf01845db2eae4c7f43c17 we wanted
to limit the number of queue elements to 3, but actually implemented 4.

Change-Id: Ic5fb164f2dfd1c293c51bee8184fc34552267a54
2019-12-15 17:25:13 +01:00
Harald Welte
56be0bf317 cardem: Fix memory leak on unsupported SIMTRACE_MSGT_DT_CEMU_CARDINSERT
Some boards like QMOD cannot simulate a virtual card insert signal
towards the modem (as the mPCIe connector doesn't have that signal).

In these situations, we were aborting processing of the related OUT
endpoint command and forgot to release the related memory.

Change-Id: I489097b7e332004e0f2beca0b22fa36d5d1d31b5
Related: OS#4251
2019-12-14 23:26:02 +01:00
Harald Welte
60118315cc update copyright statement
Change-Id: I6ffced85cf2398bbf6dcc3123accb5610e766f61
2019-12-14 23:07:04 +01:00
Harald Welte
63c9e1f402 implement minimalistic talloc_report(); add 't' command on UART
This helps when debugging the firmware, as it shows the current
utliization of the 10-msgb-talloc pool.

Change-Id: Ib10c4396cd4c9c4a6257cf45886e367214787927
Related: OS#4251
2019-12-14 23:07:04 +01:00
Harald Welte
7c1d85eb4d qmod: Document '!' and '@' commands on UART
Change-Id: I38c69ef45e92fd0aa03907e984cf524331b53d57
2019-12-14 23:07:04 +01:00
Harald Welte
587248404c cosmetic: board_qmod: Annotate #endif with comments
Change-Id: I2e2de6c65d791767637b9c43a1c0ff9cbeabf5e9
2019-12-14 23:07:04 +01:00
Harald Welte
f620c3978c qmod: Don't print EEPROM operations in help when not supported
As of Change-Id I1c8cca2f7f0f0070d7bf1ade676e035c45e4d5ab, a firmware
compiled without ALLOW_PEER_ERASE will not support resetting the hub or
writing to its EEPROM.  Let's make sure to remove those options also
from the menu.

Change-Id: I3071332d85e6168947384ddc230298d3293e4668
2019-12-14 23:07:04 +01:00
Harald Welte
a14616c096 usb_buf: Limit the maximum queue length to 3 elements
If there are already three elements in the to-be-transmitted queue
for the EP, let's free the first element of the queue.  This is a
clear indication that the USB host is not polling the endpoint
regularly.  Maybe there's no host application running at all?

This should obsolete Change-Id Ie9ebdd2ff966f67c9afd1ed760f106558f0091ad

Change-Id: Ie15183f16b22193ffdaf01845db2eae4c7f43c17
Closes: OS#4251
2019-12-14 21:51:05 +01:00
Harald Welte
f4a625be53 usb_buf: count number of elements in queue
This is in preparation for limiting the maximum queue length

Change-Id: I7cb184d7a1ccb519010a2f3e3295cc3a5fbf8052
Related: OS#4251
2019-12-14 21:50:59 +01:00
Harald Welte
271be9d181 more comments in host_communication.c.
Change-Id: I8b0124ec96b56b7c89e4c7033a11cc93c4fa2d26
2019-12-14 21:13:37 +01:00
Harald Welte
342a7fe039 Add missing CR to achieve CRLF at end of log lines
Change-Id: Ic4afb2981f68811fddb272e64dbddd3397a12642
2019-12-14 17:26:21 +00:00
Harald Welte
3c003cc2fa Fix format string related warnings (int vs. long)
Change-Id: I924a16f03e2a099b9f8eb56746bff2b9101c6802
2019-12-14 11:47:06 +01:00
Harald Welte
37055b9286 stdio: Add support for %p format string (pointer address)
We actually llready had plrenty of code using %p, despite our stdio
not implementing it ;)

Change-Id: Iecf6c849ce5ef72a8fed9b19a18e215c61c3d09f
2019-12-14 11:47:06 +01:00
Kévin Redon
75a5f224c0 minor: improve trace output
the USB trace now respects the global setting.
the verbosity is also decreased, not showing USB activity unless
debugging.
this also saves some space.

the reset cause is now printed.
the strings increase the bootloader size, but it already exceeded
the 16 kB limit when trace level is set to info.

Change-Id: I9ba08d4bb4f188f6e7a202ea86acb7a42a2054f3
2019-12-11 16:58:07 +01:00
Kévin Redon
198c3fb21b improve shared bootloader/application memory
now both partitions (bootloader and application) use a commonly
defined memory location to shared the DFU state (which includes
the magic value to know which part to start), instead of using
a hard coded value.

the bootloader size has now also been restricted to 16 kB.
this limitation is enforced so to not be able to create larger
images, which could be corrupted when flashing the application.

bootloader and application flashing have been successfully tested
on qmod st12 and st34.

Change-Id: I204bed7e9391602672ed894decec1fc12e879275
2019-12-11 16:35:31 +01:00
Kévin Redon
98cf47adba Makefile: add linker option showing memory usage
this will help seeing how much free space is available for the
bootloader (which is restricted to 16 kB)

Change-Id: Ie74a1480c2f340765046be9bdfc3a8c4ba851e9b
2019-12-11 16:13:58 +01:00
107 changed files with 5032 additions and 2464 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

164
contrib/flash.py Executable file
View File

@@ -0,0 +1,164 @@
#!/usr/bin/env python
# encoding: utf-8
# python: 3.8.1
# library to enumerate USB devices
import usb.core
from usb.util import *
# more elegant structure
from typing import NamedTuple
# regular expressions utilities
import re
# open utilities to handle files
import os, sys
# to download the firmwares
import urllib.request
# to flash using DFU-util
import subprocess
# SIMtrace 2 device information
class Device(NamedTuple):
usb_vendor_id: int
usb_product_id: int
name: str
url: dict # 1: sniff/trace firmware, 2: card emulation firmware
# SIMtrace 2 devices definitions
DEVICE_SIMTRACE = Device(usb_vendor_id=0x1d50, usb_product_id=0x60e3, name="SIMtrace 2", url={"trace": "https://ftp.osmocom.org/binaries/simtrace2/firmware/latest/simtrace-trace-dfu-latest.bin", "cardem": "https://osmocom.org/attachments/download/3868/simtrace-cardem-dfu.bin"})
DEVICE_QMOD = Device(usb_vendor_id=0x1d50, usb_product_id=0x4004, name="sysmoQMOD (Quad Modem)", url={"cardem": "https://ftp.osmocom.org/binaries/simtrace2/firmware/latest/qmod-cardem-dfu-latest.bin"})
DEVICE_OWHW = Device(usb_vendor_id=0x1d50, usb_product_id=0x4001, name="OWHW", url={"cardem": "https://ftp.osmocom.org/binaries/simtrace2/firmware/latest/owhw-cardem-dfu-latest.bin"})
DEVICE_OCTSIMTEST = Device(usb_vendor_id=0x1d50, usb_product_id=0x616d, name="OCTSIMTEST", url={"cardem": "https://ftp.osmocom.org/binaries/simtrace2/firmware/latest/octsimtest-cardem-dfu-latest.bin"})
DEVICE_NGFF_CARDEM = Device(usb_vendor_id=0x1d50, usb_product_id=0x616e, name="ngff-cardem", url={"cardem": "https://ftp.osmocom.org/binaries/simtrace2/firmware/latest/ngff_cardem-cardem-dfu-latest.bin"})
DEVICES = [DEVICE_SIMTRACE, DEVICE_QMOD, DEVICE_OCTSIMTEST, DEVICE_NGFF_CARDEM]
# which firmware does the SIMtrace USN interface subclass correspond
FIRMWARE_SUBCLASS = {1: "trace", 2: "cardem"}
def print_help():
print("this script will flash SIMtrace 2 - based devices")
print("when no argument is provided, it will try to flash the application firmware of all SIMtrace 2 devices connected to USB with the latest version")
print("to flash a specific firmware, provide the name as argument")
print("the possible firmwares are: trace, cardem")
print("to list all devices connected to USB, provide the argument \"list\"")
# the firmware to flash
to_flash = None
# parse command line argument
if len(sys.argv) == 2:
to_flash = sys.argv[1]
if to_flash not in ["list", "trace", "cardem"] and len(sys.argv) > 1:
print_help()
exit(0)
# get all USB devices
devices = []
devices_nb = 0
updated_nb = 0
usb_devices = usb.core.find(find_all=True)
for usb_device in usb_devices:
# find SIMtrace devices
definitions = list(filter(lambda x: x.usb_vendor_id == usb_device.idVendor and x.usb_product_id == usb_device.idProduct, DEVICES))
if 1 != len(definitions):
continue
devices_nb += 1
definition = definitions[0]
serial = usb_device.serial_number or "unknown"
usb_path = str(usb_device.bus) + "-" + ".".join(map(str, usb_device.port_numbers))
print("found " + definition.name + " device (chip ID " + serial + ") at USB path " + usb_path)
# determine if we are running DFU (in most cases the bootloader, but could also be the application)
dfu_interface = None
for configuration in usb_device:
# get DFU interface descriptor
dfu_interface = dfu_interface or find_descriptor(configuration, bInterfaceClass=254, bInterfaceSubClass=1)
if (None == dfu_interface):
print("no DFU USB interface found")
continue
dfu_mode = (2 == dfu_interface.bInterfaceProtocol) # InterfaceProtocol 1 is runtime mode, 2 is DFU mode
# determine firmware type (when not in DFU mode)
firmware = None
simtrace_interface = None
for configuration in usb_device:
simtrace_interface = simtrace_interface or find_descriptor(configuration, bInterfaceClass=255)
if simtrace_interface and simtrace_interface.bInterfaceSubClass in FIRMWARE_SUBCLASS:
firmware = firmware or FIRMWARE_SUBCLASS[simtrace_interface.bInterfaceSubClass]
if dfu_mode:
firmware = 'dfu'
if firmware:
print("installed firmware: " + firmware)
else:
print("unknown installed firmware")
continue
# determine version of the application/bootloader firmware
version = None
version_interface = None
for configuration in usb_device:
# get custom interface with string
version_interface = version_interface or find_descriptor(configuration, bInterfaceClass=255, bInterfaceSubClass=255)
if version_interface and version_interface.iInterface and version_interface.iInterface > 0 and get_string(usb_device, version_interface.iInterface):
version = get_string(usb_device, version_interface.iInterface)
if not version:
# the USB serial is set (in the application) since version 0.5.1.34-e026 from 2019-08-06
# https://git.osmocom.org/simtrace2/commit/?id=e0265462d8c05ebfa133db2039c2fbe3ebbd286e
# the USB serial is set (in the bootloader) since version 0.5.1.45-ac7e from 2019-11-18
# https://git.osmocom.org/simtrace2/commit/?id=5db9402a5f346e30288db228157f71c29aefce5a
# the firmware version is set (in the application) since version 0.5.1.37-ede8 from 2019-08-13
# https://git.osmocom.org/simtrace2/commit/?id=ede87e067dadd07119f24e96261b66ac92b3af6f
# the firmware version is set (in the bootloader) since version 0.5.1.45-ac7e from 2019-11-18
# https://git.osmocom.org/simtrace2/commit/?id=5db9402a5f346e30288db228157f71c29aefce5a
if dfu_mode:
if serial:
version = "< 0.5.1.45-ac7e"
else:
versoin = "< 0.5.1.45-ac7e"
else:
if serial:
version = "< 0.5.1.37-ede8"
else:
versoin = "< 0.5.1.34-e026"
print("device firmware version: " + version)
# flash latest firmware
if to_flash == "list": # we just want to list the devices, not flash them
continue
# check the firmware exists
if firmware == "dfu" and to_flash is None:
print("device is currently in DFU mode. you need to specify which firmware to flash")
continue
to_flash = to_flash or firmware
if to_flash not in definition.url.keys():
print("no firmware image available for " + firmware + " firmware")
continue
# download firmware
try:
dl_path, header = urllib.request.urlretrieve(definition.url[to_flash])
except:
print("could not download firmware " + definition.url[to_flash])
continue
dl_file = open(dl_path, "rb")
dl_data = dl_file.read()
dl_file.close()
# compare versions
dl_version = re.search(b'firmware \d+\.\d+\.\d+\.\d+-[0-9a-fA-F]{4}', dl_data)
if dl_version is None:
print("could not get version from downloaded firmware image")
os.remove(dl_path)
continue
dl_version = dl_version.group(0).decode("utf-8").split(" ")[1]
print("latest firmware version: " + dl_version)
versions = list(map(lambda x: int(x), version.split(" ")[-1].split("-")[0].split(".")))
dl_versions = list(map(lambda x: int(x), dl_version.split("-")[0].split(".")))
dl_newer = (versions[0] < dl_versions[0] or (versions[0] == dl_versions[0] and versions[1] < dl_versions[1]) or (versions[0] == dl_versions[0] and versions[1] == dl_versions[1] and versions[2] < dl_versions[2]) or (versions[0] == dl_versions[0] and versions[1] == dl_versions[1] and versions[2] == dl_versions[2] and versions[3] < dl_versions[3]))
if not dl_newer:
print("no need to flash latest version")
os.remove(dl_path)
continue
print("flashing latest version")
dfu_result = subprocess.run(["dfu-util", "--device", hex(definition.usb_vendor_id) + ":" + hex(definition.usb_product_id), "--path", usb_path, "--cfg", "1", "--alt", "1", "--reset", "--download", dl_path])
os.remove(dl_path)
if 0 != dfu_result.returncode:
printf("flashing firmware using dfu-util failed. ensure dfu-util is installed and you have the permissions to access this USB device")
continue
updated_nb += 1
print(str(devices_nb)+ " SIMtrace 2 device(s) found")
print(str(updated_nb)+ " SIMtrace 2 device(s) updated")

View File

@@ -21,13 +21,17 @@ mkdir "$deps" || true
osmo-build-dep.sh libosmocore "" '--disable-doxygen --enable-gnutls'
# verify only after building the dependency (to ensure we have most recent source of dependency)
verify_value_string_arrays_are_terminated.py $(find . -name "*.[hc]")
export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH"
export LD_LIBRARY_PATH="$inst/lib"
BUILDS=""
BUILDS+="simtrace/dfu simtrace/cardem simtrace/trace " # simtrace/triple_play
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
@@ -63,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

68
contrib/simtrace.lua Normal file
View File

@@ -0,0 +1,68 @@
usb_simtrace_protocol = Proto("USB_simtrace", "USB simtrace protocol")
local control_commands = {
-- /* SIMTRACE_MSGC_GENERIC */
[0x0000] = "SIMTRACE_CMD_DO_ERROR",
[0x0001] = "SIMTRACE_CMD_BD_BOARD_INFO",
-- /* SIMTRACE_MSGC_CARDEM */
[0x0101] = "SIMTRACE_MSGT_DT_CEMU_TX_DATA",
[0x0102] = "SIMTRACE_MSGT_DT_CEMU_SET_ATR",
[0x0103] = "SIMTRACE_MSGT_BD_CEMU_STATS",
[0x0104] = "SIMTRACE_MSGT_BD_CEMU_STATUS",
[0x0105] = "SIMTRACE_MSGT_DT_CEMU_CARDINSERT",
[0x0106] = "SIMTRACE_MSGT_DO_CEMU_RX_DATA",
[0x0107] = "SIMTRACE_MSGT_DO_CEMU_PTS",
[0x0108] = "SIMTRACE_MSGT_BD_CEMU_CONFIG",
-- /* SIMTRACE_MSGC_MODEM */
[0x0201] = "SIMTRACE_MSGT_DT_MODEM_RESET",
[0x0202] = "SIMTRACE_MSGT_DT_MODEM_SIM_SELECT",
[0x0203] = "SIMTRACE_MSGT_BD_MODEM_STATUS",
-- /* SIMTRACE_MSGC_SNIFF */
[0x0300] = "SIMTRACE_MSGT_SNIFF_CHANGE",
[0x0301] = "SIMTRACE_MSGT_SNIFF_FIDI",
[0x0302] = "SIMTRACE_MSGT_SNIFF_ATR",
[0x0304] = "SIMTRACE_MSGT_SNIFF_TPDU",
[0x0303] = "SIMTRACE_MSGT_SNIFF_PPS"
}
local msgtype = ProtoField.uint16("usb_simtrace.msgtype", "Message Type", base.HEX_DEC, control_commands)
local seqnr = ProtoField.uint8("usb_simtrace.seqnr", "Sequence Number", base.HEX_DEC)
local slotnr = ProtoField.uint8("usb_simtrace.slotnr", "Slot Number", base.HEX_DEC)
local reserved = ProtoField.uint16("usb_simtrace.reserved", "reserved", base.HEX_DEC)
local payloadlen = ProtoField.uint16("usb_simtrace.length", "length", base.HEX_DEC)
local payload = ProtoField.bytes("usb_simtrace.payload", "Data")
usb_simtrace_protocol.fields = {
msgtype, seqnr, slotnr, reserved, payloadlen, payload
}
function usb_simtrace_protocol.dissector(buffer, pinfo, tree)
length = buffer:len()
if length == 0 then return end
pinfo.cols.protocol = usb_simtrace_protocol.name
local subtree = tree:add(usb_simtrace_protocol, buffer(), "USB simtrace Data")
local command = buffer(0,2):uint()
subtree:add(msgtype, command):set_generated()
subtree:add(seqnr, buffer(2,1))
subtree:add(slotnr, buffer(3,1))
subtree:add_le(payloadlen, buffer(6,2))
pinfo.cols.info = string.format("Cmd 0x%04X : %s", command, control_commands[command])
subtree:add(payload, buffer(8,length-8))
end
function usb_simtrace_protocol.init()
local usb_product_dissectors = DissectorTable.get("usb.product")
usb_product_dissectors:add(0x1d50616d, usb_simtrace_protocol)
usb_product_dissectors:add(0x1d50616e, usb_simtrace_protocol)
-- DissectorTable.get("usb.bulk"):add(0xffff, usb_simtrace_protocol)
end

1
debian/source/format vendored Normal file
View File

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

View File

@@ -28,11 +28,19 @@
# 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
#-------------------------------------------------------------------------------
# verbosity
V ?= 0
ifneq ("$(V)","0")
SILENT :=
else
SILENT := @
endif
# Chip & board used for compilation
# (can be overriden by adding CHIP=chip and BOARD=board to the command-line)
CHIP ?= sam3s4
@@ -41,7 +49,7 @@ APP ?= dfu
# Defines which are the available memory targets for the SAM3S-EK board.
ifeq ($(APP), dfu)
MEMORIES ?= flash
MEMORIES ?= flash dfu
else
MEMORIES ?= dfu
endif
@@ -99,7 +107,8 @@ C_LIBCHIP = $(notdir $(wildcard $(AT91LIB)/libchip_sam3s/source/*.c) $(wildcard
C_LIBUSB = USBDescriptors.c USBRequests.c USBD.c USBDCallbacks.c USBDDriver.c USBDDriverCallbacks.c
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
C_LIBCOMMON = string.c stdio.c fputs.c usb_buf.c ringbuffer.c pseudo_talloc.c host_communication.c \
main_common.c stack_check.c
C_BOARD = $(notdir $(wildcard libboard/common/source/*.c))
C_BOARD += $(notdir $(wildcard libboard/$(BOARD)/source/*.c))
@@ -163,14 +172,22 @@ CFLAGS += -Wno-suggest-attribute=noreturn
# -mlong-calls -Wall
#CFLAGS += -save-temps -fverbose-asm
#CFLAGS += -Wa,-a,-ad
CFLAGS += -D__ARM
CFLAGS += -D__ARM -fno-builtin
CFLAGS += --param max-inline-insns-single=500 -mcpu=cortex-m3 -mthumb # -mfix-cortex-m3-ldrd
CFLAGS += -ffunction-sections -g $(OPTIMIZATION) $(INCLUDES) -D$(CHIP) -DTRACE_LEVEL=$(TRACE_LEVEL) -DALLOW_PEER_ERASE=$(ALLOW_PEER_ERASE)
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,--warn-unresolved-symbols $(LIB)
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
# Append BIN directories to output filename
@@ -209,22 +226,18 @@ C_OBJECTS_$(1) = $(addprefix $(OBJ)/$(1)_, $(C_OBJECTS))
ASM_OBJECTS_$(1) = $(addprefix $(OBJ)/$(1)_, $(ASM_OBJECTS))
$(1): $$(ASM_OBJECTS_$(1)) $$(C_OBJECTS_$(1))
@$(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
@$(NM) $(OUTPUT)-$$@.elf >$(OUTPUT)-$$@.elf.txt
@$(OBJCOPY) -O binary $(OUTPUT)-$$@.elf $(OUTPUT)-$$@.bin
cp $(OUTPUT)-$$@.bin $(OUTPUT)-$$@-$(GIT_VERSION).bin
cp $(OUTPUT)-$$@.bin $(OUTPUT)-$$@-latest.bin
@$(SIZE) $$^ $(OUTPUT)-$$@.elf
$(SILENT)$(CC) $(LDFLAGS) $(LD_OPTIONAL) -T"libboard/common/resources/$(CHIP)/$$@.ld" -Wl,-Map,$(OUTPUT)-$$@.map -o $(OUTPUT)-$$@.elf $$^ $(LIBS)
$(SILENT)$(NM) $(OUTPUT)-$$@.elf >$(OUTPUT)-$$@.elf.txt
$(SILENT)$(OBJCOPY) -O binary $(OUTPUT)-$$@.elf $(OUTPUT)-$$@.bin
$(SILENT)$(SIZE) $$^ $(OUTPUT)-$$@.elf
$$(C_OBJECTS_$(1)): $(OBJ)/$(1)_%.o: %.c Makefile $(OBJ) $(BIN)
@echo [COMPILING $$<]
@$(CC) $(CFLAGS) -DENVIRONMENT_$(1) -DENVIRONMENT=\"$(1)\" -Wa,-ahlms=$(BIN)/$$*.lst -c -o $$@ $$<
$(SILENT)$(CC) $(CFLAGS) -DENVIRONMENT_$(1) -DENVIRONMENT=\"$(1)\" -Wa,-ahlms=$(BIN)/$$*.lst -c -o $$@ $$<
$$(ASM_OBJECTS_$(1)): $(OBJ)/$(1)_%.o: %.S Makefile $(OBJ) $(BIN)
@echo [ASSEMBLING $$@]
@$(CC) $(ASFLAGS) -DENVIRONMENT_$(1) -DENVIRONMENT=\"$(1)\" -c -o $$@ $$<
$(SILENT)@$(CC) $(ASFLAGS) -DENVIRONMENT_$(1) -DENVIRONMENT=\"$(1)\" -c -o $$@ $$<
debug_$(1): $(1)
$(GDB) -x "$(BOARD_LIB)/resources/gcc/$(BOARD)_$(1).gdb" -ex "reset" -readnow -se $(OUTPUT)-$(1).elf

View File

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

@@ -24,10 +24,9 @@
#include "board.h"
#include "simtrace.h"
#include "utils.h"
#include "main_common.h"
#include <osmocom/core/timer.h>
unsigned int g_unique_id[4];
/*------------------------------------------------------------------------------
* Internal variables
*------------------------------------------------------------------------------*/
@@ -40,7 +39,7 @@ typedef struct {
void (*exit) (void);
/* main loop content for given configuration */
void (*run) (void);
/* Interrupt handler for USART1 */
/* Interrupt handler for USART0 */
void (*usart0_irq) (void);
/* Interrupt handler for USART1 */
void (*usart1_irq) (void);
@@ -54,6 +53,8 @@ static const conf_func config_func_ptrs[] = {
.init = Sniffer_init,
.exit = Sniffer_exit,
.run = Sniffer_run,
.usart0_irq = Sniffer_usart0_irq,
.usart1_irq = Sniffer_usart1_irq,
},
#endif
#ifdef HAVE_CCID
@@ -146,7 +147,8 @@ extern int main(void)
unsigned int i = 0;
led_init();
led_blink(LED_RED, BLINK_3O_5F);
led_blink(LED_RED, BLINK_ALWAYS_ON);
led_blink(LED_GREEN, BLINK_ALWAYS_ON);
/* Enable watchdog for 2000ms, with no window */
WDT_Enable(WDT, WDT_MR_WDRSTEN | WDT_MR_WDDBGHLT | WDT_MR_WDIDLEHLT |
@@ -154,34 +156,7 @@ extern int main(void)
PIO_InitializeInterrupts(0);
EEFC_ReadUniqueID(g_unique_id);
printf("\n\r\n\r"
"=============================================================================\n\r"
"SIMtrace2 firmware " GIT_VERSION "\n\r"
"(C) 2010-2017 by Harald Welte, 2018-2019 by Kevin Redon\n\r"
"=============================================================================\n\r");
#if (TRACE_LEVEL >= TRACE_LEVEL_INFO)
TRACE_INFO("Chip ID: 0x%08lx (Ext 0x%08lx)\n\r", CHIPID->CHIPID_CIDR, CHIPID->CHIPID_EXID);
TRACE_INFO("Serial Nr. %08x-%08x-%08x-%08x\n\r",
g_unique_id[0], g_unique_id[1],
g_unique_id[2], g_unique_id[3]);
uint8_t reset_cause = (RSTC->RSTC_SR & RSTC_SR_RSTTYP_Msk) >> RSTC_SR_RSTTYP_Pos;
static const char* reset_causes[] = {
"general reset (first power-up reset)",
"backup reset (return from backup mode)",
"watchdog reset (watchdog fault occurred)",
"software reset (processor reset required by the software)",
"user reset (NRST pin detected low)",
};
if (reset_cause < ARRAY_SIZE(reset_causes)) {
TRACE_INFO("Reset Cause: %s\n\r", reset_causes[reset_cause]);
} else {
TRACE_INFO("Reset Cause: 0x%lx\n\r", (RSTC->RSTC_SR & RSTC_SR_RSTTYP_Msk) >> RSTC_SR_RSTTYP_Pos);
}
#endif
print_banner();
board_main_top();
TRACE_INFO("USB init...\n\r");
@@ -202,8 +177,7 @@ extern int main(void)
}
TRACE_INFO("calling configure of all configurations...\n\r");
for (i = 1; i < sizeof(config_func_ptrs) / sizeof(config_func_ptrs[0]);
++i) {
for (i = 1; i < ARRAY_SIZE(config_func_ptrs); i++) {
if (config_func_ptrs[i].configure)
config_func_ptrs[i].configure();
}

View File

@@ -26,8 +26,15 @@
#include <osmocom/core/timer.h>
/* USB alternate interface index used to identify which partition to flash */
/** USB alternate interface index indicating RAM partition */
#define ALTIF_RAM 0
/** USB alternate interface index indicating flash partition */
#if defined(ENVIRONMENT_flash)
#define ALTIF_FLASH 1
#elif defined(ENVIRONMENT_dfu)
#define ALTIF_FLASH 2
#endif
unsigned int g_unique_id[4];
/* remember if the watchdog has been configured in the main loop so we can kick it in the ISR */
@@ -44,10 +51,18 @@ static const Pin pinsLeds[] = { PINS_LEDS } ;
*----------------------------------------------------------------------------*/
#define RAM_ADDR(offset) (IRAM_ADDR + BOARD_DFU_RAM_SIZE + offset)
#if defined(ENVIRONMENT_flash)
#define FLASH_ADDR(offset) (IFLASH_ADDR + BOARD_DFU_BOOT_SIZE + offset)
#elif defined(ENVIRONMENT_dfu)
#define FLASH_ADDR(offset) (IFLASH_ADDR + offset)
#endif
#define IFLASH_END ((uint8_t *)IFLASH_ADDR + IFLASH_SIZE)
#define IRAM_END ((uint8_t *)IRAM_ADDR + IRAM_SIZE)
#define IRAM_END ((uint8_t *)IRAM_ADDR + IRAM_SIZE)
#if defined(ENVIRONMENT_flash)
#define IFLASH_END ((uint8_t *)IFLASH_ADDR + IFLASH_SIZE)
#elif defined(ENVIRONMENT_dfu)
#define IFLASH_END ((uint8_t *)IFLASH_ADDR + BOARD_DFU_BOOT_SIZE)
#endif
/* incoming call-back: Host has transferred 'len' bytes (stored at
* 'data'), which we shall write to 'offset' into the partition
@@ -90,7 +105,11 @@ int USBDFU_handle_dnload(uint8_t altif, unsigned int offset,
break;
case ALTIF_FLASH:
addr = FLASH_ADDR(offset);
#if defined(ENVIRONMENT_flash)
if (addr < IFLASH_ADDR || addr + len >= IFLASH_ADDR + IFLASH_SIZE) {
#elif defined(ENVIRONMENT_dfu)
if (addr < IFLASH_ADDR || addr + len >= IFLASH_ADDR + BOARD_DFU_BOOT_SIZE) {
#endif
g_dfu->state = DFU_STATE_dfuERROR;
g_dfu->status = DFU_STATUS_errADDRESS;
rc = DFU_RET_STALL;
@@ -224,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
*------------------------------------------------------------------------------*/
@@ -246,34 +276,45 @@ 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();
TRACE_INFO("Chip ID: 0x%08x (Ext 0x%08x)\n\r", CHIPID->CHIPID_CIDR, CHIPID->CHIPID_EXID);
#if (TRACE_LEVEL >= TRACE_LEVEL_INFO)
TRACE_INFO("Chip ID: 0x%08lx (Ext 0x%08lx)\n\r", CHIPID->CHIPID_CIDR, CHIPID->CHIPID_EXID);
TRACE_INFO("Serial Nr. %08x-%08x-%08x-%08x\n\r",
g_unique_id[0], g_unique_id[1],
g_unique_id[2], g_unique_id[3]);
TRACE_INFO("Reset Cause: 0x%lx\n\r", reset_cause);
static const char* reset_causes[] = {
"general reset (first power-up reset)",
"backup reset (return from backup mode)",
"watchdog reset (watchdog fault occurred)",
"software reset (processor reset required by the software)",
"user reset (NRST pin detected low)",
};
if (reset_cause < ARRAY_SIZE(reset_causes)) {
TRACE_INFO("Reset Cause: %s\n\r", reset_causes[reset_cause]);
} else {
TRACE_INFO("Reset Cause: 0x%lx\n\r", (RSTC->RSTC_SR & RSTC_SR_RSTTYP_Msk) >> RSTC_SR_RSTTYP_Pos);
}
#endif
#if (TRACE_LEVEL >= TRACE_LEVEL_INFO)
/* Find out why we are in the DFU bootloader, and not the main application */
TRACE_INFO("DFU bootloader start reason: ");
switch (USBDFU_OverrideEnterDFU()) {
case 0:
/* 0 normally means that there is no override, but we are in the bootloader,
* thus the first check in board_cstartup_gnu did return something else than 0.
* this can only be g_dfu->magic which is erased when the segment are
* relocated, which happens in board_cstartup_gnu just after USBDFU_OverrideEnterDFU.
* no static variable can be used to store this case since this will also be overwritten
*/
if (SCB->VTOR < IFLASH_ADDR + BOARD_DFU_BOOT_SIZE) {
TRACE_INFO_WP("unknown\n\r");
} else {
TRACE_INFO_WP("DFU is the main application\n\r");
}
break;
case 1:
TRACE_INFO_WP("DFU switch requested by main application\n\r");
break;

View File

@@ -3,3 +3,4 @@ PRODUCT_STRING
DFU (Device Firmware Upgrade)
RAM
Flash (Application Partition)
Flash (Bootloader Partition)

View File

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

@@ -24,10 +24,9 @@
#include "board.h"
#include "simtrace.h"
#include "utils.h"
#include "main_common.h"
#include "osmocom/core/timer.h"
unsigned int g_unique_id[4];
/*------------------------------------------------------------------------------
* Internal variables
*------------------------------------------------------------------------------*/
@@ -158,20 +157,7 @@ extern int main(void)
PIO_InitializeInterrupts(0);
EEFC_ReadUniqueID(g_unique_id);
printf("\n\r\n\r"
"=============================================================================\n\r"
"SIMtrace2 firmware " GIT_VERSION " (C) 2010-2016 by Harald Welte\n\r"
"=============================================================================\n\r");
TRACE_INFO("Chip ID: 0x%08lx (Ext 0x%08lx)\n\r", CHIPID->CHIPID_CIDR, CHIPID->CHIPID_EXID);
TRACE_INFO("Serial Nr. %08x-%08x-%08x-%08x\n\r",
g_unique_id[0], g_unique_id[1],
g_unique_id[2], g_unique_id[3]);
TRACE_INFO("Reset Cause: 0x%lx\n\r", (RSTC->RSTC_SR & RSTC_SR_RSTTYP_Msk) >> RSTC_SR_RSTTYP_Pos);
TRACE_INFO("USB configuration used: %d\n\r", simtrace_config);
print_banner();
board_main_top();
TRACE_INFO("USB init...\n\r");

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

@@ -26,8 +26,6 @@
#include "req_ctx.h"
#include <osmocom/core/timer.h>
unsigned int g_unique_id[4];
/*------------------------------------------------------------------------------
* Internal variables
*------------------------------------------------------------------------------*/
@@ -149,17 +147,7 @@ extern int main(void)
PIO_InitializeInterrupts(0);
EEFC_ReadUniqueID(g_unique_id);
printf("\r\n\r\n"
"=============================================================================\r\n"
"SIMtrace2 firmware " GIT_REVISION " (C) 2010-2017 by Harald Welte\r\n"
"=============================================================================\r\n");
TRACE_INFO("Serial Nr. %08x-%08x-%08x-%08x\r\n",
g_unique_id[0], g_unique_id[1],
g_unique_id[2], g_unique_id[3]);
print_banner();
board_main_top();
TRACE_INFO("USB init...\r\n");

View File

@@ -45,11 +45,6 @@
* Headers
*---------------------------------------------------------------------------*/
#ifdef TRACE_LEVEL
#undef TRACE_LEVEL
#endif
#define TRACE_LEVEL TRACE_LEVEL_WARNING
#include "chip.h"
#include "USBD_HAL.h"
#include <usb/device/dfu/dfu.h>
@@ -1082,6 +1077,14 @@ static inline uint8_t UDP_Read(uint8_t bEndpoint,
* Exported functions
*---------------------------------------------------------------------------*/
uint16_t USBD_GetEndpointSize(uint8_t bEndpoint)
{
Endpoint *pEndpoint = &(endpoints[bEndpoint]);
return pEndpoint->size;
}
/**
* USBD (UDP) interrupt handler
* Manages device resume, suspend, end of bus reset.
@@ -1138,7 +1141,7 @@ void USBD_IrqHandler(void)
/* Resume (Wakeup) */
if ((status & (UDP_ISR_WAKEUP | UDP_ISR_RXRSM)) != 0) {
TRACE_INFO_WP("Res ");
TRACE_DEBUG_WP("Res ");
/* Clear and disable resume interrupts */
UDP->UDP_ICR = UDP_ICR_WAKEUP | UDP_ICR_RXRSM | UDP_ICR_RXSUSP;
UDP->UDP_IDR = UDP_IDR_WAKEUP | UDP_IDR_RXRSM;
@@ -1150,7 +1153,7 @@ void USBD_IrqHandler(void)
This interrupt is always treated last (hence the '==') */
if (status == UDP_ISR_RXSUSP) {
TRACE_INFO_WP("Susp ");
TRACE_DEBUG_WP("Susp ");
/* Enable wakeup */
UDP->UDP_IER = UDP_IER_WAKEUP | UDP_IER_RXRSM;
/* Acknowledge interrupt */
@@ -1161,19 +1164,26 @@ void USBD_IrqHandler(void)
/* End of bus reset */
else if ((status & UDP_ISR_ENDBUSRES) != 0) {
TRACE_INFO_WP("EoBRes ");
TRACE_DEBUG_WP("EoBRes ");
#if defined(BOARD_USB_DFU)
#if defined(APPLICATION_dfu)
/* if we are currently in the DFU bootloader, and we are beyond
* the MANIFEST stage, we shall switch to the normal
* application */
if (g_dfu->past_manifest)
if (g_dfu->past_manifest) {
#if defined(ENVIRONMENT_flash)
USBDFU_SwitchToApp();
#elif defined(ENVIRONMENT_dfu)
USBDFU_SwitchToDFU();
#endif
}
#else
/* if we are currently in the main application, and we are in
* appDETACH state, switch into the DFU bootloader */
if (g_dfu->state == DFU_STATE_appDETACH)
* appDETACH state or past downloading, switch into the DFU bootloader.
*/
if (g_dfu->state == DFU_STATE_appDETACH || g_dfu->state == DFU_STATE_dfuMANIFEST)
DFURT_SwitchToDFU();
#endif /* APPLICATION_dfu */
#endif /* BOARD_USB_DFU */
@@ -1202,7 +1212,7 @@ void USBD_IrqHandler(void)
if (status != 0) {
TRACE_INFO_WP("\n\r - ");
TRACE_DEBUG_WP("\n\r - ");
}
}
eptnum++;
@@ -1211,7 +1221,7 @@ void USBD_IrqHandler(void)
/* Toggle LED back to its previous state */
TRACE_DEBUG_WP("!");
TRACE_INFO_WP("\n\r");
TRACE_DEBUG_WP("\n\r");
if (USBD_GetState() >= USBD_STATE_POWERED) {
//LED_Clear(USBD_LEDUSB);
@@ -1361,7 +1371,7 @@ uint8_t USBD_HAL_ConfigureEP(const USBEndpointDescriptor *pDescriptor)
UDP->UDP_IER = (1 << bEndpoint);
}
TRACE_INFO_WP("CfgEp%d ", bEndpoint);
TRACE_DEBUG_WP("CfgEp%d ", bEndpoint);
return bEndpoint;
}
@@ -1529,7 +1539,7 @@ void USBD_HAL_RemoteWakeUp(void)
UDP_EnableUsbClock();
UDP_EnableTransceiver();
TRACE_INFO_WP("RWUp ");
TRACE_DEBUG_WP("RWUp ");
// Activates a remote wakeup (edge on ESR), then clear ESR
UDP->UDP_GLB_STAT |= UDP_GLB_STAT_ESR;
@@ -1692,7 +1702,10 @@ void USBD_HAL_Suspend(void)
/* The device enters the Suspended state */
UDP_DisableTransceiver();
UDP_DisableUsbClock();
UDP_DisablePeripheralClock();
/* Don't disable peripheral clock; this somehow breaks completion of any IN transfers
* that have already been written to the peripheral, and which we expect to complete
* after resume */
//UDP_DisablePeripheralClock();
}
/**

View File

@@ -163,7 +163,7 @@ extern void EFC_TranslateAddress( Efc** ppEfc, uint32_t dwAddress, uint16_t* pwP
wPage = (dwAddress - IFLASH_ADDR) / IFLASH_PAGE_SIZE;
wOffset = (dwAddress - IFLASH_ADDR) % IFLASH_PAGE_SIZE;
TRACE_DEBUG( "Translated 0x%08X to page=%d and offset=%d\n\r", dwAddress, wPage, wOffset ) ;
TRACE_DEBUG( "Translated 0x%08lX to page=%d and offset=%d\n\r", dwAddress, wPage, wOffset ) ;
/* Store values */
if ( pEfc )
{

View File

@@ -134,7 +134,7 @@ static void ComputeLockRange( uint32_t dwStart, uint32_t dwEnd, uint32_t *pdwAct
// Store actual page numbers
EFC_ComputeAddress( pStartEfc, wActualStartPage, 0, pdwActualStart ) ;
EFC_ComputeAddress( pEndEfc, wActualEndPage, 0, pdwActualEnd ) ;
TRACE_DEBUG( "Actual lock range is 0x%06X - 0x%06X\n\r", *pdwActualStart, *pdwActualEnd ) ;
TRACE_DEBUG( "Actual lock range is 0x%06lX - 0x%06lX\n\r", *pdwActualStart, *pdwActualEnd ) ;
}

View File

@@ -211,6 +211,16 @@ extern void PIO_InitializeInterrupts( uint32_t dwPriority )
NVIC_EnableIRQ( PIOC_IRQn ) ;
}
static InterruptSource *find_intsource4pin(const Pin *pPin)
{
unsigned int i ;
for (i = 0; i < _dwNumSources; i++) {
if (_aIntSources[i].pPin == pPin)
return &_aIntSources[i];
}
return NULL;
}
/**
* Configures a PIO or a group of PIO to generate an interrupt on status
* change. The provided interrupt handler will be called with the triggering
@@ -228,15 +238,17 @@ extern void PIO_ConfigureIt( const Pin *pPin, void (*handler)( const Pin* ) )
assert( pPin ) ;
pio = pPin->pio ;
assert( _dwNumSources < MAX_INTERRUPT_SOURCES ) ;
/* Define new source */
TRACE_DEBUG( "PIO_ConfigureIt: Defining new source #%" PRIu32 ".\n\r", _dwNumSources ) ;
pSource = &(_aIntSources[_dwNumSources]) ;
pSource->pPin = pPin ;
pSource = find_intsource4pin(pPin);
if (!pSource) {
/* Define new source */
TRACE_DEBUG( "PIO_ConfigureIt: Defining new source #%" PRIu32 ".\n\r", _dwNumSources ) ;
assert( _dwNumSources < MAX_INTERRUPT_SOURCES ) ;
pSource = &(_aIntSources[_dwNumSources]) ;
pSource->pPin = pPin ;
_dwNumSources++ ;
}
pSource->handler = handler ;
_dwNumSources++ ;
/* PIO3 with additional interrupt support
* Configure additional interrupt mode registers */

View File

@@ -8,6 +8,11 @@ void EEFC_ReadUniqueID(unsigned int *pdwUniqueID)
{
unsigned int status;
/* disable interrupts, as interrupt vectors are stored in flash,
* and after STUI was issued, we can no longer access flassh until
* SPUI complets */
__disable_irq();
/* Errata / Workaround: Set bit 16 of EEFC Flash Mode Register
* to 1 */
EFC->EEFC_FMR |= (1 << 16);
@@ -40,4 +45,6 @@ void EEFC_ReadUniqueID(unsigned int *pdwUniqueID)
do {
status = EFC->EEFC_FSR;
} while ((status & EEFC_FSR_FRDY) != EEFC_FSR_FRDY);
__enable_irq();
}

View File

@@ -300,7 +300,7 @@ void USBD_SetConfiguration(uint8_t cfgnum)
else {
deviceState = USBD_STATE_ADDRESS;
/* Reset all endpoints */
USBD_HAL_ResetEPs(0xFFFFFFFF, USBD_STATUS_RESET, 0);
USBD_HAL_ResetEPs(0xFFFFFFFE, USBD_STATUS_RESET, 0);
}
}

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, \
}
@@ -124,6 +124,9 @@ void USBDFU_Initialize(const USBDDriverDescriptors *pDescriptors);
/* USBD tells us to switch from DFU mode to application mode */
void USBDFU_SwitchToApp(void);
/* USBD tells us to switch from to DFU mode */
void USBDFU_SwitchToDFU(void);
/* Return values to be used by USBDFU_handle_{dn,up}load */
#define DFU_RET_NOTHING 0
#define DFU_RET_ZLP 1

View File

@@ -19,9 +19,10 @@ enum {
STR_MANUF = 1,
STR_PROD,
STR_CONFIG,
// strings for the first alternate interface (e.g. DFU)
_STR_FIRST_ALT,
// serial string
STR_SERIAL = (_STR_FIRST_ALT+BOARD_DFU_NUM_IF),
STR_SERIAL = (_STR_FIRST_ALT + BOARD_DFU_NUM_IF),
// version string (on additional interface)
VERSION_CONF_STR,
VERSION_STR,
@@ -29,6 +30,25 @@ enum {
STRING_DESC_CNT,
};
/* string used to replace one of both DFU flash partition atlsettings */
static const unsigned char usb_string_notavailable[] = {
USBStringDescriptor_LENGTH(13),
USBGenericDescriptor_STRING,
USBStringDescriptor_UNICODE('n'),
USBStringDescriptor_UNICODE('o'),
USBStringDescriptor_UNICODE('t'),
USBStringDescriptor_UNICODE(' '),
USBStringDescriptor_UNICODE('a'),
USBStringDescriptor_UNICODE('v'),
USBStringDescriptor_UNICODE('a'),
USBStringDescriptor_UNICODE('i'),
USBStringDescriptor_UNICODE('l'),
USBStringDescriptor_UNICODE('a'),
USBStringDescriptor_UNICODE('b'),
USBStringDescriptor_UNICODE('l'),
USBStringDescriptor_UNICODE('e'),
};
/* USB string for the serial (using 128-bit device ID) */
static unsigned char usb_string_serial[] = {
USBStringDescriptor_LENGTH(32),
@@ -121,7 +141,7 @@ static const USBDeviceDescriptor fsDevice = {
.bNumEndpoints = 0, \
.bInterfaceClass = 0xfe, \
.bInterfaceSubClass = 1, \
.iInterface = (_STR_FIRST_ALT+ALT), \
.iInterface = (_STR_FIRST_ALT + ALT), \
.bInterfaceProtocol = 2, \
}
@@ -180,6 +200,11 @@ void set_usb_serial_str(void)
for (i = 0; i < ARRAY_SIZE(usb_strings) && i < ARRAY_SIZE(usb_strings_extended); i++) {
usb_strings_extended[i] = usb_strings[i];
}
#if defined(ENVIRONMENT_dfu)
usb_strings_extended[_STR_FIRST_ALT + 1] = usb_string_notavailable;
#elif defined(ENVIRONMENT_flash)
usb_strings_extended[_STR_FIRST_ALT + 2] = usb_string_notavailable;
#endif
usb_strings_extended[STR_SERIAL] = usb_string_serial;
usb_strings_extended[VERSION_CONF_STR] = usb_string_version_conf;
usb_strings_extended[VERSION_STR] = usb_string_version;

View File

@@ -33,8 +33,7 @@
#include <usb/common/dfu/usb_dfu.h>
#include <usb/device/dfu/dfu.h>
/* FIXME: this was used for a special ELF section which then got called
* by DFU code and Application code, across flash partitions */
/** specific memory location shared across bootloader and application */
#define __dfudata __attribute__ ((section (".dfudata")))
#define __dfufunc
@@ -42,11 +41,14 @@
static USBDDriver usbdDriver;
static unsigned char if_altsettings[1];
/** structure containing the DFU state and magic value to know if DFU or application should be started */
__dfudata struct dfudata _g_dfu = {
.state = DFU_STATE_appIDLE,
.state = DFU_STATE_dfuIDLE,
.past_manifest = 0,
.total_bytes = 0,
};
/** variable to structure containing DFU state */
struct dfudata *g_dfu = &_g_dfu;
WEAK void dfu_drv_updstatus(void)
@@ -83,7 +85,7 @@ static void __dfufunc handle_getstate(void)
{
uint8_t u8 = g_dfu->state;
TRACE_DEBUG("handle_getstate(%u)\n\r", g_dfu->state);
TRACE_DEBUG("handle_getstate(%ld)\n\r", g_dfu->state);
USBD_Write(0, (char *)&u8, sizeof(u8), NULL, 0);
}
@@ -461,7 +463,20 @@ void USBDFU_SwitchToApp(void)
/* make sure the MAGIC is not set to enter DFU again */
g_dfu->magic = 0;
printf("switching to app\r\n");
/* disconnect from USB to ensure re-enumeration */
USBD_Disconnect();
/* disable any interrupts during transition */
__disable_irq();
/* Tell the hybrid to execute FTL JUMP! */
NVIC_SystemReset();
}
void USBDFU_SwitchToDFU(void)
{
/* make sure the MAGIC is not set to enter DFU again */
g_dfu->magic = USB_DFU_MAGIC;
/* disconnect from USB to ensure re-enumeration */
USBD_Disconnect();

View File

@@ -36,7 +36,12 @@
#include <usb/common/dfu/usb_dfu.h>
#include <usb/device/dfu/dfu.h>
struct dfudata *g_dfu = (struct dfudata *) IRAM_ADDR;
/** specific memory location shared across bootloader and application */
#define __dfudata __attribute__ ((section (".dfudata")))
/** structure containing the magic value to know if DFU or application should be started */
__dfudata struct dfudata _g_dfu;
/** variable to structure containing the magic value to know if DFU or application should be started */
struct dfudata *g_dfu = &_g_dfu;
/* FIXME: this was used for a special ELF section which then got called
* by DFU code and Application code, across flash partitions */
@@ -63,7 +68,7 @@ static void __dfufunc handle_getstate(void)
{
uint8_t u8 = g_dfu->state;
TRACE_DEBUG("handle_getstate(%u)\n\r", g_dfu->state);
TRACE_DEBUG("handle_getstate(%lu)\n\r", g_dfu->state);
USBD_Write(0, (char *)&u8, sizeof(u8), NULL, 0);
}
@@ -160,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;
@@ -204,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

@@ -214,6 +214,8 @@ typedef void (*MblTransferCallback)(void *pArg,
* Exported functions
*------------------------------------------------------------------------------*/
extern uint16_t USBD_GetEndpointSize(uint8_t bEndpoint);
//extern void USBD_IrqHandler(void);
extern void USBD_Init(void);

View File

@@ -112,10 +112,13 @@
#define BOARD_USB_UDP
#define BOARD_USB_DFU
#define BOARD_DFU_BOOT_SIZE (16 * 1024)
#define BOARD_DFU_RAM_SIZE (2 * 1024)
#define BOARD_DFU_PAGE_SIZE 512
#define BOARD_DFU_NUM_IF 2
/** number of DFU interfaces (used to flash specific partitions) */
#define BOARD_DFU_NUM_IF 3
extern void board_exec_dbg_cmd(int ch);
extern void board_main_top(void);

View File

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

View File

@@ -39,9 +39,9 @@ SEARCH_DIR(.)
MEMORY
{
/* reserve the first 16k (= 0x4000) for the DFU bootloader */
rom (rx) : ORIGIN = 0x00404000, LENGTH = 0x0003c000 /* flash, 256K */
/* reserve the first 32 (= 0x20) bytes for the _g_dfu struct */
ram (rwx) : ORIGIN = 0x20000020, LENGTH = 0x0000bfe0 /* sram, 48K */
rom (rx) : ORIGIN = 0x00400000 + 16K, LENGTH = 256K - 16K /* flash, 256K */
/* note: dfudata will be at the start */
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 48K /* SRAM, 48K */
}
/* Section Definitions */
@@ -111,6 +111,8 @@ SECTIONS
{
. = ALIGN(4);
_srelocate = .;
/* we must make sure the .dfudata is linked to start of RAM */
*(.dfudata .dfudata.*);
*(.ramfunc .ramfunc.*);
*(.data .data.*);
. = ALIGN(4);

View File

@@ -38,8 +38,8 @@ SEARCH_DIR(.)
/* Memory Spaces Definitions */
MEMORY
{
rom (rx) : ORIGIN = 0x00400000, LENGTH = 0x00040000 /* flash, 256K */
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x0000c000 /* sram, 48K */
rom (rx) : ORIGIN = 0x00400000, LENGTH = 16K /* flash, 256K, but only the first 16K should be used for the bootloader */
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 48K /* SRAM, 48K */
}
/* Section Definitions */

View File

@@ -126,7 +126,7 @@ IntFunc exception_table[] = {
IrqHandlerNotUsed /* 35 not used */
};
#if defined(BOARD_USB_DFU) && defined(APPLICATION_dfu)
#if defined(BOARD_USB_DFU) && defined(APPLICATION_dfu) && defined(ENVIRONMENT_flash)
#include "usb/device/dfu/dfu.h"
static void BootIntoApp(void)
{
@@ -159,8 +159,9 @@ void ResetException( void )
LowLevelInit() ;
#if defined(BOARD_USB_DFU) && defined(APPLICATION_dfu)
if (!USBDFU_OverrideEnterDFU()) {
#if defined(BOARD_USB_DFU) && defined(APPLICATION_dfu) && defined(ENVIRONMENT_flash)
// boot application if there is not DFU override
if (!USBDFU_OverrideEnterDFU() && SCB->VTOR < IFLASH_ADDR + BOARD_DFU_BOOT_SIZE) {
UART_Exit();
__disable_irq();
BootIntoApp();

View File

@@ -218,3 +218,8 @@ void mdelay(unsigned int msecs)
do {
} while ((jiffies - jiffies_start) < msecs);
}
void abort() {
NVIC_SystemReset();
while(1) {};
}

View File

@@ -0,0 +1,107 @@
/* Osmocom ngff-cardem board definition
*
* (C) 2021 by Harald Welte <laforge@osmocom.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
*/
#pragma once
#include "board_common.h"
#include "simtrace_usb.h"
/** Name of the board */
#define BOARD_NAME "NGFF-CARDEM"
/** Board definition */
#define ngff_cardem
/** oscillator used as main clock source (in Hz) */
#define BOARD_MAINOSC 12000000
/** desired main clock frequency (in Hz, based on BOARD_MAINOSC) */
#define BOARD_MCK 58000000 // 12.000 * 29 / 6
/** MCU pin connected to red LED */
#define PIO_LED_RED PIO_PA17
/** MCU pin connected to green LED */
#define PIO_LED_GREEN PIO_PA18
/** red LED pin definition */
#define PIN_LED_RED {PIO_LED_RED, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT}
/** green LED pin definition */
#define PIN_LED_GREEN {PIO_LED_GREEN, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT}
/** LEDs pin definition */
#define PINS_LEDS PIN_LED_RED, PIN_LED_GREEN
/** index for red LED in LEDs pin definition array */
#define LED_NUM_RED 0
/** index for green LED in LEDs pin definition array */
#define LED_NUM_GREEN 1
/** the green LED is actually red and used as indication for USIM1 */
#define LED_USIM1 LED_GREEN
/* USIM 2 interface (USART) */
#define PIN_USIM2_CLK {PIO_PA2, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
#define PIN_USIM2_IO {PIO_PA6, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
#define PINS_ISO7816_USIM2 PIN_USIM2_CLK, PIN_USIM2_IO
/* USIM 2 interface (TC) */
#define PIN_USIM2_IO_TC {PIO_PA1, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
#define PIN_USIM2_CLK_TC {PIO_PA4, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
#define PINS_TC_USIM2 PIN_USIM2_IO_TC, PIN_USIM2_CLK_TC
/* USIM 1 interface (USART) */
#define PIN_USIM1_IO {PIO_PA22, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
#define PIN_USIM1_CLK {PIO_PA23, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
#define PINS_ISO7816_USIM1 PIN_USIM1_CLK, PIN_USIM1_IO
/* USIM 1 interface (TC) */
#define PIN_USIM1_IO_TC {PIO_PA27, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
#define PIN_USIM1_CLK_TC {PIO_PA29, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
#define PINS_TC_USIM1 PIN_USIM1_IO_TC, PIN_USIM1_CLK_TC
#define PIN_USIM1_nRST {PIO_PA24, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT}
#define PIN_USIM1_VCC {PIO_PB2, PIOB, ID_PIOB, PIO_INPUT, PIO_DEFAULT}
#define PIN_USIM2_nRST {PIO_PA7, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT}
//#define PIN_USIM2_VCC {PIO_PB2, PIOB, ID_PIOB, PIO_INPUT, PIO_DEFAULT}
#define PINS_USIM1 PINS_TC_USIM1, PINS_ISO7816_USIM1, PIN_USIM1_nRST
#define PINS_USIM2 PINS_TC_USIM2, PINS_ISO7816_USIM2, PIN_USIM2_nRST
/* from v3 and onwards only (!) */
#define PIN_DET_USIM1_PRES {PIO_PA8, PIOA, ID_PIOA, PIO_INPUT, PIO_PULLUP | PIO_DEGLITCH | PIO_IT_EDGE}
/* inputs reading the WWAN LED level */
#define PIN_WWAN1 {PIO_PA15, PIOA, ID_PIOA, PIO_INPUT, PIO_PULLUP | PIO_DEGLITCH | PIO_IT_EDGE}
#define PINS_WWAN_IN { PIN_WWAN1 }
/* outputs controlling RESET input of modems */
#define PIN_PERST1 {PIO_PA25, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_PULLUP}
#define PINS_PERST { PIN_PERST1 }
#define PIN_VERSION_DET {PIO_PA19, PIOA, ID_PIOA, PIO_PERIPH_D, PIO_DEFAULT}
/* GPIO towards SPDT switches between real SIM and SAM3 */
//#define PIN_SIM_SWITCH1 {PIO_PA20, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
//#define PIN_SIM_SWITCH2 {PIO_PA28, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
#define BOARD_USB_BMATTRIBUTES USBConfigurationDescriptor_SELFPOWERED_NORWAKEUP
#define BOARD_USB_VENDOR_ID USB_VENDOR_OPENMOKO
#define BOARD_USB_PRODUCT_ID USB_PRODUCT_NGFF_CARDEM
#define BOARD_DFU_USB_PRODUCT_ID USB_PRODUCT_NGFF_CARDEM
#define BOARD_USB_RELEASE 0x010
#define DETECT_VCC_BY_ADC
#define VCC_UV_THRESH_1V8 1500000
#define VCC_UV_THRESH_3V 2500000
#define HAVE_CARDEM

View File

@@ -0,0 +1,22 @@
/* card presence utilities
*
* (C) 2016-2017 by Harald Welte <hwelte@hmw-consulting.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#pragma once
int is_card_present(int port);
int card_present_init(void);

View File

@@ -0,0 +1,20 @@
/* Code to read/track the status of the WWAN LEDs of attached modems
*
* 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
*/
#pragma once
int wwan_led_active(int wwan);
int wwan_led_init(void);

View File

@@ -0,0 +1,21 @@
/* Code to control the PERST lines of attached modems
*
* 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
*/
#pragma once
int wwan_perst_set(int modem_nr, int active);
int wwan_perst_do_reset_pulse(int modem_nr, unsigned int duration_ms);
int wwan_perst_init(void);

View File

@@ -0,0 +1 @@
ngff-cardem

View File

@@ -0,0 +1,152 @@
/* sysmocom quad-modem sysmoQMOD application code
*
* (C) 2021 Harald Welte <laforge@osmocom.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 "simtrace.h"
#include "utils.h"
#include "led.h"
#include "wwan_led.h"
#include "wwan_perst.h"
#include "sim_switch.h"
#include "boardver_adc.h"
#include "card_pres.h"
#include <osmocom/core/timer.h>
#include "usb_buf.h"
/* array of generated USB Strings */
extern unsigned char *usb_strings[];
/* returns '1' in case we should break any endless loop */
void board_exec_dbg_cmd(int ch)
{
switch (ch) {
case '?':
printf("\t?\thelp\n\r");
printf("\tR\treset SAM3\n\r");
printf("\tl\tswitch off LED 1\n\r");
printf("\tL\tswitch on LED 1\n\r");
printf("\tg\tswitch off LED 2\n\r");
printf("\tG\tswitch on LED 2\n\r");
printf("\tU\tProceed to USB Initialization\n\r");
printf("\t1\tGenerate 1ms reset pulse on WWAN1\n\r");
printf("\t!\tSwitch Channel A from physical -> remote\n\r");
printf("\t@\tSwitch Channel B from physical -> remote\n\r");
printf("\tt\t(pseudo)talloc report\n\r");
break;
case 'R':
printf("Asking NVIC to reset us\n\r");
USBD_Disconnect();
NVIC_SystemReset();
break;
case 'l':
led_blink(LED_GREEN, BLINK_ALWAYS_OFF);
printf("LED 1 switched off\n\r");
break;
case 'L':
led_blink(LED_GREEN, BLINK_ALWAYS_ON);
printf("LED 1 switched on\n\r");
break;
case 'g':
led_blink(LED_RED, BLINK_ALWAYS_OFF);
printf("LED 2 switched off\n\r");
break;
case 'G':
led_blink(LED_RED, BLINK_ALWAYS_ON);
printf("LED 2 switched on\n\r");
break;
case '1':
printf("Resetting Modem\n\r");
wwan_perst_do_reset_pulse(0, 300);
break;
case '!':
sim_switch_use_physical(0, 0);
break;
case 't':
talloc_report(NULL, stdout);
break;
default:
printf("Unknown command '%c'\n\r", ch);
break;
}
}
void board_main_top(void)
{
#ifndef APPLICATION_dfu
usb_buf_init();
wwan_led_init();
wwan_perst_init();
sim_switch_init();
#endif
/* Obtain the circuit board version (currently just prints voltage */
get_board_version_adc();
#ifndef APPLICATION_dfu
/* Initialize checking for card insert/remove events */
card_present_init();
#endif
}
static int uart_has_loopback_jumper(void)
{
unsigned int i;
const Pin uart_loopback_pins[] = {
{PIO_PA9A_URXD0, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT},
{PIO_PA10A_UTXD0, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
};
/* Configure UART pins as I/O */
PIO_Configure(uart_loopback_pins, PIO_LISTSIZE(uart_loopback_pins));
/* Send pattern over UART TX and check if it is received on RX
* If the loop doesn't get interrupted, RxD always follows TxD and thus a
* loopback jumper has been placed on RxD/TxD, and we will boot
* into DFU unconditionally
*/
int has_loopback_jumper = 1;
for (i = 0; i < 10; i++) {
/* Set TxD high; abort if RxD doesn't go high either */
PIO_Set(&uart_loopback_pins[1]);
if (!PIO_Get(&uart_loopback_pins[0])) {
has_loopback_jumper = 0;
break;
}
/* Set TxD low, abort if RxD doesn't go low either */
PIO_Clear(&uart_loopback_pins[1]);
if (PIO_Get(&uart_loopback_pins[0])) {
has_loopback_jumper = 0;
break;
}
}
/* Put pins back to UART mode */
const Pin uart_pins[] = {PINS_UART};
PIO_Configure(uart_pins, PIO_LISTSIZE(uart_pins));
return has_loopback_jumper;
}
int board_override_enter_dfu(void)
{
/* If the loopback jumper is set, we enter DFU mode */
if (uart_has_loopback_jumper())
return 1;
return 0;
}

View File

@@ -0,0 +1,76 @@
/* card presence utilities
*
* (C) 2016-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 <osmocom/core/timer.h>
#include "board.h"
#include "utils.h"
#include "card_pres.h"
#define NUM_CARDPRES 1
#define TIMER_INTERVAL_MS 500
static const Pin pin_cardpres[NUM_CARDPRES] = { PIN_DET_USIM1_PRES };
static int last_state[NUM_CARDPRES] = { -1 };
static struct osmo_timer_list cardpres_timer;
/* Determine if a SIM card is present in the given slot */
int is_card_present(int port)
{
const Pin *pin;
int present;
if (port < 0 || port >= NUM_CARDPRES)
return -1;
pin = &pin_cardpres[port];
/* Card present signals are low-active, as we have a switch
* against GND and an internal-pull-up in the SAM3 */
present = PIO_Get(pin) ? 0 : 1;
return present;
}
static void cardpres_tmr_cb(void *data)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(pin_cardpres); i++) {
int state = is_card_present(i);
if (state != last_state[i]) {
TRACE_INFO("%u: Card Detect Status %d -> %d\r\n", i, last_state[i], state);
/* FIXME: report to USB host */
last_state[i] = state;
}
}
osmo_timer_schedule(&cardpres_timer, 0, TIMER_INTERVAL_MS*1000);
}
int card_present_init(void)
{
unsigned int i;
PIO_Configure(pin_cardpres, ARRAY_SIZE(pin_cardpres));
/* start timer */
cardpres_timer.cb = cardpres_tmr_cb;
osmo_timer_schedule(&cardpres_timer, 0, TIMER_INTERVAL_MS*1000);
return 2;
}

View File

@@ -0,0 +1,93 @@
/* Code to read/track the status of the WWAN LEDs of attached modems
*
* 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
*/
/* Depending on the board this is running on, it might be possible
* for the controller to read the status of the WWAN LED output lines of
* the cellular modem. If the board supports this, it sets the
* PIN_WWAN1 and/or PIN_WWAN2 defines in its board.h file.
*/
#include "board.h"
#include "wwan_led.h"
#ifdef PIN_WWAN1
static const Pin pin_wwan1 = PIN_WWAN1;
static void wwan1_irqhandler(const Pin *pPin)
{
int active = wwan_led_active(0);
TRACE_INFO("0: WWAN LED %u\r\n", active);
/* TODO: notify host via USB */
}
#endif
#ifdef PIN_WWAN2
static const Pin pin_wwan2 = PIN_WWAN2;
static void wwan2_irqhandler(const Pin *pPin)
{
int active = wwan_led_active(1);
TRACE_INFO("1: WWAN LED %u\r\n", active);
/* TODO: notify host via USB */
}
#endif
/* determine if a tiven WWAN led is currently active or not */
int wwan_led_active(int wwan)
{
const Pin *pin;
int active;
switch (wwan) {
#ifdef PIN_WWAN1
case 0:
pin = &pin_wwan1;
break;
#endif
#ifdef PIN_WWAN2
case 1:
pin = &pin_wwan2;
break;
#endif
default:
return -1;
}
active = PIO_Get(pin) ? 0 : 1;
return active;
}
int wwan_led_init(void)
{
int num_leds = 0;
#ifdef PIN_WWAN1
PIO_Configure(&pin_wwan1, 1);
PIO_ConfigureIt(&pin_wwan1, wwan1_irqhandler);
PIO_EnableIt(&pin_wwan1);
num_leds++;
#endif
#ifdef PIN_WWAN2
PIO_Configure(&pin_wwan2, 1);
PIO_ConfigureIt(&pin_wwan2, wwan2_irqhandler);
PIO_EnableIt(&pin_wwan2);
num_leds++;
#endif
return num_leds;
}

View File

@@ -0,0 +1,127 @@
/* Code to control the PERST lines of attached modems
*
* 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
*/
/* Depending on the board this is running on, it might be possible
* for the controller to set the status of the PERST input line of
* the cellular modem. If the board supports this, it sets the
* PIN_PERST1 and/or PIN_PERST2 defines in its board.h file.
*/
#include "board.h"
#include "trace.h"
#include "wwan_perst.h"
#include <osmocom/core/timer.h>
struct wwan_perst {
uint8_t idx;
const Pin pin;
struct osmo_timer_list timer;
};
#ifdef PIN_PERST1
static struct wwan_perst perst1 = {
.idx = 0,
.pin = PIN_PERST1,
};
#endif
#ifdef PIN_PERST2
static struct wwan_perst perst2 = {
.idx = 1,
.pin = PIN_PERST2,
};
#endif
static int initialized = 0;
static void perst_tmr_cb(void *data)
{
struct wwan_perst *perst = data;
/* release the (low-active) reset */
TRACE_INFO("%u: De-asserting modem reset\r\n", perst->idx);
PIO_Clear(&perst->pin);
}
static struct wwan_perst *get_perst_for_modem(int modem_nr)
{
if (!initialized) {
TRACE_ERROR("Somebody forgot to call wwan_perst_init()\r\n");
wwan_perst_init();
}
switch (modem_nr) {
#ifdef PIN_PERST1
case 0:
return &perst1;
#endif
#ifdef PIN_PERST2
case 1:
return &perst2;
#endif
default:
return NULL;
}
}
int wwan_perst_do_reset_pulse(int modem_nr, unsigned int duration_ms)
{
struct wwan_perst *perst = get_perst_for_modem(modem_nr);
if (!perst)
return -1;
TRACE_INFO("%u: Asserting modem reset\r\n", modem_nr);
PIO_Set(&perst->pin);
osmo_timer_schedule(&perst->timer, duration_ms/1000, (duration_ms%1000)*1000);
return 0;
}
int wwan_perst_set(int modem_nr, int active)
{
struct wwan_perst *perst = get_perst_for_modem(modem_nr);
if (!perst)
return -1;
osmo_timer_del(&perst->timer);
if (active) {
TRACE_INFO("%u: Asserting modem reset\r\n", modem_nr);
PIO_Set(&perst->pin);
} else {
TRACE_INFO("%u: De-asserting modem reset\r\n", modem_nr);
PIO_Clear(&perst->pin);
}
return 0;
}
int wwan_perst_init(void)
{
int num_perst = 0;
#ifdef PIN_PERST1
PIO_Configure(&perst1.pin, 1);
perst1.timer.cb = perst_tmr_cb;
perst1.timer.data = (void *) &perst1;
num_perst++;
#endif
#ifdef PIN_PERST2
PIO_Configure(&perst2.pin, 1);
perst2.timer.cb = perst_tmr_cb;
perst2.timer.data = (void *) &perst2;
num_perst++;
#endif
initialized = 1;
return num_perst;
}

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

@@ -0,0 +1,90 @@
/* Code to switch between local (physical) and remote (emulated) SIM
*
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#include "board.h"
#include "trace.h"
#include "led.h"
#include "sim_switch.h"
#ifdef PIN_SIM_SWITCH1
static const Pin pin_conn_usim1 = {PIO_PA20, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT};
#endif
#ifdef PIN_SIM_SWITCH2
static const Pin pin_conn_usim2 = {PIO_PA28, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT};
#endif
static int initialized = 0;
int sim_switch_use_physical(unsigned int nr, int physical)
{
const Pin *pin;
enum led led;
if (!initialized) {
TRACE_ERROR("Somebody forgot to call sim_switch_init()\r\n");
sim_switch_init();
}
TRACE_INFO("Modem %d: %s SIM\n\r", nr,
physical ? "physical" : "virtual");
switch (nr) {
#ifdef PIN_SIM_SWITCH1
case 0:
pin = &pin_conn_usim1;
led = LED_USIM1;
break;
#endif
#ifdef PIN_SIM_SWITCH2
case 1:
pin = &pin_conn_usim2;
led = LED_USIM2;
break;
#endif
default:
TRACE_ERROR("Invalid SIM%u\n\r", nr);
return -1;
}
if (physical) {
TRACE_INFO("%u: Use local/physical SIM\r\n", nr);
PIO_Clear(pin);
led_blink(led, BLINK_ALWAYS_ON);
} else {
TRACE_INFO("%u: Use remote/emulated SIM\r\n", nr);
PIO_Set(pin);
led_blink(led, BLINK_ALWAYS_OFF);
}
return 0;
}
int sim_switch_init(void)
{
int num_switch = 0;
#ifdef PIN_SIM_SWITCH1
PIO_Configure(&pin_conn_usim1, 1);
num_switch++;
#endif
#ifdef PIN_SIM_SWITCH2
PIO_Configure(&pin_conn_usim2, 1);
num_switch++;
#endif
initialized = 1;
return num_switch;
}

View File

@@ -109,6 +109,9 @@
#define BOARD_USB_RELEASE 0x010
#define CARDEMU_SECOND_UART
#define DETECT_VCC_BY_ADC
#define VCC_UV_THRESH_1V8 1500000
#define VCC_UV_THRESH_3V 2500000
#define HAVE_CARDEM

View File

@@ -194,7 +194,7 @@ void board_exec_dbg_cmd(int ch)
this is done to prevent accidental ERASE on noisy serial input since only one character can trigger the ERASE.
*/
static bool allow_erase = false;
#endif
#endif /* ALLOW_PEER_ERASE */
switch (ch) {
case '?':
@@ -205,13 +205,17 @@ void board_exec_dbg_cmd(int ch)
printf("\tg\tswitch off LED 2\n\r");
printf("\tG\tswitch off LED 2\n\r");
if (qmod_sam3_is_12()) {
#if (ALLOW_PEER_ERASE > 0)
printf("\tE\tprogram EEPROM\n\r");
printf("\te\tErase EEPROM\n\r");
#endif /* ALLOW_PEER_ERASE */
printf("\tO\tEnable PRTPWR_OVERRIDE\n\r");
printf("\to\tDisable PRTPWR_OVERRIDE\n\r");
#if (ALLOW_PEER_ERASE > 0)
printf("\tH\tRelease HUB RESET (high)\n\r");
printf("\th\tAssert HUB RESET (low)\n\r");
printf("\tw\tWrite single byte in EEPROM\n\r");
#endif /* ALLOW_PEER_ERASE */
printf("\tr\tRead single byte from EEPROM\n\r");
}
printf("\tX\tRelease peer SAM3 from reset\n\r");
@@ -220,10 +224,13 @@ void board_exec_dbg_cmd(int ch)
printf("\tY\tRelease peer SAM3 ERASE signal\n\r");
printf("\ta\tAllow asserting peer SAM3 ERASE signal\n\r");
printf("\ty\tAssert peer SAM3 ERASE signal\n\r");
#endif
#endif /* ALLOW_PEER_ERASE */
printf("\tU\tProceed to USB Initialization\n\r");
printf("\t1\tGenerate 1ms reset pulse on WWAN1\n\r");
printf("\t2\tGenerate 1ms reset pulse on WWAN2\n\r");
printf("\t!\tSwitch Channel A from physical -> remote\n\r");
printf("\t@\tSwitch Channel B from physical -> remote\n\r");
printf("\tt\t(pseudo)talloc report\n\r");
break;
case 'R':
printf("Asking NVIC to reset us\n\r");
@@ -271,7 +278,7 @@ void board_exec_dbg_cmd(int ch)
printf("Please first allow setting SIMTRACExx_ERASE\n\r");
}
break;
#endif
#endif /* ALLOW_PEER_ERASE */
case '1':
printf("Resetting Modem 1 (of this SAM3)\n\r");
wwan_perst_do_reset_pulse(0, 300);
@@ -286,6 +293,9 @@ void board_exec_dbg_cmd(int ch)
case '@':
sim_switch_use_physical(0, 0);
break;
case 't':
talloc_report(NULL, stdout);
break;
default:
if (!qmod_sam3_is_12())
printf("Unknown command '%c'\n\r", ch);
@@ -299,7 +309,7 @@ void board_exec_dbg_cmd(int ch)
if ('a' != ch) {
allow_erase = false;
}
#endif
#endif /* ALLOW_PEER_ERASE */
}
void board_main_top(void)

View File

@@ -0,0 +1,90 @@
/* Code to switch between local (physical) and remote (emulated) SIM
*
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#include "board.h"
#include "trace.h"
#include "led.h"
#include "sim_switch.h"
#ifdef PIN_SIM_SWITCH1
static const Pin pin_conn_usim1 = {PIO_PA20, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT};
#endif
#ifdef PIN_SIM_SWITCH2
static const Pin pin_conn_usim2 = {PIO_PA28, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT};
#endif
static int initialized = 0;
int sim_switch_use_physical(unsigned int nr, int physical)
{
const Pin *pin;
enum led led;
if (!initialized) {
TRACE_ERROR("Somebody forgot to call sim_switch_init()\r\n");
sim_switch_init();
}
TRACE_INFO("Modem %d: %s SIM\n\r", nr,
physical ? "physical" : "virtual");
switch (nr) {
#ifdef PIN_SIM_SWITCH1
case 0:
pin = &pin_conn_usim1;
led = LED_USIM1;
break;
#endif
#ifdef PIN_SIM_SWITCH2
case 1:
pin = &pin_conn_usim2;
led = LED_USIM2;
break;
#endif
default:
TRACE_ERROR("Invalid SIM%u\n\r", nr);
return -1;
}
if (physical) {
TRACE_INFO("%u: Use local/physical SIM\r\n", nr);
PIO_Clear(pin);
led_blink(led, BLINK_ALWAYS_ON);
} else {
TRACE_INFO("%u: Use remote/emulated SIM\r\n", nr);
PIO_Set(pin);
led_blink(led, BLINK_ALWAYS_OFF);
}
return 0;
}
int sim_switch_init(void)
{
int num_switch = 0;
#ifdef PIN_SIM_SWITCH1
PIO_Configure(&pin_conn_usim1, 1);
num_switch++;
#endif
#ifdef PIN_SIM_SWITCH2
PIO_Configure(&pin_conn_usim2, 1);
num_switch++;
#endif
initialized = 1;
return num_switch;
}

View File

@@ -78,11 +78,11 @@
/* 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_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}
#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_PHONE_IO, PIN_PHONE_CLK, PIN_PHONE_CLK_INPUT, PIN_USIM1_VCC, PIN_PHONE_IO_INPUT, PIN_USIM1_nRST
#define PINS_USIM1 PIN_USIM1_IO, PIN_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) */
@@ -153,10 +153,14 @@
/** Supported modes */
/* SIMtrace board supports sniffer mode */
#ifdef APPLICATION_trace
#define HAVE_SNIFFER
#endif
/* SIMtrace board supports CCID mode */
//#define HAVE_CCID
/* SIMtrace board supports card emulation mode */
//#define HAVE_CARDEM
#ifdef APPLICATION_cardem
#define HAVE_CARDEM
#endif
/* SIMtrace board supports man-in-the-middle mode */
//#define HAVE_MITM

View File

@@ -0,0 +1,54 @@
/* Code to switch between local (physical) and remote (emulated) SIM
*
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
* (C) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#include "board.h"
#include "trace.h"
#include "led.h"
#include "sim_switch.h"
int sim_switch_use_physical(unsigned int nr, int physical)
{
const Pin pin_sc = PIN_SC_SW_DEFAULT; // pin to control bus switch for VCC/RST/CLK signals
const Pin pin_io = PIN_IO_SW_DEFAULT; // pin to control bus switch for I/O signal
if (nr > 0) {
TRACE_ERROR("SIM interface for Modem %d can't be switched\r\n", nr);
return -1;
}
TRACE_INFO("Modem %u: %s SIM\n\r", nr, physical ? "physical" : "virtual");
if (physical) {
TRACE_INFO("%u: Use local/physical SIM\r\n", nr);
PIO_Set(&pin_sc);
PIO_Set(&pin_io);
} else {
TRACE_INFO("%u: Use remote/emulated SIM\r\n", nr);
PIO_Clear(&pin_sc);
PIO_Clear(&pin_io);
}
return 0;
}
int sim_switch_init(void)
{
// the bus switch is already initialised
return 1; // SIMtrace hardware has only one switchable interface
}

View File

@@ -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);
@@ -56,13 +55,24 @@ int card_emu_set_atr(struct card_handle *ch, const uint8_t *atr, uint8_t len);
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);
void card_emu_report_status(struct card_handle *ch, bool report_on_irq);
#define ENABLE_TX 0x01
#define ENABLE_RX 0x02
void card_emu_wtime_half_expired(void *ch);
void card_emu_wtime_expired(void *ch);
#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);
void card_emu_uart_update_wt(uint8_t uart_chan, uint32_t wt);
void card_emu_uart_reset_wt(uint8_t uart_chan);
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);
void card_emu_uart_interrupt(uint8_t uart_chan);
struct cardemu_usb_msg_config;
int card_emu_set_config(struct card_handle *ch, const struct cardemu_usb_msg_config *scfg,
unsigned int scfg_len);

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

@@ -0,0 +1,3 @@
#pragma once
void print_banner(void);

View File

@@ -21,7 +21,7 @@
#include <stdbool.h>
#include <sys/types.h>
#define RING_BUFLEN 512
#define RING_BUFLEN 1024
typedef struct ringbuf {
uint8_t buf[RING_BUFLEN];

View File

@@ -62,6 +62,8 @@ enum simtrace_msg_type_cardem {
SIMTRACE_MSGT_DO_CEMU_RX_DATA,
/* Indicate PTS request from phone */
SIMTRACE_MSGT_DO_CEMU_PTS,
/* Set configurable parameters */
SIMTRACE_MSGT_BD_CEMU_CONFIG,
};
/* SIMTRACE_MSGC_MODEM */
@@ -228,11 +230,17 @@ struct cardemu_usb_msg_status {
uint32_t flags;
/* phone-applied target voltage in mV */
uint16_t voltage_mv;
/* Fi/Di related information */
uint8_t fi;
uint8_t di;
uint8_t wi;
uint32_t waiting_time;
/* 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 */
@@ -254,6 +262,17 @@ struct cardemu_usb_msg_error {
uint8_t msg[0];
} __attribute__ ((packed));
/* enable/disable the generation of DO_STATUS on IRQ endpoint */
#define CEMU_FEAT_F_STATUS_IRQ 0x00000001
/* SIMTRACE_MSGT_BD_CEMU_CONFIG */
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));
/***********************************************************************
* MODEM CONTROL
***********************************************************************/

View File

@@ -25,6 +25,8 @@
#define USB_PRODUCT_QMOD_SAM3 0x4004
#define USB_PRODUCT_SIMTRACE2_DFU 0x60e3 /* was 0x60e2 */
#define USB_PRODUCT_SIMTRACE2 0x60e3
#define USB_PRODUCT_OCTSIMTEST 0x616d
#define USB_PRODUCT_NGFF_CARDEM 0x616e
/* USB proprietary class */
#define USB_CLASS_PROPRIETARY 0xff
@@ -64,4 +66,4 @@
#define SIMTRACE_CARDEM_USB_EP_USIM2_INT 3
/*! Maximum number of endpoints */
#define BOARD_USB_NUMENDPOINTS 6
#define BOARD_USB_NUMENDPOINTS 7 /* 0 (control) + 2 (interfaces) * 3 (endpoints) */

View File

@@ -17,6 +17,7 @@
#pragma once
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
/* minimalistic emulation of core talloc API functions used by msgb.c */
@@ -39,3 +40,4 @@ void *talloc_named_const(const void *context, size_t size, const char *name);
void talloc_set_name_const(const void *ptr, const char *name);
char *talloc_strdup(const void *t, const char *p);
void *talloc_pool(const void *context, size_t size);
void talloc_report(const void *ptr, FILE *f);

View File

@@ -29,6 +29,8 @@ struct usb_buffered_ep {
volatile uint32_t in_progress;
/* Tx queue (IN) / Rx queue (OUT) */
struct llist_head queue;
/* current length of queue */
unsigned int queue_len;
};
struct msgb *usb_buf_alloc(uint8_t ep);

View File

@@ -1,6 +1,6 @@
/* ISO7816-3 state machine for the card side
*
* (C) 2010-2017 by Harald Welte <laforge@gnumonks.org>
* (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
@@ -27,16 +27,21 @@
#include "utils.h"
#include "trace.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
/* bit-mask of supported CEMU_FEAT_F_ flags */
#define SUPPORTED_FEATURES (CEMU_FEAT_F_STATUS_IRQ)
#define ISO7816_3_INIT_WTIME 9600
#define ISO7816_3_DEFAULT_WI 10
#define ISO7816_3_ATR_LEN_MAX (1+32) /* TS plus 32 chars */
@@ -55,42 +60,15 @@ enum iso7816_3_card_state {
};
const struct value_string iso7816_3_card_state_names[] = {
{
.value = ISO_S_WAIT_POWER,
.str = "WAIT_POWER",
},
{
.value = ISO_S_WAIT_CLK,
.str = "WAIT_CLK",
},
{
.value = ISO_S_WAIT_RST,
.str = "WAIT_RST",
},
{
.value = ISO_S_WAIT_ATR,
.str = "WAIT_ATR",
},
{
.value = ISO_S_IN_ATR,
.str = "IN_ATR",
},
{
.value = ISO_S_IN_PTS,
.str = "IN_PTS",
},
{
.value = ISO_S_WAIT_TPDU,
.str = "WAIT_TPDU",
},
{
.value = ISO_S_IN_TPDU,
.str = "IN_TPDU",
},
{
.value = 0,
.str = NULL,
},
{ ISO_S_WAIT_POWER, "WAIT_POWER" },
{ ISO_S_WAIT_CLK, "WAIT_CLK" },
{ ISO_S_WAIT_RST, "WAIT_RST" },
{ ISO_S_WAIT_ATR, "WAIT_ATR" },
{ ISO_S_IN_ATR, "IN_ATR" },
{ ISO_S_IN_PTS, "IN_PTS" },
{ ISO_S_WAIT_TPDU, "WAIT_TPDU" },
{ ISO_S_IN_TPDU, "IN_TPDU" },
{ 0, NULL }
};
@@ -110,6 +88,22 @@ enum pts_state {
PTS_S_WAIT_RESP_PCK = PTS_S_WAIT_REQ_PCK | 0x10,
};
const struct value_string pts_state_names[] = {
{ PTS_S_WAIT_REQ_PTSS, "WAIT_REQ_PTSS" },
{ PTS_S_WAIT_REQ_PTS0, "WAIT_REQ_PTS0" },
{ PTS_S_WAIT_REQ_PTS1, "WAIT_REQ_PTS1" },
{ PTS_S_WAIT_REQ_PTS2, "WAIT_REQ_PTS2" },
{ PTS_S_WAIT_REQ_PTS3, "WAIT_REQ_PTS3" },
{ PTS_S_WAIT_REQ_PCK, "WAIT_REQ_PCK" },
{ PTS_S_WAIT_RESP_PTSS, "WAIT_RESP_PTSS" },
{ PTS_S_WAIT_RESP_PTS0, "WAIT_RESP_PTS0" },
{ PTS_S_WAIT_RESP_PTS1, "WAIT_RESP_PTS1" },
{ PTS_S_WAIT_RESP_PTS2, "WAIT_RESP_PTS2" },
{ PTS_S_WAIT_RESP_PTS3, "WAIT_RESP_PTS3" },
{ PTS_S_WAIT_RESP_PCK, "WAIT_RESP_PCK" },
{ 0, NULL }
};
/* PTS field byte index */
#define _PTSS 0
#define _PTS0 1
@@ -131,42 +125,15 @@ enum tpdu_state {
};
const struct value_string tpdu_state_names[] = {
{
.value = TPDU_S_WAIT_CLA,
.str = "WAIT_CLA",
},
{
.value = TPDU_S_WAIT_INS,
.str = "WAIT_INS",
},
{
.value = TPDU_S_WAIT_P1,
.str = "WAIT_P1",
},
{
.value = TPDU_S_WAIT_P2,
.str = "WAIT_P2",
},
{
.value = TPDU_S_WAIT_P3,
.str = "WAIT_P3",
},
{
.value = TPDU_S_WAIT_PB,
.str = "WAIT_PB",
},
{
.value = TPDU_S_WAIT_RX,
.str = "WAIT_RX",
},
{
.value = TPDU_S_WAIT_TX,
.str = "WAIT_TX",
},
{
.value = 0,
.str = NULL,
},
{ TPDU_S_WAIT_CLA, "WAIT_CLA" },
{ TPDU_S_WAIT_INS, "WAIT_INS" },
{ TPDU_S_WAIT_P1, "WAIT_P1" },
{ TPDU_S_WAIT_P2, "WAIT_P2" },
{ TPDU_S_WAIT_P3, "WAIT_P3" },
{ TPDU_S_WAIT_PB, "WAIT_PB" },
{ TPDU_S_WAIT_RX, "WAIT_RX" },
{ TPDU_S_WAIT_TX, "WAIT_TX" },
{ 0, NULL }
};
/* TPDU field byte index */
@@ -179,6 +146,9 @@ const struct value_string tpdu_state_names[] = {
struct card_handle {
unsigned int num;
/* bit-mask of enabled optional features (CEMU_FEAT_F_*) */
uint32_t features;
enum iso7816_3_card_state state;
/* signal levels */
@@ -186,19 +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) */
/* timing parameters, from PTS */
uint8_t fi;
uint8_t di;
/* 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;
uint8_t tc_chan; /* TC channel number */
/*! 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 */
uint32_t waiting_time; /* in clocks */
/* ATR state machine */
struct {
uint8_t idx;
@@ -233,6 +218,27 @@ struct card_handle {
} stats;
};
/* reset all the 'dynamic' state of the card handle to the initial/default values */
static void card_handle_reset(struct card_handle *ch)
{
struct msgb *msg;
card_emu_uart_update_wt(ch->uart_chan, 0);
/* release any buffers we may still own */
if (ch->uart_tx_msg) {
usb_buf_free(ch->uart_tx_msg);
ch->uart_tx_msg = NULL;
}
if (ch->uart_rx_msg) {
usb_buf_free(ch->uart_rx_msg);
ch->uart_rx_msg = NULL;
}
while ((msg = msgb_dequeue(&ch->uart_tx_queue))) {
usb_buf_free(msg);
}
}
struct llist_head *card_emu_get_uart_tx_queue(struct card_handle *ch)
{
return &ch->uart_tx_queue;
@@ -260,18 +266,18 @@ struct msgb *usb_buf_alloc_st(uint8_t ep, uint8_t msg_class, uint8_t msg_type)
while (!msg) {
msg = usb_buf_alloc(ep); // try to allocate some memory
if (!msg) { // allocation failed, we might be out of memory
struct llist_head *queue = usb_get_queue(ep);
if (!queue) {
struct usb_buffered_ep *bep = usb_get_buf_ep(ep);
if (!bep) {
TRACE_ERROR("ep %u: %s queue does not exist\n\r",
ep, __func__);
return NULL;
}
if (llist_empty(queue)) {
if (llist_empty(&bep->queue)) {
TRACE_ERROR("ep %u: %s EOMEM (queue already empty)\n\r",
ep, __func__);
return NULL;
}
msg = msgb_dequeue(queue);
msg = msgb_dequeue_count(&bep->queue, &bep->queue_len);
if (!msg) {
TRACE_ERROR("ep %u: %s no msg in non-empty queue\n\r",
ep, __func__);
@@ -372,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);
}
@@ -403,26 +407,23 @@ static void card_set_state(struct card_handle *ch,
case ISO_S_WAIT_RST:
/* disable Rx and Tx of UART */
card_emu_uart_enable(ch->uart_chan, 0);
/* check end activation state (only necessary if the reader to not respect the activation sequence) */
if (ch->vcc_active && ch->clocked && !ch->in_reset) {
/* enable the TC/ETU counter once reset has been released */
tc_etu_enable(ch->tc_chan);
/* prepare to send the ATR */
card_set_state(ch, ISO_S_WAIT_ATR);
}
/* disable timeout */
card_emu_uart_update_wt(ch->uart_chan, 0);
break;
case ISO_S_WAIT_ATR:
/* Reset to initial Fi / Di ratio */
ch->fi = 1;
ch->di = 1;
ch->Fi_index = ch->F_index = 1;
ch->Di_index = ch->D_index = 1;
ch->wi = ISO7816_3_DEFAULT_WI;
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 tc_etu mechanism to wait this time.
* 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.
*/
tc_etu_set_wtime(ch->tc_chan, 2);
/* ensure the TC_ETU timer is enabled */
tc_etu_enable(ch->tc_chan);
card_emu_uart_update_wt(ch->uart_chan, 2);
break;
case ISO_S_IN_ATR:
/* initialize to default WI, this will be overwritten if we
@@ -432,7 +433,7 @@ static void card_set_state(struct card_handle *ch,
/* update waiting time to initial waiting time */
ch->waiting_time = ISO7816_3_INIT_WTIME;
/* set initial waiting time */
tc_etu_set_wtime(ch->tc_chan, ch->waiting_time);
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 */
@@ -507,11 +508,11 @@ static int tx_byte_atr(struct card_handle *ch)
}
}
}
/* update waiting time (see ISO 7816-3 10.2) */
ch->waiting_time = ch->wi * 960 * ch->fi;
tc_etu_set_wtime(ch->tc_chan, ch->waiting_time);
/* reset PTS to initial state */
set_pts_state(ch, PTS_S_WAIT_REQ_PTSS);
/* 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;
@@ -528,8 +529,9 @@ static int tx_byte_atr(struct card_handle *ch)
/* Update the PTS sub-state */
static void set_pts_state(struct card_handle *ch, enum pts_state new_ptss)
{
TRACE_DEBUG("%u: 7816 PTS state %u -> %u\r\n",
ch->num, ch->pts.state, new_ptss);
TRACE_DEBUG("%u: 7816 PTS state %s -> %s\r\n", ch->num,
get_value_string(pts_state_names, ch->pts.state),
get_value_string(pts_state_names, new_ptss));
ch->pts.state = new_ptss;
}
@@ -609,8 +611,8 @@ process_byte_pts(struct card_handle *ch, uint8_t byte)
memcpy(ch->pts.resp, ch->pts.req, sizeof(ch->pts.resp));
break;
default:
TRACE_ERROR("%u: process_byte_pts() in invalid state %u\r\n",
ch->num, ch->pts.state);
TRACE_ERROR("%u: process_byte_pts() in invalid PTS state %s\r\n", ch->num,
get_value_string(pts_state_names, ch->pts.state));
break;
}
/* calculate the next state and set it */
@@ -645,10 +647,11 @@ static int tx_byte_pts(struct card_handle *ch)
case PTS_S_WAIT_RESP_PTS1:
byte = ch->pts.resp[_PTS1];
/* This must be TA1 */
ch->fi = byte >> 4;
ch->di = byte & 0xf;
TRACE_DEBUG("%u: found Fi=%u Di=%u\r\n", ch->num,
ch->fi, ch->di);
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];
@@ -660,8 +663,8 @@ static int tx_byte_pts(struct card_handle *ch)
byte = ch->pts.resp[_PCK];
break;
default:
TRACE_ERROR("%u: get_byte_pts() in invalid state %u\r\n",
ch->num, ch->pts.state);
TRACE_ERROR("%u: get_byte_pts() in invalid PTS state %s\r\n", ch->num,
get_value_string(pts_state_names, ch->pts.state));
return 0;
}
@@ -673,7 +676,7 @@ 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);
/* update baud rate generator with Fi/Di */
/* update baud rate generator with F/D */
emu_update_fidi(ch);
/* Wait for the next TPDU */
card_set_state(ch, ISO_S_WAIT_TPDU);
@@ -753,14 +756,28 @@ static void set_tpdu_state(struct card_handle *ch, enum tpdu_state new_ts)
switch (new_ts) {
case TPDU_S_WAIT_CLA:
case TPDU_S_WAIT_RX:
/* 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:
/* 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:
/* 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:
/* 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;
@@ -867,8 +884,8 @@ process_byte_tpdu(struct card_handle *ch, uint8_t byte)
add_tpdu_byte(ch, byte);
break;
default:
TRACE_ERROR("%u: process_byte_tpdu() in invalid state %u\r\n",
ch->num, ch->tpdu.state);
TRACE_ERROR("%u: process_byte_tpdu() in invalid TPDU state %s\r\n", ch->num,
get_value_string(tpdu_state_names, ch->tpdu.state));
}
/* ensure we stay in TPDU ISO state */
@@ -955,6 +972,8 @@ void card_emu_process_rx_byte(struct card_handle *ch, uint8_t byte)
switch (ch->state) {
case ISO_S_WAIT_TPDU:
if (byte == 0xff) {
/* reset PTS to initial state */
set_pts_state(ch, PTS_S_WAIT_REQ_PTSS);
new_state = process_byte_pts(ch, byte);
ch->stats.pps++;
goto out_silent;
@@ -967,8 +986,8 @@ void card_emu_process_rx_byte(struct card_handle *ch, uint8_t byte)
new_state = process_byte_pts(ch, byte);
goto out_silent;
default:
TRACE_ERROR("%u: Received UART char in invalid 7816 state "
"%u\r\n", ch->num, ch->state);
TRACE_ERROR("%u: Received UART char in invalid 7816 state %s\r\n", ch->num,
get_value_string(iso7816_3_card_state_names, ch->state));
break;
}
@@ -1021,13 +1040,16 @@ void card_emu_have_new_uart_tx(struct card_handle *ch)
}
}
void card_emu_report_status(struct card_handle *ch)
void card_emu_report_status(struct card_handle *ch, bool report_on_irq)
{
struct msgb *msg;
struct cardemu_usb_msg_status *sts;
uint8_t ep = ch->in_ep;
msg = usb_buf_alloc_st(ch->in_ep, SIMTRACE_MSGC_CARDEM,
SIMTRACE_MSGT_BD_CEMU_STATUS);
if (report_on_irq)
ep = ch->irq_ep;
msg = usb_buf_alloc_st(ep, SIMTRACE_MSGC_CARDEM, SIMTRACE_MSGT_BD_CEMU_STATUS);
if (!msg)
return;
@@ -1040,26 +1062,52 @@ void card_emu_report_status(struct card_handle *ch)
if (ch->in_reset)
sts->flags |= CEMU_STATUS_F_RESET_ACTIVE;
/* FIXME: voltage + card insert */
sts->fi = ch->fi;
sts->di = ch->di;
sts->F_index = ch->F_index;
sts->D_index = ch->D_index;
sts->wi = ch->wi;
sts->waiting_time = ch->waiting_time;
usb_buf_upd_len_and_submit(msg);
}
static void card_emu_report_config(struct card_handle *ch)
{
struct msgb *msg;
struct cardemu_usb_msg_config *cfg;
uint8_t ep = ch->in_ep;
msg = usb_buf_alloc_st(ch->in_ep, SIMTRACE_MSGC_CARDEM, SIMTRACE_MSGT_BD_CEMU_CONFIG);
if (!msg)
return;
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);
}
/* hardware driver informs us that a card I/O signal has changed */
void card_emu_io_statechg(struct card_handle *ch, enum card_io io, int active)
{
uint32_t chg_mask = 0;
switch (io) {
case CARD_IO_VCC:
if (active == 0 && ch->vcc_active == 1) {
TRACE_INFO("%u: VCC deactivated\r\n", ch->num);
tc_etu_disable(ch->tc_chan);
card_handle_reset(ch);
card_set_state(ch, ISO_S_WAIT_POWER);
chg_mask |= CEMU_STATUS_F_VCC_PRESENT;
} else if (active == 1 && ch->vcc_active == 0) {
TRACE_INFO("%u: VCC activated\r\n", ch->num);
card_set_state(ch, ISO_S_WAIT_CLK);
chg_mask |= CEMU_STATUS_F_VCC_PRESENT;
}
ch->vcc_active = active;
break;
@@ -1068,27 +1116,49 @@ void card_emu_io_statechg(struct card_handle *ch, enum card_io io, int active)
TRACE_INFO("%u: CLK activated\r\n", ch->num);
if (ch->state == ISO_S_WAIT_CLK)
card_set_state(ch, ISO_S_WAIT_RST);
chg_mask |= CEMU_STATUS_F_CLK_ACTIVE;
} else if (active == 0 && ch->clocked == 1) {
TRACE_INFO("%u: CLK deactivated\r\n", ch->num);
chg_mask |= CEMU_STATUS_F_CLK_ACTIVE;
}
ch->clocked = active;
break;
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) {
/* enable the TC/ETU counter once reset has been released */
tc_etu_enable(ch->tc_chan);
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);
}
chg_mask |= CEMU_STATUS_F_RESET_ACTIVE;
} else if (active && !ch->in_reset) {
TRACE_INFO("%u: RST asserted\r\n", ch->num);
tc_etu_disable(ch->tc_chan);
card_handle_reset(ch);
chg_mask |= CEMU_STATUS_F_RESET_ACTIVE;
card_set_state(ch, ISO_S_WAIT_RST);
}
ch->in_reset = active;
break;
}
switch (ch->state) {
case ISO_S_WAIT_POWER:
case ISO_S_WAIT_CLK:
case ISO_S_WAIT_RST:
/* check end activation state (even if the reader does
* not respect the activation sequence) */
if (ch->vcc_active && ch->clocked && !ch->in_reset) {
/* prepare to send the ATR */
card_set_state(ch, ISO_S_WAIT_ATR);
}
break;
default:
break;
}
/* notify the host about the state change */
if ((ch->features & CEMU_FEAT_F_STATUS_IRQ) && chg_mask)
card_emu_report_status(ch, true);
}
/* User sets a new ATR to be returned during next card reset */
@@ -1115,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 tc_etu_wtime_half_expired(void *handle)
void card_emu_wtime_half_expired(void *handle)
{
struct card_handle *ch = handle;
/* transmit NULL procedure byte well before waiting time expires */
@@ -1125,7 +1195,10 @@ void tc_etu_wtime_half_expired(void *handle)
case TPDU_S_WAIT_PB:
case TPDU_S_WAIT_TX:
putchar('N');
/* 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;
@@ -1137,7 +1210,7 @@ void tc_etu_wtime_half_expired(void *handle)
}
/* hardware driver informs us that one (more) ETU has expired */
void tc_etu_wtime_expired(void *handle)
void card_emu_wtime_expired(void *handle)
{
struct card_handle *ch = handle;
switch (ch->state) {
@@ -1151,12 +1224,45 @@ void tc_etu_wtime_expired(void *handle)
}
}
/* shortest ATR possible (uses default speed and no options) */
static const uint8_t default_atr[] = { 0x3B, 0x00 };
/* 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 };
static struct card_handle card_handles[NUM_SLOTS];
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)
int card_emu_set_config(struct card_handle *ch, const struct cardemu_usb_msg_config *scfg,
unsigned int scfg_len)
{
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 uart_chan, uint8_t in_ep, uint8_t irq_ep, bool vcc_active, bool in_reset, bool clocked)
{
struct card_handle *ch;
@@ -1177,11 +1283,10 @@ 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 = 0;
ch->di = 1;
ch->Fi_index = ch->F_index = 1;
ch->Di_index = ch->D_index = 1;
ch->wi = ISO7816_3_DEFAULT_WI;
ch->tc_chan = tc_chan;
ch->uart_chan = uart_chan;
ch->waiting_time = ISO7816_3_INIT_WTIME;
@@ -1192,7 +1297,7 @@ struct card_handle *card_emu_init(uint8_t slot_num, uint8_t tc_chan, uint8_t uar
ch->pts.state = PTS_S_WAIT_REQ_PTSS;
ch->tpdu.state = TPDU_S_WAIT_CLA;
tc_etu_init(ch->tc_chan, ch);
card_handle_reset(ch);
return ch;
}

View File

@@ -428,7 +428,7 @@ static void PCtoRDRXfrBlock( void )
uint16_t msglen = 0;
uint32_t ret;
TRACE_DEBUG("PCtoRDRXfrBlock\n");
TRACE_DEBUG("PCtoRDRXfrBlock\n\r");
// Check the block length
if ( ccidDriver.sCcidCommand.wLength > (configurationDescriptorsFS->ccid.dwMaxCCIDMessageLength-10) ) {
@@ -921,7 +921,7 @@ void USBDCallbacks_RequestReceived(const USBGenericRequest *request)
void CCID_SmartCardRequest( void )
{
unsigned char bStatus;
TRACE_DEBUG("CCID_req\n");
TRACE_DEBUG("CCID_req\n\r");
do {

View File

@@ -27,27 +27,36 @@
* USBD Integration API
***********************************************************************/
/* call-back after (successful?) transfer of a buffer */
/* call-back after (successful?) transfer of a write buffer on IN EP */
static void usb_write_cb(uint8_t *arg, uint8_t status, uint32_t transferred,
uint32_t remaining)
{
struct msgb *msg = (struct msgb *) arg;
struct usb_buffered_ep *bep = msg->dst;
uint16_t ep_size = USBD_GetEndpointSize(bep->ep);
unsigned long x;
TRACE_DEBUG("%s (EP=0x%02x)\r\n", __func__, bep->ep);
if (((msgb_length(msg) % ep_size) == 0) && (transferred == ep_size)) {
/* terminate with ZLP; pass in 'msg' again as 'arg' so we get
* called the second time and proceed with usb_buf_free below */
USBD_Write(bep->ep, 0, 0, (TransferCallback) &usb_write_cb, msg);
return;
}
local_irq_save(x);
bep->in_progress--;
local_irq_restore(x);
TRACE_DEBUG("%u: in_progress=%d\n", bep->ep, bep->in_progress);
TRACE_DEBUG("%u: in_progress=%lu\r\n", bep->ep, bep->in_progress);
if (status != USBD_STATUS_SUCCESS)
TRACE_ERROR("%s error, status=%d\n", __func__, status);
TRACE_ERROR("%s error, status=%d\r\n", __func__, status);
usb_buf_free(msg);
}
/* check if the spcified IN endpoint is idle and submit the next buffer from queue */
int usb_refill_to_host(uint8_t ep)
{
struct usb_buffered_ep *bep = usb_get_buf_ep(ep);
@@ -75,44 +84,44 @@ int usb_refill_to_host(uint8_t ep)
bep->in_progress++;
msg = msgb_dequeue(&bep->queue);
msg = msgb_dequeue_count(&bep->queue, &bep->queue_len);
local_irq_restore(x);
TRACE_DEBUG("%s (EP=0x%02x), in_progress=%d\r\n", __func__, ep, bep->in_progress);
TRACE_DEBUG("%s (EP=0x%02x), in_progress=%lu\r\n", __func__, ep, bep->in_progress);
msg->dst = bep;
rc = USBD_Write(ep, msgb_data(msg), msgb_length(msg),
(TransferCallback) &usb_write_cb, msg);
if (rc != USBD_STATUS_SUCCESS) {
TRACE_ERROR("%s error %x\n", __func__, rc);
TRACE_ERROR("%s error %x\r\n", __func__, rc);
/* re-insert to head of queue */
llist_add_irqsafe(&msg->list, &bep->queue);
local_irq_save(x);
bep->in_progress--;
local_irq_restore(x);
TRACE_DEBUG("%02x: in_progress=%d\n", bep->ep, bep->in_progress);
TRACE_DEBUG("%02x: in_progress=%lu\r\n", bep->ep, bep->in_progress);
return 0;
}
return 1;
}
/* call-back after (successful?) transfer of a buffer */
/* call-back after (successful?) read transfer of a buffer on OUT EP */
static void usb_read_cb(uint8_t *arg, uint8_t status, uint32_t transferred,
uint32_t remaining)
{
struct msgb *msg = (struct msgb *) arg;
struct usb_buffered_ep *bep = msg->dst;
TRACE_DEBUG("%s (EP=%u, len=%u, q=%p)\r\n", __func__,
TRACE_DEBUG("%s (EP=%u, len=%lu, q=%p)\r\n", __func__,
bep->ep, transferred, &bep->queue);
bep->in_progress = 0;
if (status != USBD_STATUS_SUCCESS) {
TRACE_ERROR("%s error, status=%d\n", __func__, status);
TRACE_ERROR("%s error, status=%d\r\n", __func__, status);
usb_buf_free(msg);
return;
}
@@ -120,6 +129,7 @@ static void usb_read_cb(uint8_t *arg, uint8_t status, uint32_t transferred,
llist_add_tail_irqsafe(&msg->list, &bep->queue);
}
/* refill the read queue for data received from host PC on OUT EP, if needed */
int usb_refill_from_host(uint8_t ep)
{
struct usb_buffered_ep *bep = usb_get_buf_ep(ep);
@@ -150,7 +160,7 @@ int usb_refill_from_host(uint8_t ep)
rc = USBD_Read(ep, msg->head, msgb_tailroom(msg),
(TransferCallback) &usb_read_cb, msg);
if (rc != USBD_STATUS_SUCCESS) {
TRACE_ERROR("%s error %d\n", __func__, rc);
TRACE_ERROR("%s error %d\r\n", __func__, rc);
usb_buf_free(msg);
bep->in_progress = 0;
}
@@ -158,6 +168,7 @@ int usb_refill_from_host(uint8_t ep)
return 1;
}
/* drain any buffers from the queue of the endpoint and release their memory */
int usb_drain_queue(uint8_t ep)
{
struct usb_buffered_ep *bep = usb_get_buf_ep(ep);
@@ -177,7 +188,7 @@ int usb_drain_queue(uint8_t ep)
}
/* free all queued msgbs */
while ((msg = msgb_dequeue(&bep->queue))) {
while ((msg = msgb_dequeue_count(&bep->queue, &bep->queue_len))) {
usb_buf_free(msg);
ret++;
}

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

@@ -0,0 +1,54 @@
/* SIMtrace 2 firmware common main helpers
*
* (C) 2015-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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "board.h"
#include "utils.h"
void print_banner(void)
{
printf("\n\r\n\r"
"=============================================================================\n\r"
"SIMtrace2 firmware " GIT_VERSION ", BOARD=" BOARD ", APP=" APPLICATION "\n\r"
"(C) 2010-2019 by Harald Welte, 2018-2019 by Kevin Redon\n\r"
"=============================================================================\n\r");
#if (TRACE_LEVEL >= TRACE_LEVEL_INFO)
/* print chip-unique ID */
unsigned int unique_id[4];
EEFC_ReadUniqueID(unique_id);
TRACE_INFO("Chip ID: 0x%08lx (Ext 0x%08lx)\n\r", CHIPID->CHIPID_CIDR, CHIPID->CHIPID_EXID);
TRACE_INFO("Serial Nr. %08x-%08x-%08x-%08x\n\r",
unique_id[0], unique_id[1], unique_id[2], unique_id[3]);
/* print reset cause */
uint8_t reset_cause = (RSTC->RSTC_SR & RSTC_SR_RSTTYP_Msk) >> RSTC_SR_RSTTYP_Pos;
static const char* reset_causes[] = {
"general reset (first power-up reset)",
"backup reset (return from backup mode)",
"watchdog reset (watchdog fault occurred)",
"software reset (processor reset required by the software)",
"user reset (NRST pin detected low)",
};
if (reset_cause < ARRAY_SIZE(reset_causes)) {
TRACE_INFO("Reset Cause: %s\n\r", reset_causes[reset_cause]);
} else {
TRACE_INFO("Reset Cause: 0x%lx\n\r", (RSTC->RSTC_SR & RSTC_SR_RSTTYP_Msk) >> RSTC_SR_RSTTYP_Pos);
}
#endif
}

View File

@@ -1,7 +1,7 @@
/* card emulation mode
*
* (C) 2015-2017 by Harald Welte <laforge@gnumonks.org>
* (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
* (C) 2018-2019 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -42,6 +42,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,13 +59,26 @@ struct cardem_inst {
struct llist_head usb_out_queue;
struct ringbuf rb;
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_insert;
#ifdef DETECT_VCC_BY_ADC
uint32_t vcc_uv;
uint32_t vcc_uv_last;
#endif
bool vcc_active;
bool vcc_active_last;
bool rst_active;
bool rst_active_last;
};
struct cardem_inst cardem_inst[] = {
@@ -129,18 +146,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;
USART_EnableIt(usart, US_IER_TXRDY);
USART_EnableIt(usart, US_IER_TXRDY | US_IER_TIMEOUT);
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:
@@ -149,6 +192,7 @@ 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;
USART_EnableIt(usart, US_IER_RXRDY);
USART_SetReceiverEnabled(usart, 1);
@@ -188,8 +232,25 @@ 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)
{
Usart *usart = get_usart_by_chan(inst_num);
@@ -197,32 +258,84 @@ static void usart_irq_rx(uint8_t inst_num)
uint32_t csr;
uint8_t byte = 0;
/* get one atomic snapshot of state/flags before they get changed */
csr = usart->US_CSR & usart->US_IMR;
/* 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");
}
/* check if the transmitter is ready for the next byte */
if (csr & US_CSR_TXRDY) {
if (card_emu_tx_byte(ci->ch) == 0)
/* 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 & (US_CSR_OVRE|US_CSR_FRAME|US_CSR_PARE|
US_CSR_TIMEOUT|US_CSR_NACK|(1<<10))) {
/* 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 e 0x%x st: 0x%lx\n", ci->num, byte, csr);
TRACE_ERROR("%u USART error on 0x%x status: 0x%lx\n", ci->num, byte, csr);
}
/* 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 {
/* subtract the actual timeout since the new might not have been set and
* reloaded yet */
ci->wt.remaining -= (usart->US_RTOR & 0xffff);
}
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 {
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);
}
}
}
/*! ISR called for USART0 */
void mode_cardemu_usart0_irq(void)
{
/* USART0 == Instance 1 == USIM 2 */
usart_irq_rx(1);
}
/*! ISR called for USART1 */
void mode_cardemu_usart1_irq(void)
{
/* USART1 == Instance 0 == USIM 1 */
@@ -241,6 +354,41 @@ int card_emu_uart_update_fidi(uint8_t uart_chan, unsigned int fidi)
return 0;
}
/*! 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)
{
OSMO_ASSERT(uart_chan < ARRAY_SIZE(cardem_inst));
struct cardem_inst *ci = &cardem_inst[uart_chan];
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.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)
{
OSMO_ASSERT(uart_chan < ARRAY_SIZE(cardem_inst));
struct cardem_inst *ci = &cardem_inst[uart_chan];
Usart *usart = get_usart_by_chan(uart_chan);
/* 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 */
void card_emu_uart_interrupt(uint8_t uart_chan)
{
@@ -260,8 +408,11 @@ 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 int adc_triggered = 0;
static volatile int adc_triggered = 0;
static int adc_sam3s_reva_errata = 0;
static int card_vcc_adc_init(void)
@@ -308,23 +459,16 @@ 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 &&
ci->vcc_uv_last < VCC_UV_THRESH_3V) {
card_emu_io_statechg(ci->ch, CARD_IO_VCC, 1);
/* FIXME do this for real */
card_emu_io_statechg(ci->ch, CARD_IO_CLK, 1);
} else if (ci->vcc_uv < VCC_UV_THRESH_3V &&
ci->vcc_uv_last >= VCC_UV_THRESH_3V) {
/* FIXME do this for real */
card_emu_io_statechg(ci->ch, CARD_IO_CLK, 0);
card_emu_io_statechg(ci->ch, CARD_IO_VCC, 0);
}
ci->vcc_uv_last = ci->vcc_uv;
#ifdef octsimtest
if (ci->vcc_uv >= VCC_UV_THRESH_1V8)
#else
if (ci->vcc_uv >= VCC_UV_THRESH_3V)
#endif
ci->vcc_active = true;
else
ci->vcc_active = false;
}
void ADC_IrqHandler(void)
@@ -347,44 +491,54 @@ void ADC_IrqHandler(void)
cardem_inst[0].vcc_uv = adc2uv(val);
process_vcc_adc(&cardem_inst[0]);
ADC->ADC_CR |= ADC_CR_START;
adc_triggered = 1;
}
}
#endif /* DETECT_VCC_BY_ADC */
/* called from main loop; dispatches card I/O state changes to card_emu from main loop */
static void process_io_statechg(struct cardem_inst *ci)
{
if (ci->vcc_active != ci->vcc_active_last) {
card_emu_io_statechg(ci->ch, CARD_IO_VCC, ci->vcc_active);
/* FIXME do this for real */
card_emu_io_statechg(ci->ch, CARD_IO_CLK, ci->vcc_active);
ci->vcc_active_last = ci->vcc_active;
}
if (ci->rst_active != ci->rst_active_last) {
card_emu_io_statechg(ci->ch, CARD_IO_RST, ci->rst_active);
ci->rst_active_last = ci->rst_active;
}
}
/***********************************************************************
* Core USB / main loop integration
***********************************************************************/
static void usim1_rst_irqhandler(const Pin *pPin)
{
bool active = PIO_Get(&pin_usim1_rst) ? false : true;
card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_RST, active);
cardem_inst[0].rst_active = PIO_Get(&pin_usim1_rst) ? false : true;
}
#ifndef DETECT_VCC_BY_ADC
static void usim1_vcc_irqhandler(const Pin *pPin)
{
bool active = PIO_Get(&pin_usim1_vcc) ? true : false;
card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_VCC, active);
/* FIXME do this for real */
card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_CLK, active);
cardem_inst[0].vcc_active = PIO_Get(&pin_usim1_vcc) ? true : false;
}
#endif /* !DETECT_VCC_BY_ADC */
#ifdef CARDEMU_SECOND_UART
static void usim2_rst_irqhandler(const Pin *pPin)
{
bool active = PIO_Get(&pin_usim2_rst) ? false : true;
card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_RST, active);
cardem_inst[1].rst_active = PIO_Get(&pin_usim2_rst) ? false : true;
}
#ifndef DETECT_VCC_BY_ADC
static void usim2_vcc_irqhandler(const Pin *pPin)
{
bool active = PIO_Get(&pin_usim2_vcc) ? true : false;
card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_VCC, active);
/* FIXME do this for real */
card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_CLK, active);
cardem_inst[1].vcc_active = PIO_Get(&pin_usim2_vcc) ? true : false;
}
#endif /* !DETECT_VCC_BY_ADC */
#endif /* CARDEMU_SECOND_UART */
@@ -412,15 +566,28 @@ void mode_cardemu_init(void)
INIT_LLIST_HEAD(&cardem_inst[0].usb_out_queue);
rbuf_reset(&cardem_inst[0].rb);
PIO_Configure(pins_usim1, PIO_LISTSIZE(pins_usim1));
/* configure USART as ISO-7816 slave (e.g. card) */
ISO7816_Init(&cardem_inst[0].usart_info, CLK_SLAVE);
NVIC_EnableIRQ(USART1_IRQn);
PIO_ConfigureIt(&pin_usim1_rst, usim1_rst_irqhandler);
PIO_EnableIt(&pin_usim1_rst);
/* obtain current RST state */
usim1_rst_irqhandler(&pin_usim1_rst);
#ifndef DETECT_VCC_BY_ADC
PIO_ConfigureIt(&pin_usim1_vcc, usim1_vcc_irqhandler);
PIO_EnableIt(&pin_usim1_vcc);
/* obtain current VCC state */
usim1_vcc_irqhandler(&pin_usim1_vcc);
#else
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, SIMTRACE_CARDEM_USB_EP_USIM1_INT, PIO_Get(&pin_usim1_vcc) ? true : false, PIO_Get(&pin_usim1_rst) ? false : true, PIO_Get(&pin_usim1_vcc) ? true : false);
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);
#ifdef CARDEMU_SECOND_UART
@@ -428,15 +595,24 @@ void mode_cardemu_init(void)
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 */
NVIC_EnableIRQ(USART0_IRQn);
PIO_ConfigureIt(&pin_usim2_rst, usim2_rst_irqhandler);
PIO_EnableIt(&pin_usim2_rst);
usim2_rst_irqhandler(&pin_usim2_rst); /* obtain current RST state */
#ifndef DETECT_VCC_BY_ADC
PIO_ConfigureIt(&pin_usim2_vcc, usim2_vcc_irqhandler);
PIO_EnableIt(&pin_usim2_vcc);
usim2_vcc_irqhandler(&pin_usim2_vcc); /* obtain current VCC state */
#else
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, SIMTRACE_CARDEM_USB_EP_USIM2_INT, PIO_Get(&pin_usim2_vcc) ? true : false, PIO_Get(&pin_usim2_rst) ? false : true, PIO_Get(&pin_usim2_vcc) ? true : false);
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 */
#endif /* CARDEMU_SECOND_UART */
}
@@ -480,12 +656,33 @@ 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)
{
struct simtrace_msg_hdr *hdr;
struct cardemu_usb_msg_set_atr *atr;
struct cardemu_usb_msg_cardinsert *cardins;
struct cardemu_usb_msg_config *cfg;
struct llist_head *queue;
hdr = (struct simtrace_msg_hdr *) msg->l1h;
@@ -502,21 +699,16 @@ 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");
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:
card_emu_report_status(ci->ch);
card_emu_report_status(ci->ch, false);
usb_buf_free(msg);
break;
case SIMTRACE_MSGT_BD_CEMU_CONFIG:
cfg = (struct cardemu_usb_msg_config *) msg->l2h;
card_emu_set_config(ci->ch, cfg, msgb_l2len(msg));
usb_buf_free(msg);
break;
case SIMTRACE_MSGT_BD_CEMU_STATS:
@@ -652,9 +844,10 @@ static void dispatch_received_msg(struct msgb *msg, struct cardem_inst *ci)
}
if (mh->msg_len > msgb_length(msg)) {
TRACE_ERROR("%u: Unexpected large message (%u bytes)\n",
TRACE_ERROR("%u: Unexpected large message (%u bytes)\r\n",
ci->num, mh->msg_len);
usb_buf_free(segm);
break;
} else {
uint8_t *cur = msgb_put(segm, mh->msg_len);
segm->l1h = segm->head;
@@ -714,6 +907,8 @@ void mode_cardemu_run(void)
//TRACE_ERROR("%uRx%02x\r\n", i, byte);
}
process_io_statechg(ci);
/* first try to send any pending messages on IRQ */
usb_refill_to_host(ci->ep_int);

View File

@@ -15,13 +15,16 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdint.h>
#include <stdio.h>
#include "talloc.h"
#include "trace.h"
#include "utils.h"
#include <osmocom/core/utils.h>
#define NUM_RCTX_SMALL 10
/* TODO: this number should dynamically scale. We need at least one per IN/IRQ endpoint,
* as well as at least 3 for every OUT endpoint. Plus some more depending on the application */
#define NUM_RCTX_SMALL 20
#define RCTX_SIZE_SMALL 348
static uint8_t msgb_data[NUM_RCTX_SMALL][RCTX_SIZE_SMALL] __attribute__((aligned(sizeof(long))));
@@ -63,6 +66,7 @@ int _talloc_free(void *ptr, const char *location)
if (ptr == msgb_data[i]) {
if (!msgb_inuse[i]) {
TRACE_ERROR("%s: double_free by %s\r\n", __func__, location);
OSMO_ASSERT(0);
} else {
msgb_inuse[i] = 0;
}
@@ -73,9 +77,24 @@ int _talloc_free(void *ptr, const char *location)
local_irq_restore(x);
TRACE_ERROR("%s: invalid pointer %p from %s\r\n", __func__, ptr, location);
OSMO_ASSERT(0);
return -1;
}
void talloc_report(const void *ptr, FILE *f)
{
unsigned int i;
fprintf(f, "talloc_report(): ");
for (i = 0; i < ARRAY_SIZE(msgb_inuse); i++) {
if (msgb_inuse[i])
fputc('X', f);
else
fputc('_', f);
}
fprintf(f, "\r\n");
}
void talloc_set_name_const(const void *ptr, const char *name)
{
/* do nothing */

View File

@@ -71,7 +71,7 @@ void ISR_PhoneRST(const Pin * pPin)
USBD_Write(SIMTRACE_USB_EP_PHONE_INT, "R", 1,
(TransferCallback) & Callback_PhoneRST_ISR,
0)) != USBD_STATUS_SUCCESS) {
TRACE_ERROR("USB err status: %d (%s)\n", ret, __FUNCTION__);
TRACE_ERROR("USB err status: %d (%s)\r\n", ret, __FUNCTION__);
return;
}
@@ -109,7 +109,7 @@ void mode_trace_usart1_irq(void)
/* Fill char into buffer */
rbuf_write(&sim_rcv_buf, c);
} else {
TRACE_DEBUG("e %x st: %x\n", c, stat);
TRACE_DEBUG("e %x st: %lx\r\n", c, stat);
} /* else: error occurred */
char_stat = stat;
@@ -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

@@ -303,22 +303,10 @@ static void change_state(enum iso7816_3_sniff_state iso_state_new)
}
const struct value_string data_flags[] = {
{
.value = SNIFF_DATA_FLAG_ERROR_INCOMPLETE,
.str = "incomplete",
},
{
.value = SNIFF_DATA_FLAG_ERROR_MALFORMED,
.str = "malformed",
},
{
.value = SNIFF_DATA_FLAG_ERROR_CHECKSUM,
.str = "checksum error",
},
{
.value = 0,
.str = NULL,
},
{ SNIFF_DATA_FLAG_ERROR_INCOMPLETE, "incomplete" },
{ SNIFF_DATA_FLAG_ERROR_MALFORMED, "malformed" },
{ SNIFF_DATA_FLAG_ERROR_CHECKSUM, "checksum error" },
{ 0, NULL }
};
static void print_flags(const struct value_string* flag_meanings, uint32_t nb_flags, uint32_t flags) {
@@ -670,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");

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

@@ -358,6 +358,7 @@ signed int vsnprintf(char *pStr, size_t length, const char *pFormat, va_list ap)
case 'i': num = PutSignedInt(pStr, fill, width, va_arg(ap, signed int)); break;
case 'u': num = PutUnsignedInt(pStr, fill, width, va_arg(ap, unsigned int)); break;
case 'x': num = PutHexa(pStr, fill, width, 0, va_arg(ap, unsigned int)); break;
case 'p': num = PutHexa(pStr, fill, width, 0, va_arg(ap, unsigned long)); break;
case 'X': num = PutHexa(pStr, fill, width, 1, va_arg(ap, unsigned int)); break;
case 's': num = PutString(pStr, va_arg(ap, char *)); break;
case 'c': num = PutChar(pStr, va_arg(ap, unsigned int)); break;

View File

@@ -24,6 +24,7 @@
#include <errno.h>
#define USB_ALLOC_SIZE 280
#define USB_MAX_QLEN 3
static struct usb_buffered_ep usb_buffered_ep[BOARD_USB_NUMENDPOINTS];
@@ -78,7 +79,18 @@ int usb_buf_submit(struct msgb *msg)
/* no need for irqsafe operation, as the usb_tx_queue is
* processed only by the main loop context */
msgb_enqueue(&ep->queue, msg);
if (ep->queue_len >= USB_MAX_QLEN) {
struct msgb *evict;
/* free the first pending buffer in the queue */
TRACE_INFO("EP%02x: dropping first queue element (qlen=%u)\r\n",
ep->ep, ep->queue_len);
evict = msgb_dequeue_count(&ep->queue, &ep->queue_len);
OSMO_ASSERT(evict);
usb_buf_free(evict);
}
msgb_enqueue_count(&ep->queue, msg, &ep->queue_len);
return 0;
}
@@ -89,5 +101,6 @@ void usb_buf_init(void)
for (i = 0; i < ARRAY_SIZE(usb_buffered_ep); i++) {
struct usb_buffered_ep *ep = &usb_buffered_ep[i];
INIT_LLIST_HEAD(&ep->queue);
ep->ep = i;
}
}

View File

@@ -80,6 +80,49 @@ extern int msgb_resize_area(struct msgb *msg, uint8_t *area,
extern struct msgb *msgb_copy(const struct msgb *msg, const char *name);
static int msgb_test_invariant(const struct msgb *msg) __attribute__((pure));
/*! Free all msgbs from a queue built with msgb_enqueue().
* \param[in] queue list head of a msgb queue.
*/
static inline void msgb_queue_free(struct llist_head *queue)
{
struct msgb *msg;
while ((msg = msgb_dequeue(queue))) msgb_free(msg);
}
/*! Enqueue message buffer to tail of a queue and increment queue size counter
* \param[in] queue linked list header of queue
* \param[in] msg message buffer to be added to the queue
* \param[in] count pointer to variable holding size of the queue
*
* The function will append the specified message buffer \a msg to the queue
* implemented by \ref llist_head \a queue using function \ref msgb_enqueue_count,
* then increment \a count
*/
static inline void msgb_enqueue_count(struct llist_head *queue, struct msgb *msg,
unsigned int *count)
{
msgb_enqueue(queue, msg);
(*count)++;
}
/*! Dequeue message buffer from head of queue and decrement queue size counter
* \param[in] queue linked list header of queue
* \param[in] count pointer to variable holding size of the queue
* \returns message buffer (if any) or NULL if queue empty
*
* The function will remove the first message buffer from the queue
* implemented by \ref llist_head \a queue using function \ref msgb_enqueue_count,
* and decrement \a count, all if queue is not empty.
*/
static inline struct msgb *msgb_dequeue_count(struct llist_head *queue,
unsigned int *count)
{
struct msgb *msg = msgb_dequeue(queue);
if (msg)
(*count)--;
return msg;
}
#ifdef MSGB_DEBUG
#include <osmocom/core/panic.h>
#define MSGB_ABORT(msg, fmt, args ...) do { \

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);
}
@@ -177,14 +179,14 @@ static void dump_rctx(struct msgb *msg)
static void get_and_verify_rctx(uint8_t ep, const uint8_t *data, unsigned int len)
{
struct llist_head *queue = usb_get_queue(ep);
struct usb_buffered_ep *bep = usb_get_buf_ep(ep);
struct msgb *msg;
struct cardemu_usb_msg_tx_data *td;
struct cardemu_usb_msg_rx_data *rd;
struct simtrace_msg_hdr *mh;
assert(queue);
msg = msgb_dequeue(queue);
assert(bep);
msg = msgb_dequeue_count(&bep->queue, &bep->queue_len);
assert(msg);
dump_rctx(msg);
assert(msg->l1h);
@@ -214,13 +216,13 @@ static void get_and_verify_rctx(uint8_t ep, const uint8_t *data, unsigned int le
static void get_and_verify_rctx_pps(const uint8_t *data, unsigned int len)
{
struct llist_head *queue = usb_get_queue(PHONE_DATAIN);
struct usb_buffered_ep *bep = usb_get_buf_ep(PHONE_DATAIN);
struct msgb *msg;
struct simtrace_msg_hdr *mh;
struct cardemu_usb_msg_pts_info *ptsi;
assert(queue);
msg = msgb_dequeue(queue);
assert(bep);
msg = msgb_dequeue_count(&bep->queue, &bep->queue_len);
assert(msg);
dump_rctx(msg);
assert(msg->l1h);
@@ -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();

File diff suppressed because it is too large Load Diff

5
host/.gitignore vendored
View File

@@ -20,6 +20,7 @@ depcomp
install-sh
missing
stamp-h1
m4
#libtool
ltmain.sh
@@ -30,3 +31,7 @@ libtool
.version
*.pc
simtrace2-list
simtrace2-sniff
simtrace2-cardem-pcsc

339
host/COPYING Normal file
View File

@@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

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 ../../
@@ -58,6 +58,7 @@ AC_SUBST(SYMBOL_VISIBILITY)
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.0.0)
PKG_CHECK_MODULES(LIBOSMOSIM, libosmosim >= 1.0.0)
PKG_CHECK_MODULES(LIBOSMOUSB, libosmousb >= 0.0.0)
PKG_CHECK_MODULES(LIBUSB, libusb-1.0)
AC_ARG_ENABLE(sanitize,
@@ -99,4 +100,5 @@ AC_OUTPUT(
src/Makefile
lib/Makefile
contrib/Makefile
contrib/simtrace2.spec
Makefile)

View File

@@ -16,6 +16,10 @@ ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="4002", GROUP="plugdev"
# sysmocom QMOD SAM3 (DFU and runtime)
ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="4003", GROUP="plugdev"
ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="4004", GROUP="plugdev"
# sysmocom OCTSIMTEST
ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="616d", GROUP="plugdev"
# ngff-cardem
ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="616e", GROUP="plugdev"
# All done
LABEL="simtrace2_rules_end"

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

@@ -1,7 +1,8 @@
nobase_include_HEADERS = \
osmocom/simtrace2/apdu_dispatch.h \
osmocom/simtrace2/libusb_util.h \
osmocom/simtrace2/simtrace2_api.h \
osmocom/simtrace2/simtrace_usb.h \
osmocom/simtrace2/simtrace_prot.h \
osmocom/simtrace2/gsmtap.h
osmocom/simtrace2/usb_util.h \
osmocom/simtrace2/gsmtap.h \
$(NULL)

View File

@@ -1,6 +1,6 @@
/* apdu_dispatch - State machine to determine Rx/Tx phases of APDU
*
* (C) 2016 by Harald Welte <hwelte@hmw-consulting.de>
* (C) 2016-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
@@ -44,6 +44,8 @@ enum osmo_apdu_action {
APDU_ACT_RX_MORE_CAPDU_FROM_READER = 0x0002,
};
const char *osmo_apdu_dump_context_buf(char *buf, unsigned int buf_len,
const struct osmo_apdu_context *ac);
int osmo_apdu_segment_in(struct osmo_apdu_context *ac, const uint8_t *apdu_buf,
unsigned int apdu_len, bool new_apdu);

View File

@@ -1,73 +0,0 @@
/* libisb utilities
*
* (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.
*/
#pragma once
#include <libusb.h>
#define USB_MAX_PATH_LEN 20
struct dev_id {
uint16_t vendor_id;
uint16_t product_id;
};
/* Find any USB devices in the system matching the given Vendor and
* Product ID */
libusb_device **find_matching_usb_devs(const struct dev_id *dev_ids);
/* structure describing a single matching interface found */
struct usb_interface_match {
/* libusb device E*/
libusb_device *usb_dev;
/* Vendor ID of the device running matching interface */
uint16_t vendor;
/* Product ID of the device running matching interface */
uint16_t product;
/* USB Bus Address */
uint8_t addr;
/* physical path */
char path[USB_MAX_PATH_LEN];
/* configuration of matching interface */
uint8_t configuration;
/* interface number of matching interface */
uint8_t interface;
/* altsetting of matching interface */
uint8_t altsetting;
/* bInterfaceClass of matching interface */
uint8_t class;
/* bInterfaceSubClass of matching interface */
uint8_t sub_class;
/* bInterfaceProtocol of matching interface */
uint8_t protocol;
/* index of string descriptor of matching interface */
uint8_t string_idx;
};
int dev_find_matching_interfaces(libusb_device *dev, int class, int sub_class, int protocol,
struct usb_interface_match *out, unsigned int out_len);
int usb_match_interfaces(libusb_context *ctx, const struct dev_id *dev_ids,
int class, int sub_class, int protocol,
struct usb_interface_match *out, unsigned int out_len);
libusb_device_handle *usb_open_claim_interface(libusb_context *ctx,
const struct usb_interface_match *ifm);
int get_usb_ep_addrs(libusb_device_handle *devh, unsigned int if_num,
uint8_t *out, uint8_t *in, uint8_t *irq);

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;
@@ -33,10 +35,12 @@ struct osmo_st2_cardem_inst {
const struct osim_cla_ins_card_profile *card_prof;
/* libosmosim SIM card channel */
struct osim_chan_hdl *chan;
/* path of the underlying USB device */
char *usb_path;
/* opaque data TBD by user */
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);
@@ -48,6 +52,7 @@ int osmo_st2_cardem_request_pb_and_tx(struct osmo_st2_cardem_inst *ci, uint8_t p
int osmo_st2_cardem_request_sw_tx(struct osmo_st2_cardem_inst *ci, const uint8_t *sw);
int osmo_st2_cardem_request_set_atr(struct osmo_st2_cardem_inst *ci, const uint8_t *atr,
unsigned int atr_len);
int osmo_st2_cardem_request_config(struct osmo_st2_cardem_inst *ci, uint32_t features);
int osmo_st2_modem_reset_pulse(struct osmo_st2_slot *slot, uint16_t duration_ms);

View File

@@ -0,0 +1,5 @@
#pragma once
#include <osmocom/usb/libusb.h>
extern const struct dev_id osmo_st2_compatible_dev_ids[];

View File

@@ -15,5 +15,6 @@ libosmo_simtrace2_la_LIBADD = $(COMMONLIBS)
libosmo_simtrace2_la_SOURCES = \
apdu_dispatch.c \
gsmtap.c \
libusb_util.c \
simtrace2_api.c
simtrace2_api.c \
usb_util.c \
$(NULL)

View File

@@ -1,6 +1,6 @@
/* apdu_dispatch - State machine to determine Rx/Tx phases of APDU
*
* (C) 2016 by Harald Welte <hwelte@hmw-consulting.de>
* (C) 2016-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
@@ -24,6 +24,7 @@
#include <errno.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/logging.h>
#include <osmocom/sim/sim.h>
#include <osmocom/sim/class_tables.h>
@@ -41,7 +42,7 @@ static inline bool is_de_complete(struct osmo_apdu_context *ac)
return (ac->le.tot == ac->le.cur);
}
static const char *dump_apdu_hdr(const struct osim_apdu_cmd_hdr *h)
static const char *stringify_apdu_hdr(const struct osim_apdu_cmd_hdr *h)
{
static char buf[256];
sprintf(buf, "CLA=%02x INS=%02x P1=%02x P2=%02x P3=%02x",
@@ -50,12 +51,19 @@ static const char *dump_apdu_hdr(const struct osim_apdu_cmd_hdr *h)
return buf;
}
static void dump_apdu_ctx(const struct osmo_apdu_context *ac)
/*! generate string representation of APDU context in specified output buffer.
* \param[in] buf output string buffer provided by caller
* \param[in] buf_len size of buf in bytes
* \param[in] ac APDU context to dump in buffer
* \returns pointer to buf on success */
const char *osmo_apdu_dump_context_buf(char *buf, unsigned int buf_len,
const struct osmo_apdu_context *ac)
{
printf("%s; case=%d, lc=%d(%d), le=%d(%d)\n",
dump_apdu_hdr(&ac->hdr), ac->apdu_case,
ac->lc.tot, ac->lc.cur,
ac->le.tot, ac->le.cur);
snprintf(buf, buf_len, "%s; case=%d, lc=%d(%d), le=%d(%d)\n",
stringify_apdu_hdr(&ac->hdr), ac->apdu_case,
ac->lc.tot, ac->lc.cur,
ac->le.tot, ac->le.cur);
return buf;
}
/*! \brief input function for APDU segmentation
@@ -105,7 +113,7 @@ int osmo_apdu_segment_in(struct osmo_apdu_context *ac, const uint8_t *apdu_buf,
break;
case 0:
default:
fprintf(stderr, "Unknown APDU case %d\n", ac->apdu_case);
LOGP(DLGLOBAL, LOGL_ERROR, "Unknown APDU case %d\n", ac->apdu_case);
return -1;
}
} else {
@@ -124,8 +132,8 @@ int osmo_apdu_segment_in(struct osmo_apdu_context *ac, const uint8_t *apdu_buf,
ac->lc.cur += cpy_len;
break;
default:
fprintf(stderr, "Unknown APDU case %d\n", ac->apdu_case);
break;
LOGP(DLGLOBAL, LOGL_ERROR, "Unknown APDU case %d\n", ac->apdu_case);
return -1;
}
}
@@ -163,11 +171,9 @@ int osmo_apdu_segment_in(struct osmo_apdu_context *ac, const uint8_t *apdu_buf,
break;
case 0:
default:
fprintf(stderr, "Unknown APDU case %d\n", ac->apdu_case);
break;
LOGP(DLGLOBAL, LOGL_ERROR, "Unknown APDU case %d\n", ac->apdu_case);
return -1;
}
dump_apdu_ctx(ac);
return rc;
}

View File

@@ -1,3 +1,22 @@
/* gsmtap - How to encapsulate SIM protocol traces in GSMTAP
*
* (C) 2016-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 <osmocom/simtrace2/gsmtap.h>
#include <osmocom/core/gsmtap.h>

View File

@@ -1,338 +0,0 @@
/* libusb utilities
*
* (C) 2010-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 <stdint.h>
#include <string.h>
#include <libusb.h>
#include <osmocom/simtrace2/libusb_util.h>
static char path_buf[USB_MAX_PATH_LEN];
static char *get_path(libusb_device *dev)
{
#if (defined(LIBUSB_API_VERSION) && LIBUSB_API_VERSION >= 0x01000102) || (defined(LIBUSBX_API_VERSION) && LIBUSBX_API_VERSION >= 0x01000102)
uint8_t path[8];
int r,j;
r = libusb_get_port_numbers(dev, path, sizeof(path));
if (r > 0) {
sprintf(path_buf,"%d-%d",libusb_get_bus_number(dev),path[0]);
for (j = 1; j < r; j++){
sprintf(path_buf+strlen(path_buf),".%d",path[j]);
};
}
return path_buf;
#else
# warning "libusb too old - building without USB path support!"
return NULL;
#endif
}
static int match_dev_id(const struct libusb_device_descriptor *desc, const struct dev_id *id)
{
if ((desc->idVendor == id->vendor_id) && (desc->idProduct == id->product_id))
return 1;
return 0;
}
static int match_dev_ids(const struct libusb_device_descriptor *desc, const struct dev_id *ids)
{
const struct dev_id *id;
for (id = ids; id->vendor_id || id->product_id; id++) {
if (match_dev_id(desc, id))
return 1;
}
return 0;
}
libusb_device **find_matching_usb_devs(const struct dev_id *dev_ids)
{
libusb_device **list;
libusb_device **out = calloc(256, sizeof(libusb_device *));
libusb_device **cur = out;
unsigned int i;
int rc;
if (!out)
return NULL;
rc = libusb_get_device_list(NULL, &list);
if (rc <= 0) {
perror("No USB devices found");
free(out);
return NULL;
}
for (i = 0; list[i] != NULL; i++) {
struct libusb_device_descriptor dev_desc;
libusb_device *dev = list[i];
rc = libusb_get_device_descriptor(dev, &dev_desc);
if (rc < 0) {
perror("Couldn't get device descriptor\n");
libusb_unref_device(dev);
continue;
}
if (match_dev_ids(&dev_desc, dev_ids)) {
*cur = dev;
cur++;
/* FIXME: overflow check */
} else
libusb_unref_device(dev);
}
if (cur == out) {
libusb_free_device_list(list, 1);
free(out);
return NULL;
}
libusb_free_device_list(list, 0);
return out;
}
int dev_find_matching_interfaces(libusb_device *dev, int class, int sub_class, int protocol,
struct usb_interface_match *out, unsigned int out_len)
{
struct libusb_device_descriptor dev_desc;
int rc, i, out_idx = 0;
uint8_t addr;
char *path;
rc = libusb_get_device_descriptor(dev, &dev_desc);
if (rc < 0) {
perror("Couldn't get device descriptor\n");
return -EIO;
}
addr = libusb_get_device_address(dev);
path = get_path(dev);
/* iterate over all configurations */
for (i = 0; i < dev_desc.bNumConfigurations; i++) {
struct libusb_config_descriptor *conf_desc;
int j;
rc = libusb_get_config_descriptor(dev, i, &conf_desc);
if (rc < 0) {
fprintf(stderr, "Couldn't get config descriptor %u\n", i);
continue;
}
/* iterate over all interfaces */
for (j = 0; j < conf_desc->bNumInterfaces; j++) {
const struct libusb_interface *intf = &conf_desc->interface[j];
int k;
/* iterate over all alternate settings */
for (k = 0; k < intf->num_altsetting; k++) {
const struct libusb_interface_descriptor *if_desc;
if_desc = &intf->altsetting[k];
if (class >= 0 && if_desc->bInterfaceClass != class)
continue;
if (sub_class >= 0 && if_desc->bInterfaceSubClass != sub_class)
continue;
if (protocol >= 0 && if_desc->bInterfaceProtocol != protocol)
continue;
/* MATCH! */
out[out_idx].usb_dev = dev;
out[out_idx].vendor = dev_desc.idVendor;
out[out_idx].product = dev_desc.idProduct;
out[out_idx].addr = addr;
strncpy(out[out_idx].path, path, sizeof(out[out_idx].path)-1);
out[out_idx].path[sizeof(out[out_idx].path)-1] = '\0';
out[out_idx].configuration = conf_desc->bConfigurationValue;
out[out_idx].interface = if_desc->bInterfaceNumber;
out[out_idx].altsetting = if_desc->bAlternateSetting;
out[out_idx].class = if_desc->bInterfaceClass;
out[out_idx].sub_class = if_desc->bInterfaceSubClass;
out[out_idx].protocol = if_desc->bInterfaceProtocol;
out[out_idx].string_idx = if_desc->iInterface;
out_idx++;
if (out_idx >= out_len)
return out_idx;
}
}
}
return out_idx;
}
int usb_match_interfaces(libusb_context *ctx, const struct dev_id *dev_ids,
int class, int sub_class, int protocol,
struct usb_interface_match *out, unsigned int out_len)
{
struct usb_interface_match *out_cur = out;
unsigned int out_len_remain = out_len;
libusb_device **list;
libusb_device **dev;
list = find_matching_usb_devs(dev_ids);
if (!list)
return 0;
for (dev = list; *dev; dev++) {
int rc;
#if 0
struct libusb_device_descriptor dev_desc;
uint8_t ports[8];
uint8_t addr;
rc = libusb_get_device_descriptor(*dev, &dev_desc);
if (rc < 0) {
perror("Cannot get device descriptor");
continue;
}
addr = libusb_get_device_address(*dev);
rc = libusb_get_port_numbers(*dev, ports, sizeof(ports));
if (rc < 0) {
perror("Cannot get device path");
continue;
}
printf("Found USB Device %04x:%04x at address %d\n",
dev_desc.idVendor, dev_desc.idProduct, addr);
#endif
rc = dev_find_matching_interfaces(*dev, class, sub_class, protocol, out_cur, out_len_remain);
if (rc < 0)
continue;
out_cur += rc;
out_len_remain -= rc;
}
return out_len - out_len_remain;
}
libusb_device_handle *usb_open_claim_interface(libusb_context *ctx,
const struct usb_interface_match *ifm)
{
int rc, config;
struct dev_id dev_ids[] = { { ifm->vendor, ifm->product }, { 0, 0 } };
libusb_device **list;
libusb_device **dev;
libusb_device_handle *usb_devh = NULL;
list = find_matching_usb_devs(dev_ids);
if (!list) {
perror("No USB device with matching VID/PID");
return NULL;
}
for (dev = list; *dev; dev++) {
int addr;
char *path;
addr = libusb_get_device_address(*dev);
path = get_path(*dev);
if ((ifm->addr && addr == ifm->addr) ||
(strlen(ifm->path) && !strcmp(path, ifm->path))) {
rc = libusb_open(*dev, &usb_devh);
if (rc < 0) {
fprintf(stderr, "Cannot open device: %s\n", libusb_error_name(rc));
usb_devh = NULL;
break;
}
rc = libusb_get_configuration(usb_devh, &config);
if (rc < 0) {
fprintf(stderr, "Cannot get current configuration: %s\n", libusb_error_name(rc));
libusb_close(usb_devh);
usb_devh = NULL;
break;
}
if (config != ifm->configuration) {
rc = libusb_set_configuration(usb_devh, ifm->configuration);
if (rc < 0) {
fprintf(stderr, "Cannot set configuration: %s\n", libusb_error_name(rc));
libusb_close(usb_devh);
usb_devh = NULL;
break;
}
}
rc = libusb_claim_interface(usb_devh, ifm->interface);
if (rc < 0) {
fprintf(stderr, "Cannot claim interface: %s\n", libusb_error_name(rc));
libusb_close(usb_devh);
usb_devh = NULL;
break;
}
rc = libusb_set_interface_alt_setting(usb_devh, ifm->interface, ifm->altsetting);
if (rc < 0) {
fprintf(stderr, "Cannot set interface altsetting: %s\n", libusb_error_name(rc));
libusb_release_interface(usb_devh, ifm->interface);
libusb_close(usb_devh);
usb_devh = NULL;
break;
}
}
}
/* unref / free list */
for (dev = list; *dev; dev++)
libusb_unref_device(*dev);
free(list);
return usb_devh;
}
/*! \brief obtain the endpoint addresses for a given USB interface */
int get_usb_ep_addrs(libusb_device_handle *devh, unsigned int if_num,
uint8_t *out, uint8_t *in, uint8_t *irq)
{
libusb_device *dev = libusb_get_device(devh);
struct libusb_config_descriptor *cdesc;
const struct libusb_interface_descriptor *idesc;
const struct libusb_interface *iface;
int rc, l;
rc = libusb_get_active_config_descriptor(dev, &cdesc);
if (rc < 0)
return rc;
iface = &cdesc->interface[if_num];
/* FIXME: we assume there's no altsetting */
idesc = &iface->altsetting[0];
for (l = 0; l < idesc->bNumEndpoints; l++) {
const struct libusb_endpoint_descriptor *edesc = &idesc->endpoint[l];
switch (edesc->bmAttributes & 3) {
case LIBUSB_TRANSFER_TYPE_BULK:
if (edesc->bEndpointAddress & 0x80) {
if (in)
*in = edesc->bEndpointAddress;
} else {
if (out)
*out = edesc->bEndpointAddress;
}
break;
case LIBUSB_TRANSFER_TYPE_INTERRUPT:
if (irq)
*irq = edesc->bEndpointAddress;
break;
default:
break;
}
}
return 0;
}

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;
@@ -204,6 +261,21 @@ int osmo_st2_cardem_request_set_atr(struct osmo_st2_cardem_inst *ci, const uint8
return osmo_st2_slot_tx_msg(ci->slot, msg, SIMTRACE_MSGC_CARDEM, SIMTRACE_MSGT_DT_CEMU_SET_ATR);
}
int osmo_st2_cardem_request_config(struct osmo_st2_cardem_inst *ci, uint32_t features)
{
struct msgb *msg = st_msgb_alloc();
struct cardemu_usb_msg_config *cfg;
cfg = (struct cardemu_usb_msg_config *) msgb_put(msg, sizeof(*cfg));
LOGSLOT(ci->slot, LOGL_NOTICE, "<= %s(features=%08x)\n", __func__, features);
memset(cfg, 0, sizeof(*cfg));
cfg->features = features;
return osmo_st2_slot_tx_msg(ci->slot, msg, SIMTRACE_MSGC_CARDEM, SIMTRACE_MSGT_BD_CEMU_CONFIG);
}
/***********************************************************************
* Modem Control protocol
***********************************************************************/
@@ -213,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;
@@ -243,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;

Some files were not shown because too many files have changed in this diff Show More