mirror of
https://gitea.osmocom.org/sim-card/simtrace2.git
synced 2026-03-18 22:38:32 +03:00
Compare commits
17 Commits
laforge/to
...
hoernchen/
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ccceb0ffba | ||
|
|
e0f4d9216e | ||
|
|
22adb8acd5 | ||
|
|
b59fb8fc92 | ||
|
|
70bd983e56 | ||
|
|
c3d9fe78c7 | ||
|
|
6268322221 | ||
|
|
5eaf5f8e3a | ||
|
|
cd62c46e6d | ||
|
|
c5635780bb | ||
|
|
2d0d1e8cb3 | ||
|
|
b0d789e09d | ||
|
|
ae28d5a4c5 | ||
|
|
9dd4dc287d | ||
|
|
ed7b838392 | ||
|
|
656fda7ddd | ||
|
|
4a76fe50ea |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -18,8 +18,7 @@ tags
|
|||||||
*.bin
|
*.bin
|
||||||
*.p
|
*.p
|
||||||
host/simtrace2-list
|
host/simtrace2-list
|
||||||
host/simtrace2-cardem-pcsc
|
host/simtrace2-remsim
|
||||||
host/contrib/simtrace2.spec
|
host/simtrace2-remsim-usb2udp
|
||||||
usb_strings_generated.h
|
usb_strings_generated.h
|
||||||
firmware/usbstring/usbstring
|
firmware/usbstring/usbstring
|
||||||
firmware/apps/*/usb_strings.txt.patched
|
|
||||||
|
|||||||
17
README.md
17
README.md
@@ -5,6 +5,9 @@ This is the repository for the next-generation SIMtrace devices,
|
|||||||
providing abilities to trace the communication between (U)SIM card and
|
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.
|
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
|
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 /
|
or its associated firmware. SIMtrace v1.x is based on a different CPU /
|
||||||
microcontroller architecture and uses a completely different software
|
microcontroller architecture and uses a completely different software
|
||||||
@@ -13,6 +16,12 @@ stack and host software.
|
|||||||
Supported Hardware
|
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
|
* Osmocom SIMtrace 1.x with SAM3 controller
|
||||||
** this is open hardware and schematics / PCB design is published
|
** this is open hardware and schematics / PCB design is published
|
||||||
* sysmocom sysmoQMOD (with 4 Modems, 4 SIM slots and 2 SAM3)
|
* sysmocom sysmoQMOD (with 4 Modems, 4 SIM slots and 2 SAM3)
|
||||||
@@ -28,11 +37,3 @@ This repository contains several directory
|
|||||||
* firmware - the firmware to run on the actual devices
|
* firmware - the firmware to run on the actual devices
|
||||||
* hardware - some information related to the hardware
|
* hardware - some information related to the hardware
|
||||||
* host - Programs to use on the USB host to interface with 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
10
TODO-RELEASE
@@ -1,10 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -31,7 +31,6 @@ BUILDS=""
|
|||||||
BUILDS+="simtrace/dfu simtrace/trace simtrace/cardem "
|
BUILDS+="simtrace/dfu simtrace/trace simtrace/cardem "
|
||||||
BUILDS+="qmod/dfu qmod/cardem "
|
BUILDS+="qmod/dfu qmod/cardem "
|
||||||
BUILDS+="owhw/dfu owhw/cardem "
|
BUILDS+="owhw/dfu owhw/cardem "
|
||||||
BUILDS+="octsimtest/cardem "
|
|
||||||
|
|
||||||
cd $TOPDIR/firmware
|
cd $TOPDIR/firmware
|
||||||
for build in $BUILDS; do
|
for build in $BUILDS; do
|
||||||
@@ -67,16 +66,15 @@ make dist
|
|||||||
if [ "x$publish" = "x--publish" ]; then
|
if [ "x$publish" = "x--publish" ]; then
|
||||||
echo
|
echo
|
||||||
echo "=============== UPLOAD BUILD =============="
|
echo "=============== UPLOAD BUILD =============="
|
||||||
$TOPDIR/contrib/prepare_upload.sh
|
|
||||||
|
|
||||||
cat > "/build/known_hosts" <<EOF
|
cat > "/build/known_hosts" <<EOF
|
||||||
[ftp.osmocom.org]:48 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDgQ9HntlpWNmh953a2Gc8NysKE4orOatVT1wQkyzhARnfYUerRuwyNr1GqMyBKdSI9amYVBXJIOUFcpV81niA7zQRUs66bpIMkE9/rHxBd81SkorEPOIS84W4vm3SZtuNqa+fADcqe88Hcb0ZdTzjKILuwi19gzrQyME2knHY71EOETe9Yow5RD2hTIpB5ecNxI0LUKDq+Ii8HfBvndPBIr0BWYDugckQ3Bocf+yn/tn2/GZieFEyFpBGF/MnLbAAfUKIdeyFRX7ufaiWWz5yKAfEhtziqdAGZaXNaLG6gkpy3EixOAy6ZXuTAk3b3Y0FUmDjhOHllbPmTOcKMry9
|
[rita.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=
|
[rita.osmocom.org]:48 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPdWn1kEousXuKsZ+qJEZTt/NSeASxCrUfNDW3LWtH+d8Ust7ZuKp/vuyG+5pe5pwpPOgFu7TjN+0lVjYJVXH54=
|
||||||
[ftp.osmocom.org]:48 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK8iivY70EiR5NiGChV39gRLjNpC8lvu1ZdHtdMw2zuX
|
[rita.osmocom.org]:48 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK8iivY70EiR5NiGChV39gRLjNpC8lvu1ZdHtdMw2zuX
|
||||||
EOF
|
EOF
|
||||||
SSH_COMMAND="ssh -o 'UserKnownHostsFile=/build/known_hosts' -p 48"
|
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@ftp.osmocom.org:web-files/simtrace2/firmware/latest/
|
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@ftp.osmocom.org:web-files/simtrace2/firmware/all/
|
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/
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo
|
echo
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
#!/bin/sh -e
|
|
||||||
# Create copies of binaries with -latest, -$GIT_VERSION (OS#4413, OS#3452)
|
|
||||||
cd "$(dirname "$0")/.."
|
|
||||||
|
|
||||||
GIT_VERSION="$(./git-version-gen .tarball-version)"
|
|
||||||
|
|
||||||
echo "Copying binaries with "-latest" and "-$GIT_VERSION" appended..."
|
|
||||||
|
|
||||||
cd firmware/bin
|
|
||||||
for ext in bin elf; do
|
|
||||||
for file in *."$ext"; do
|
|
||||||
without_ext="${file%.*}"
|
|
||||||
cp -v "$file" "$without_ext-latest.$ext"
|
|
||||||
cp -v "$file" "$without_ext-$GIT_VERSION.$ext"
|
|
||||||
done
|
|
||||||
done
|
|
||||||
1
debian/source/format
vendored
1
debian/source/format
vendored
@@ -1 +0,0 @@
|
|||||||
3.0 (native)
|
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
# Makefile for compiling the Getting Started with SAM3S Microcontrollers project
|
# Makefile for compiling the Getting Started with SAM3S Microcontrollers project
|
||||||
|
|
||||||
GIT_VERSION=$(shell $(TOP)/git-version-gen $(TOP)/.tarball-version)
|
GIT_VERSION=$(shell $(TOP)/git-version-gen $(TOP)/.tarvers)
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
# User-modifiable options
|
# User-modifiable options
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
@@ -108,7 +108,7 @@ C_LIBUSB = USBDescriptors.c USBRequests.c USBD.c USBDCallbacks.c USBDDriver.
|
|||||||
C_LIBUSB_RT = dfu.c dfu_runtime.c
|
C_LIBUSB_RT = dfu.c dfu_runtime.c
|
||||||
C_LIBUSB_DFU = dfu.c dfu_desc.c dfu_driver.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
|
main_common.c tc_etu.c
|
||||||
|
|
||||||
C_BOARD = $(notdir $(wildcard libboard/common/source/*.c))
|
C_BOARD = $(notdir $(wildcard libboard/common/source/*.c))
|
||||||
C_BOARD += $(notdir $(wildcard libboard/$(BOARD)/source/*.c))
|
C_BOARD += $(notdir $(wildcard libboard/$(BOARD)/source/*.c))
|
||||||
@@ -178,14 +178,6 @@ CFLAGS += -ffunction-sections -g $(OPTIMIZATION) $(INCLUDES) -D$(CHIP) -DTRACE_L
|
|||||||
CFLAGS += -DGIT_VERSION=\"$(GIT_VERSION)\"
|
CFLAGS += -DGIT_VERSION=\"$(GIT_VERSION)\"
|
||||||
CFLAGS += -DBOARD=\"$(BOARD)\" -DBOARD_$(BOARD)
|
CFLAGS += -DBOARD=\"$(BOARD)\" -DBOARD_$(BOARD)
|
||||||
CFLAGS += -DAPPLICATION=\"$(APP)\" -DAPPLICATION_$(APP)
|
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__
|
ASFLAGS = -mcpu=cortex-m3 -mthumb -Wall -g $(OPTIMIZATION) $(INCLUDES) -D$(CHIP) -D__ASSEMBLY__
|
||||||
LDFLAGS = -mcpu=cortex-m3 -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--entry=ResetException -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--print-memory-usage -Wl,--no-undefined $(LIB)
|
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
|
#LD_OPTIONAL=-Wl,--print-gc-sections -Wl,--stats
|
||||||
@@ -227,8 +219,12 @@ ASM_OBJECTS_$(1) = $(addprefix $(OBJ)/$(1)_, $(ASM_OBJECTS))
|
|||||||
|
|
||||||
$(1): $$(ASM_OBJECTS_$(1)) $$(C_OBJECTS_$(1))
|
$(1): $$(ASM_OBJECTS_$(1)) $$(C_OBJECTS_$(1))
|
||||||
$(SILENT)$(CC) $(LDFLAGS) $(LD_OPTIONAL) -T"libboard/common/resources/$(CHIP)/$$@.ld" -Wl,-Map,$(OUTPUT)-$$@.map -o $(OUTPUT)-$$@.elf $$^ $(LIBS)
|
$(SILENT)$(CC) $(LDFLAGS) $(LD_OPTIONAL) -T"libboard/common/resources/$(CHIP)/$$@.ld" -Wl,-Map,$(OUTPUT)-$$@.map -o $(OUTPUT)-$$@.elf $$^ $(LIBS)
|
||||||
|
cp $(OUTPUT)-$$@.elf $(OUTPUT)-$$@-$(GIT_VERSION).elf
|
||||||
|
cp $(OUTPUT)-$$@.elf $(OUTPUT)-$$@-latest.elf
|
||||||
$(SILENT)$(NM) $(OUTPUT)-$$@.elf >$(OUTPUT)-$$@.elf.txt
|
$(SILENT)$(NM) $(OUTPUT)-$$@.elf >$(OUTPUT)-$$@.elf.txt
|
||||||
$(SILENT)$(OBJCOPY) -O binary $(OUTPUT)-$$@.elf $(OUTPUT)-$$@.bin
|
$(SILENT)$(OBJCOPY) -O binary $(OUTPUT)-$$@.elf $(OUTPUT)-$$@.bin
|
||||||
|
cp $(OUTPUT)-$$@.bin $(OUTPUT)-$$@-$(GIT_VERSION).bin
|
||||||
|
cp $(OUTPUT)-$$@.bin $(OUTPUT)-$$@-latest.bin
|
||||||
$(SILENT)$(SIZE) $$^ $(OUTPUT)-$$@.elf
|
$(SILENT)$(SIZE) $$^ $(OUTPUT)-$$@.elf
|
||||||
|
|
||||||
$$(C_OBJECTS_$(1)): $(OBJ)/$(1)_%.o: %.c Makefile $(OBJ) $(BIN)
|
$$(C_OBJECTS_$(1)): $(OBJ)/$(1)_%.o: %.c Makefile $(OBJ) $(BIN)
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
C_FILES += $(C_LIBUSB_RT)
|
C_FILES += $(C_LIBUSB_RT)
|
||||||
|
|
||||||
C_FILES += card_emu.c cciddriver.c iso7816_4.c iso7816_fidi.c mitm.c mode_cardemu.c mode_ccid.c simtrace_iso7816.c sniffer.c usb.c
|
C_FILES += card_emu.c iso7816_fidi.c iso7816_3.c iso7816_4.c mode_cardemu.c simtrace_iso7816.c usb.c
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ extern int main(void)
|
|||||||
while (USBD_GetState() < USBD_STATE_CONFIGURED) {
|
while (USBD_GetState() < USBD_STATE_CONFIGURED) {
|
||||||
WDT_Restart(WDT);
|
WDT_Restart(WDT);
|
||||||
check_exec_dbg_cmd();
|
check_exec_dbg_cmd();
|
||||||
#if 0
|
#if 1
|
||||||
if (i >= MAX_USB_ITER * 3) {
|
if (i >= MAX_USB_ITER * 3) {
|
||||||
TRACE_ERROR("Resetting board (USB could "
|
TRACE_ERROR("Resetting board (USB could "
|
||||||
"not be configured)\n\r");
|
"not be configured)\n\r");
|
||||||
@@ -221,7 +221,6 @@ extern int main(void)
|
|||||||
}
|
}
|
||||||
last_simtrace_config = simtrace_config;
|
last_simtrace_config = simtrace_config;
|
||||||
} else {
|
} else {
|
||||||
//FIXME: usb_proces() for every interface in this configuration?
|
|
||||||
if (config_func_ptrs[simtrace_config].run) {
|
if (config_func_ptrs[simtrace_config].run) {
|
||||||
config_func_ptrs[simtrace_config].run();
|
config_func_ptrs[simtrace_config].run();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -243,17 +243,6 @@ static void check_exec_dbg_cmd(void)
|
|||||||
//board_exec_dbg_cmd(ch);
|
//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
|
* Main
|
||||||
*------------------------------------------------------------------------------*/
|
*------------------------------------------------------------------------------*/
|
||||||
@@ -276,14 +265,16 @@ extern int main(void)
|
|||||||
PIO_Clear(&pinsLeds[LED_NUM_GREEN]);
|
PIO_Clear(&pinsLeds[LED_NUM_GREEN]);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
PIO_InitializeInterrupts(0);
|
||||||
|
|
||||||
EEFC_ReadUniqueID(g_unique_id);
|
EEFC_ReadUniqueID(g_unique_id);
|
||||||
|
|
||||||
printf("\n\r\n\r");
|
printf("\n\r\n\r"
|
||||||
print_line();
|
"=============================================================================\n\r"
|
||||||
printf("DFU bootloader %s for board %s\n\r"
|
"DFU bootloader %s for board %s\n\r"
|
||||||
"(C) 2010-2017 by Harald Welte, 2018-2019 by Kevin Redon\n\r",
|
"(C) 2010-2017 by Harald Welte, 2018-2019 by Kevin Redon\n\r"
|
||||||
|
"=============================================================================\n\r",
|
||||||
manifest_revision, manifest_board);
|
manifest_revision, manifest_board);
|
||||||
print_line();
|
|
||||||
|
|
||||||
#if (TRACE_LEVEL >= TRACE_LEVEL_INFO)
|
#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("Chip ID: 0x%08lx (Ext 0x%08lx)\n\r", CHIPID->CHIPID_CIDR, CHIPID->CHIPID_EXID);
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
C_FILES += $(C_LIBUSB_RT)
|
C_FILES += $(C_LIBUSB_RT)
|
||||||
|
|
||||||
C_FILES += card_emu.c cciddriver.c iso7816_4.c iso7816_fidi.c mitm.c mode_cardemu.c mode_ccid.c simtrace_iso7816.c sniffer.c usb.c
|
C_FILES += iso7816_4.c iso7816_fidi.c simtrace_iso7816.c sniffer.c usb.c
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
C_FILES += $(C_LIBUSB_RT)
|
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 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 tc_etu.c usb.c
|
||||||
|
|||||||
@@ -1672,10 +1672,6 @@ uint8_t USBD_HAL_Halt(uint8_t bEndpoint, uint8_t ctl)
|
|||||||
UDP->UDP_RST_EP |= 1 << bEndpoint;
|
UDP->UDP_RST_EP |= 1 << bEndpoint;
|
||||||
UDP->UDP_RST_EP &= ~(1 << bEndpoint);
|
UDP->UDP_RST_EP &= ~(1 << bEndpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This fixes a weird bug with regard to ping-pong OUT endpoints */
|
|
||||||
UDP->UDP_RST_EP |= 1 << bEndpoint;
|
|
||||||
UDP->UDP_RST_EP &= ~(1 << bEndpoint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return Halt status */
|
/* Return Halt status */
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ struct dfu_desc {
|
|||||||
#define DFU_FUNC_DESC { \
|
#define DFU_FUNC_DESC { \
|
||||||
.bLength = USB_DT_DFU_SIZE, \
|
.bLength = USB_DT_DFU_SIZE, \
|
||||||
.bDescriptorType = USB_DT_DFU, \
|
.bDescriptorType = USB_DT_DFU, \
|
||||||
.bmAttributes = USB_DFU_CAN_UPLOAD | USB_DFU_CAN_DOWNLOAD | USB_DFU_WILL_DETACH, \
|
.bmAttributes = USB_DFU_CAN_UPLOAD | USB_DFU_CAN_DOWNLOAD, \
|
||||||
.wDetachTimeOut = 0x00, \
|
.wDetachTimeOut = 0xff00, \
|
||||||
.wTransferSize = BOARD_DFU_PAGE_SIZE, \
|
.wTransferSize = BOARD_DFU_PAGE_SIZE, \
|
||||||
.bcdDFUVersion = 0x0100, \
|
.bcdDFUVersion = 0x0100, \
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -165,8 +165,6 @@ void USBDFU_Runtime_RequestHandler(const USBGenericRequest *request)
|
|||||||
* will then trigger DFURT_SwitchToDFU() below */
|
* will then trigger DFURT_SwitchToDFU() below */
|
||||||
TRACE_DEBUG("\r\n====dfu_detach\n\r");
|
TRACE_DEBUG("\r\n====dfu_detach\n\r");
|
||||||
g_dfu->state = DFU_STATE_appDETACH;
|
g_dfu->state = DFU_STATE_appDETACH;
|
||||||
USBD_Write(0, 0, 0, 0, 0);
|
|
||||||
DFURT_SwitchToDFU();
|
|
||||||
ret = DFU_RET_ZLP;
|
ret = DFU_RET_ZLP;
|
||||||
goto out;
|
goto out;
|
||||||
break;
|
break;
|
||||||
@@ -211,14 +209,13 @@ out:
|
|||||||
|
|
||||||
void DFURT_SwitchToDFU(void)
|
void DFURT_SwitchToDFU(void)
|
||||||
{
|
{
|
||||||
__disable_irq();
|
|
||||||
|
|
||||||
/* store the magic value that the DFU loader can detect and
|
/* store the magic value that the DFU loader can detect and
|
||||||
* activate itself, rather than boot into the application */
|
* activate itself, rather than boot into the application */
|
||||||
g_dfu->magic = USB_DFU_MAGIC;
|
g_dfu->magic = USB_DFU_MAGIC;
|
||||||
__DMB();
|
|
||||||
/* Disconnect the USB by removing the pull-up */
|
/* Disconnect the USB by removing the pull-up */
|
||||||
USBD_Disconnect();
|
USBD_Disconnect();
|
||||||
|
__disable_irq();
|
||||||
|
|
||||||
/* reset the processor, we will start execution with the
|
/* reset the processor, we will start execution with the
|
||||||
* ResetVector of the bootloader */
|
* ResetVector of the bootloader */
|
||||||
|
|||||||
@@ -50,28 +50,81 @@
|
|||||||
/* Button to force bootloader start (shorted to ground when pressed */
|
/* Button to force bootloader start (shorted to ground when pressed */
|
||||||
#define PIN_BOOTLOADER_SW {PIO_PA5, PIOA, ID_PIOA, PIO_INPUT, PIO_PULLUP}
|
#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
|
// 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) */
|
/* 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 connection **/
|
||||||
/* Phone USIM slot 1 VCC pin (VCC_PHONE in schematic) */
|
/* Phone USIM slot 1 VCC pin (VCC_PHONE in schematic) */
|
||||||
#define PIN_USIM1_VCC {PIO_PA25, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT}
|
#define PIN_USIM1_VCC {PIO_PA25, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT}
|
||||||
/* Phone USIM slot 1 RST pin (active low; RST_PHONE in schematic) */
|
/* Phone USIM slot 1 RST pin (active low; RST_PHONE in schematic) */
|
||||||
#define PIN_USIM1_nRST {PIO_PA24, PIOA, ID_PIOA, PIO_INPUT, PIO_IT_EDGE | PIO_DEGLITCH }
|
#define PIN_USIM1_nRST {PIO_PA24, PIOA, ID_PIOA, PIO_INPUT, PIO_IT_RISE_EDGE | PIO_DEGLITCH }
|
||||||
/* Phone I/O data signal input/output (I/O_PHONE in schematic) */
|
/* Phone I/O data signal input/output (I/O_PHONE in schematic) */
|
||||||
#define PIN_PHONE_IO {PIO_PA22A_TXD1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
|
#define PIN_PHONE_IO {PIO_PA22A_TXD1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
|
||||||
/* Phone CLK clock input (CLK_PHONE in schematic) */
|
/* Phone CLK clock input (CLK_PHONE in schematic) */
|
||||||
#define PIN_PHONE_CLK {PIO_PA23A_SCK1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
|
#define PIN_PHONE_CLK {PIO_PA23A_SCK1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
|
||||||
/* Pin used 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 */
|
/* 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, PIN_USIM1_IO_DIR
|
#define PINS_USIM1 PIN_PHONE_IO, PIN_PHONE_CLK, PIN_PHONE_CLK_INPUT, PIN_USIM1_VCC, PIN_PHONE_IO_INPUT, PIN_USIM1_nRST
|
||||||
/* Phone I/O data signal input/output (unused USART RX input; connected to I/O_PHONE in schematic) */
|
/* Phone I/O data signal input/output (unused USART RX input; connected to I/O_PHONE in schematic) */
|
||||||
#define PIN_PHONE_IO_INPUT {PIO_PA21A_RXD1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
|
#define PIN_PHONE_IO_INPUT {PIO_PA21A_RXD1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
|
||||||
/* Pin used as clock input (to measure the ETU duration; connected to CLK_PHONE in schematic) */
|
/* Pin used as clock input (to measure the ETU duration; connected to CLK_PHONE in schematic) */
|
||||||
#define PIN_PHONE_CLK_INPUT {PIO_PA29B_TCLK2, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
|
#define PIN_PHONE_CLK_INPUT {PIO_PA29B_TCLK2, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
|
||||||
|
|
||||||
/** Default pin configuration **/
|
/** 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 **/
|
/** External SPI flash interface **/
|
||||||
/* SPI MISO pin definition */
|
/* SPI MISO pin definition */
|
||||||
@@ -96,32 +149,21 @@
|
|||||||
/* OpenMoko SIMtrace 2 USB vendor ID */
|
/* OpenMoko SIMtrace 2 USB vendor ID */
|
||||||
#define BOARD_USB_VENDOR_ID USB_VENDOR_OPENMOKO
|
#define BOARD_USB_VENDOR_ID USB_VENDOR_OPENMOKO
|
||||||
/* OpenMoko SIMtrace 2 USB product ID (main application/runtime mode) */
|
/* OpenMoko SIMtrace 2 USB product ID (main application/runtime mode) */
|
||||||
#define BOARD_USB_PRODUCT_ID USB_PRODUCT_OCTSIMTEST
|
#define BOARD_USB_PRODUCT_ID USB_PRODUCT_SIMTRACE2
|
||||||
/* OpenMoko SIMtrace 2 DFU USB product ID (DFU bootloader/DFU mode) */
|
/* OpenMoko SIMtrace 2 DFU USB product ID (DFU bootloader/DFU mode) */
|
||||||
#define BOARD_DFU_USB_PRODUCT_ID USB_PRODUCT_OCTSIMTEST
|
#define BOARD_DFU_USB_PRODUCT_ID USB_PRODUCT_SIMTRACE2_DFU
|
||||||
/* USB release number (bcdDevice, shown as 0.00) */
|
/* USB release number (bcdDevice, shown as 0.00) */
|
||||||
#define BOARD_USB_RELEASE 0x000
|
#define BOARD_USB_RELEASE 0x000
|
||||||
/* Indicate SIMtrace is bus power in USB attributes */
|
/* Indicate SIMtrace is bus power in USB attributes */
|
||||||
#define BOARD_USB_BMATTRIBUTES USBConfigurationDescriptor_BUSPOWERED_NORWAKEUP
|
#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 */
|
/** Supported modes */
|
||||||
/* SIMtrace board supports sniffer mode */
|
/* SIMtrace board supports sniffer mode */
|
||||||
//#define HAVE_SNIFFER
|
//#define HAVE_SNIFFER
|
||||||
/* SIMtrace board supports CCID mode */
|
/* SIMtrace board supports CCID mode */
|
||||||
//#define HAVE_CCID
|
//#define HAVE_CCID
|
||||||
/* SIMtrace board supports card emulation mode */
|
/* SIMtrace board supports card emulation mode */
|
||||||
#define HAVE_CARDEM
|
//#define HAVE_CARDEM
|
||||||
/* SIMtrace board supports man-in-the-middle mode */
|
/* SIMtrace board supports man-in-the-middle mode */
|
||||||
//#define HAVE_MITM
|
//#define HAVE_MITM
|
||||||
/* octsimtest board supports gpio_test mode */
|
/* octsimtest board supports gpio_test mode */
|
||||||
|
|||||||
@@ -18,10 +18,8 @@
|
|||||||
|
|
||||||
#define MCP23017_ADDRESS 0x20
|
#define MCP23017_ADDRESS 0x20
|
||||||
|
|
||||||
int mcp23017_init(uint8_t slave, uint8_t iodira, uint8_t iodirb);
|
int mcp23017_init(uint8_t slave);
|
||||||
int mcp23017_test(uint8_t slave);
|
int mcp23017_test(uint8_t slave);
|
||||||
int mcp23017_toggle(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_write_byte(uint8_t slave, uint8_t addr, uint8_t byte);
|
||||||
//int mcp23017_read_byte(uint8_t slave, uint8_t addr);
|
//int mcp23017_read_byte(uint8_t slave, uint8_t addr);
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
#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
|
|
||||||
@@ -17,7 +17,6 @@
|
|||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
|
||||||
*/
|
*/
|
||||||
#include <stdbool.h>
|
|
||||||
#include "board.h"
|
#include "board.h"
|
||||||
#include "simtrace.h"
|
#include "simtrace.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
@@ -26,29 +25,16 @@
|
|||||||
#include "usb_buf.h"
|
#include "usb_buf.h"
|
||||||
#include "i2c.h"
|
#include "i2c.h"
|
||||||
#include "mcp23017.h"
|
#include "mcp23017.h"
|
||||||
#include "mux.h"
|
|
||||||
|
|
||||||
static bool mcp2317_present = false;
|
|
||||||
|
|
||||||
void board_exec_dbg_cmd(int ch)
|
void board_exec_dbg_cmd(int ch)
|
||||||
{
|
{
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case '?':
|
case '?':
|
||||||
printf("\t?\thelp\n\r");
|
printf("\t?\thelp\n\r");
|
||||||
printf("\t0-8\tselect physical SIM slot\n\r");
|
|
||||||
printf("\tR\treset SAM3\n\r");
|
printf("\tR\treset SAM3\n\r");
|
||||||
printf("\tm\trun mcp23017 test\n\r");
|
printf("\tm\trun mcp23017 test\n\r");
|
||||||
printf("\ti\tset card insert via I2C\n\r");
|
printf("\tR\ttoggle MSB of gpio on mcp23017\n\r");
|
||||||
printf("\tI\tdisable card insert\n\r");
|
|
||||||
break;
|
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':
|
case 'R':
|
||||||
printf("Asking NVIC to reset us\n\r");
|
printf("Asking NVIC to reset us\n\r");
|
||||||
USBD_Disconnect();
|
USBD_Disconnect();
|
||||||
@@ -57,13 +43,8 @@ void board_exec_dbg_cmd(int ch)
|
|||||||
case 'm':
|
case 'm':
|
||||||
mcp23017_test(MCP23017_ADDRESS);
|
mcp23017_test(MCP23017_ADDRESS);
|
||||||
break;
|
break;
|
||||||
case 'i':
|
case 't':
|
||||||
printf("Setting card insert (slot=%u)\r\n", mux_get_slot());
|
mcp23017_toggle(MCP23017_ADDRESS);
|
||||||
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;
|
break;
|
||||||
default:
|
default:
|
||||||
printf("Unknown command '%c'\n\r", ch);
|
printf("Unknown command '%c'\n\r", ch);
|
||||||
@@ -76,13 +57,9 @@ void board_main_top(void)
|
|||||||
#ifndef APPLICATION_dfu
|
#ifndef APPLICATION_dfu
|
||||||
usb_buf_init();
|
usb_buf_init();
|
||||||
|
|
||||||
mux_init();
|
|
||||||
i2c_pin_init();
|
i2c_pin_init();
|
||||||
/* PORT A: all outputs, Port B0 output, B1..B7 unused */
|
if (!mcp23017_init(MCP23017_ADDRESS))
|
||||||
if (mcp23017_init(MCP23017_ADDRESS, 0x00, 0xfe) == 0) {
|
printf("mcp23017 not found!\n\r");
|
||||||
mcp2317_present = true;
|
|
||||||
mcp23017_set_output_a(MCP23017_ADDRESS, 0);
|
|
||||||
}
|
|
||||||
/* Initialize checking for card insert/remove events */
|
/* Initialize checking for card insert/remove events */
|
||||||
//card_present_init();
|
//card_present_init();
|
||||||
#endif
|
#endif
|
||||||
@@ -102,23 +79,3 @@ int board_override_enter_dfu(void)
|
|||||||
} else
|
} else
|
||||||
return 0;
|
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -92,25 +92,19 @@ out_stop:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mcp23017_init(uint8_t slave, uint8_t iodira, uint8_t iodirb)
|
int mcp23017_init(uint8_t slave)
|
||||||
{
|
{
|
||||||
TRACE_DEBUG("mcp23017_init\n\r");
|
printf("mcp23017_init\n\r");
|
||||||
|
|
||||||
// all gpio input
|
// all gpio input
|
||||||
if (mcp23017_write_byte(slave, MCP23017_IODIRA, iodira))
|
if (mcp23017_write_byte(slave, MCP23017_IODIRA, 0xff))
|
||||||
goto out_err;
|
return false;
|
||||||
// msb of portb output, rest input
|
// msb of portb output, rest input
|
||||||
if (mcp23017_write_byte(slave, MCP23017_IODIRB, iodirb))
|
if (mcp23017_write_byte(slave, MCP23017_IODIRB, 0x7f))
|
||||||
goto out_err;
|
return false;
|
||||||
if (mcp23017_write_byte(slave, MCP23017_IOCONA, 0x20)) //disable SEQOP (autoinc addressing)
|
if (mcp23017_write_byte(slave, MCP23017_IOCONA, 0x20)) //disable SEQOP (autoinc addressing)
|
||||||
goto out_err;
|
return false;
|
||||||
|
printf("mcp23017 found\n\r");
|
||||||
TRACE_DEBUG("mcp23017 found\n\r");
|
return true;
|
||||||
return 0;
|
|
||||||
|
|
||||||
out_err:
|
|
||||||
TRACE_WARNING("mcp23017 NOT found!\n\r");
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int mcp23017_test(uint8_t slave)
|
int mcp23017_test(uint8_t slave)
|
||||||
@@ -126,16 +120,6 @@ int mcp23017_test(uint8_t slave)
|
|||||||
return 0;
|
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)
|
int mcp23017_toggle(uint8_t slave)
|
||||||
{
|
{
|
||||||
// example writing MSB of gpio
|
// example writing MSB of gpio
|
||||||
|
|||||||
@@ -1,113 +0,0 @@
|
|||||||
/* 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);
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
/* 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
|
|
||||||
}
|
|
||||||
@@ -91,8 +91,8 @@
|
|||||||
#define PINS_WWAN_IN { PIN_WWAN1, PIN_WWAN2 }
|
#define PINS_WWAN_IN { PIN_WWAN1, PIN_WWAN2 }
|
||||||
|
|
||||||
/* outputs controlling RESET input of modems */
|
/* outputs controlling RESET input of modems */
|
||||||
#define PIN_PERST1 {PIO_PA25, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_PULLUP}
|
#define PIN_PERST1 {PIO_PA25, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_PULLUP}
|
||||||
#define PIN_PERST2 {PIO_PA26, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_PULLUP}
|
#define PIN_PERST2 {PIO_PA26, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_PULLUP}
|
||||||
#define PINS_PERST { PIN_PERST1, PIN_PERST2 }
|
#define PINS_PERST { PIN_PERST1, PIN_PERST2 }
|
||||||
|
|
||||||
#define PIN_VERSION_DET {PIO_PA19, PIOA, ID_PIOA, PIO_PERIPH_D, PIO_DEFAULT}
|
#define PIN_VERSION_DET {PIO_PA19, PIOA, ID_PIOA, PIO_PERIPH_D, PIO_DEFAULT}
|
||||||
@@ -109,9 +109,9 @@
|
|||||||
#define BOARD_USB_RELEASE 0x010
|
#define BOARD_USB_RELEASE 0x010
|
||||||
|
|
||||||
#define CARDEMU_SECOND_UART
|
#define CARDEMU_SECOND_UART
|
||||||
|
|
||||||
#define DETECT_VCC_BY_ADC
|
#define DETECT_VCC_BY_ADC
|
||||||
#define VCC_UV_THRESH_1V8 1500000
|
|
||||||
#define VCC_UV_THRESH_3V 2500000
|
|
||||||
|
|
||||||
|
/** sysmoQMOD only supports card emulation */
|
||||||
|
#ifdef APPLICATION_cardem
|
||||||
#define HAVE_CARDEM
|
#define HAVE_CARDEM
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -80,9 +80,9 @@
|
|||||||
/* Phone I/O data signal input/output (I/O_PHONE in schematic) */
|
/* Phone I/O data signal input/output (I/O_PHONE in schematic) */
|
||||||
#define PIN_USIM1_IO {PIO_PA22A_TXD1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
|
#define PIN_USIM1_IO {PIO_PA22A_TXD1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
|
||||||
/* Phone CLK clock input (CLK_PHONE in schematic) */
|
/* Phone CLK clock input (CLK_PHONE in schematic) */
|
||||||
#define PIN_USIM1_CLK {PIO_PA23A_SCK1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
|
#define PIN_PHONE_CLK {PIO_PA23A_SCK1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
|
||||||
/* Pin used for phone USIM slot 1 communication */
|
/* Pin used for phone USIM slot 1 communication */
|
||||||
#define PINS_USIM1 PIN_USIM1_IO, PIN_USIM1_CLK, PIN_PHONE_CLK_INPUT, PIN_USIM1_VCC, PIN_PHONE_IO_INPUT, PIN_USIM1_nRST
|
#define PINS_USIM1 PIN_USIM1_IO, PIN_PHONE_CLK, PIN_PHONE_CLK_INPUT, PIN_USIM1_VCC, PIN_PHONE_IO_INPUT, PIN_USIM1_nRST
|
||||||
/* Phone I/O data signal input/output (unused USART RX input; connected to I/O_PHONE in schematic) */
|
/* Phone I/O data signal input/output (unused USART RX input; connected to I/O_PHONE in schematic) */
|
||||||
#define PIN_PHONE_IO_INPUT {PIO_PA21A_RXD1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
|
#define PIN_PHONE_IO_INPUT {PIO_PA21A_RXD1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
|
||||||
/* Pin used as clock input (to measure the ETU duration; connected to CLK_PHONE in schematic) */
|
/* Pin used as clock input (to measure the ETU duration; connected to CLK_PHONE in schematic) */
|
||||||
@@ -120,6 +120,14 @@
|
|||||||
/* ISO7816-communication related pins */
|
/* ISO7816-communication related pins */
|
||||||
#define PINS_ISO7816 PIN_SIM_IO, PIN_SIM_CLK, PIN_ISO7816_RSTMC // SIM_PWEN_PIN, PIN_SIM_IO2, PIN_SIM_CLK2
|
#define PINS_ISO7816 PIN_SIM_IO, PIN_SIM_CLK, PIN_ISO7816_RSTMC // SIM_PWEN_PIN, PIN_SIM_IO2, PIN_SIM_CLK2
|
||||||
|
|
||||||
|
/** card emulation configuration */
|
||||||
|
/* Disable power converter 4.5-6V to 3.3V (active high) */
|
||||||
|
#define PIN_SIM_PWEN_CARDEMU {PIO_PA5, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
|
||||||
|
/* Disable power switch to forward VCC_PHONE to VCC_SIM (active high) */
|
||||||
|
#define PIN_VCC_FWD_CARDEMU {PIO_PA26, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
|
||||||
|
/* Disable power to SIM */
|
||||||
|
#define PINS_PWR_CARDEMU PIN_SIM_PWEN_CARDEMU, PIN_VCC_FWD_CARDEMU
|
||||||
|
|
||||||
/** External SPI flash interface **/
|
/** External SPI flash interface **/
|
||||||
/* SPI MISO pin definition */
|
/* SPI MISO pin definition */
|
||||||
#define PIN_SPI_MISO {PIO_PA12A_MISO, PIOA, PIOA, PIO_PERIPH_A, PIO_PULLUP}
|
#define PIN_SPI_MISO {PIO_PA12A_MISO, PIOA, PIOA, PIO_PERIPH_A, PIO_PULLUP}
|
||||||
@@ -157,10 +165,14 @@
|
|||||||
#define HAVE_SNIFFER
|
#define HAVE_SNIFFER
|
||||||
#endif
|
#endif
|
||||||
/* SIMtrace board supports CCID mode */
|
/* SIMtrace board supports CCID mode */
|
||||||
|
#ifdef APPLICATION_ccid
|
||||||
//#define HAVE_CCID
|
//#define HAVE_CCID
|
||||||
|
#endif
|
||||||
/* SIMtrace board supports card emulation mode */
|
/* SIMtrace board supports card emulation mode */
|
||||||
#ifdef APPLICATION_cardem
|
#ifdef APPLICATION_cardem
|
||||||
#define HAVE_CARDEM
|
#define HAVE_CARDEM
|
||||||
#endif
|
#endif
|
||||||
/* SIMtrace board supports man-in-the-middle mode */
|
/* SIMtrace board supports man-in-the-middle mode */
|
||||||
|
#ifdef APPLICATION_mitm
|
||||||
//#define HAVE_MITM
|
//#define HAVE_MITM
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -22,6 +22,15 @@
|
|||||||
#include "led.h"
|
#include "led.h"
|
||||||
#include "sim_switch.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)
|
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_sc = PIN_SC_SW_DEFAULT; // pin to control bus switch for VCC/RST/CLK signals
|
||||||
|
|||||||
@@ -89,7 +89,7 @@
|
|||||||
/// \param condition Condition to verify.
|
/// \param condition Condition to verify.
|
||||||
#define ASSERT(condition) { \
|
#define ASSERT(condition) { \
|
||||||
if (!(condition)) { \
|
if (!(condition)) { \
|
||||||
printf_sync("-F- ASSERT: %s %s:%d\n\r", #condition, __BASE_FILE__, __LINE__); \
|
printf("-F- ASSERT: %s %s:%d\n\r", #condition, __BASE_FILE__, __LINE__); \
|
||||||
while (1); \
|
while (1); \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ enum card_io {
|
|||||||
|
|
||||||
/** initialise card slot
|
/** initialise card slot
|
||||||
* @param[in] slot_num slot number (arbitrary number)
|
* @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] uart_chan UART peripheral channel
|
||||||
* @param[in] in_ep USB IN end point number
|
* @param[in] in_ep USB IN end point number
|
||||||
* @param[in] irq_ep USB INTerrupt end point number
|
* @param[in] irq_ep USB INTerrupt end point number
|
||||||
@@ -39,7 +40,7 @@ enum card_io {
|
|||||||
* @param[in] clocked initial CLK signat state (true = active)
|
* @param[in] clocked initial CLK signat state (true = active)
|
||||||
* @return main card handle reference
|
* @return main card handle reference
|
||||||
*/
|
*/
|
||||||
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 *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);
|
||||||
|
|
||||||
/* process a single byte received from the reader */
|
/* process a single byte received from the reader */
|
||||||
void card_emu_process_rx_byte(struct card_handle *ch, uint8_t byte);
|
void card_emu_process_rx_byte(struct card_handle *ch, uint8_t byte);
|
||||||
@@ -57,17 +58,43 @@ struct llist_head *card_emu_get_uart_tx_queue(struct card_handle *ch);
|
|||||||
void card_emu_have_new_uart_tx(struct card_handle *ch);
|
void card_emu_have_new_uart_tx(struct card_handle *ch);
|
||||||
void card_emu_report_status(struct card_handle *ch, bool report_on_irq);
|
void card_emu_report_status(struct card_handle *ch, bool report_on_irq);
|
||||||
|
|
||||||
void card_emu_wtime_half_expired(void *ch);
|
/*! call when the waiting time has half-expired
|
||||||
void card_emu_wtime_expired(void *ch);
|
* param[in] ch card for which the waiting time half expired
|
||||||
|
*/
|
||||||
|
void card_emu_wt_halfed(void *ch);
|
||||||
|
/*! call when the waiting time has expired
|
||||||
|
* param[in] ch card for which the waiting time expired
|
||||||
|
*/
|
||||||
|
void card_emu_wt_expired(void *ch);
|
||||||
|
|
||||||
#define ENABLE_TX 0x01
|
#define ENABLE_TX 0x01
|
||||||
#define ENABLE_RX 0x02
|
#define ENABLE_RX 0x02
|
||||||
#define ENABLE_TX_TIMER_ONLY 0x03
|
|
||||||
|
// the following functions are callbacks implement in mode_cardemu.c
|
||||||
|
|
||||||
int card_emu_uart_update_fidi(uint8_t uart_chan, unsigned int fidi);
|
int card_emu_uart_update_fidi(uint8_t uart_chan, unsigned int fidi);
|
||||||
|
|
||||||
|
/*! update F and D on USART peripheral
|
||||||
|
* @param[in] usart USART peripheral to configure
|
||||||
|
* @param[in] f clock rate conversion integer F value
|
||||||
|
* @param[in] d baud rate adjustment factor D value
|
||||||
|
* @note this should happen after reset and protocol select (through PPS or implicit)
|
||||||
|
*/
|
||||||
|
void card_emu_uart_update_fd(uint8_t uart_chan, uint16_t f, uint8_t d);
|
||||||
|
/*! update WT on USART peripheral
|
||||||
|
* @param[in] usart USART peripheral to configure
|
||||||
|
* @param[in] wt inactivity Waiting Time before card_emu_wt_expired is called (0 to disable)
|
||||||
|
*/
|
||||||
void card_emu_uart_update_wt(uint8_t uart_chan, uint32_t wt);
|
void card_emu_uart_update_wt(uint8_t uart_chan, uint32_t wt);
|
||||||
|
/*! reset waiting timeout count down on USART peripheral
|
||||||
|
* @param[in] usart USART peripheral to configure
|
||||||
|
*/
|
||||||
void card_emu_uart_reset_wt(uint8_t uart_chan);
|
void card_emu_uart_reset_wt(uint8_t uart_chan);
|
||||||
|
/*! set I/O line high
|
||||||
|
* @param[in] usart USART peripheral to configure
|
||||||
|
* @param[in] set if I/O line should be set high (true), or cleared low (false)
|
||||||
|
*/
|
||||||
|
void card_emu_uart_io_set(uint8_t uart_chan, bool set);
|
||||||
int card_emu_uart_tx(uint8_t uart_chan, uint8_t byte);
|
int card_emu_uart_tx(uint8_t uart_chan, uint8_t byte);
|
||||||
void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx);
|
void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx);
|
||||||
void card_emu_uart_wait_tx_idle(uint8_t uart_chan);
|
void card_emu_uart_wait_tx_idle(uint8_t uart_chan);
|
||||||
|
|||||||
98
firmware/libcommon/include/iso7816_3.h
Normal file
98
firmware/libcommon/include/iso7816_3.h
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
/* this library provides utilities to handle the ISO-7816 part 3 communication aspects (e.g. related to F and D) */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
/** default clock rate conversion integer Fd
|
||||||
|
* @implements ISO/IEC 7816-3:2006(E) section 8.1
|
||||||
|
*/
|
||||||
|
#define ISO7816_3_DEFAULT_FD 372
|
||||||
|
/** default baud rate adjustment factor Dd
|
||||||
|
* @implements ISO/IEC 7816-3:2006(E) section 8.1
|
||||||
|
*/
|
||||||
|
#define ISO7816_3_DEFAULT_DD 1
|
||||||
|
/** default clock rate conversion integer Fi
|
||||||
|
* @implements ISO/IEC 7816-3:2006(E) section 8.3
|
||||||
|
* @note non-default value is optionally specified in TA1
|
||||||
|
*/
|
||||||
|
#define ISO7816_3_DEFAULT_FI 372
|
||||||
|
/** default baud rate adjustment factor Di
|
||||||
|
* @implements ISO/IEC 7816-3:2006(E) section 8.3
|
||||||
|
* @note non-default value is optionally specified in TA1
|
||||||
|
*/
|
||||||
|
#define ISO7816_3_DEFAULT_DI 1
|
||||||
|
/** default maximum clock frequency, in Hz
|
||||||
|
* @implements ISO/IEC 7816-3:2006(E) section 8.3
|
||||||
|
* @note non-default value is optionally specified in TA1
|
||||||
|
*/
|
||||||
|
#define ISO7816_3_DEFAULT_FMAX 5000000UL
|
||||||
|
/** default Waiting Integer (WI) value for T=0
|
||||||
|
* @implements ISO/IEC 7816-3:2006(E) section 10.2
|
||||||
|
* @note non-default value is optionally specified in TC2
|
||||||
|
*/
|
||||||
|
#define ISO7816_3_DEFAULT_WI 10
|
||||||
|
/** default Waiting Time (WT) value, in ETU
|
||||||
|
* @implements ISO/IEC 7816-3:2006(E) section 8.1
|
||||||
|
* @note depends on Fi, Di, and WI if protocol T=0 is selected
|
||||||
|
*/
|
||||||
|
#define ISO7816_3_DEFAULT_WT 9600
|
||||||
|
|
||||||
|
/** Table encoding the clock rate conversion integer Fi
|
||||||
|
* @note Fi is indicated in TA1, but the same table is used for F and Fn during PPS
|
||||||
|
* @implements ISO/IEC 7816-3:2006(E) table 7
|
||||||
|
*/
|
||||||
|
extern const uint16_t iso7816_3_fi_table[];
|
||||||
|
|
||||||
|
/** Table encoding the maximum clock frequency f_max in Hz
|
||||||
|
* @implements ISO/IEC 7816-3:2006(E) table 7
|
||||||
|
* @note f_max is indicated in TA1, but the same table is used for F and Fn during PPS
|
||||||
|
*/
|
||||||
|
extern const uint32_t iso7816_3_fmax_table[];
|
||||||
|
|
||||||
|
/** Table encoding the baud rate adjust integer Di
|
||||||
|
* @implements ISO/IEC 7816-3:2006(E) table 8
|
||||||
|
* @note Di is indicated in TA1, but the same table is used for D and Dn during PPS
|
||||||
|
*/
|
||||||
|
extern const uint8_t iso7816_3_di_table[];
|
||||||
|
|
||||||
|
/* verify if the clock rate conversion integer F value is valid
|
||||||
|
* @param[in] f F value to be validated
|
||||||
|
* @return if F value is valid
|
||||||
|
* @note only values in ISO/IEC 7816-3:2006(E) table 7 are valid
|
||||||
|
*/
|
||||||
|
bool iso7816_3_valid_f(uint16_t f);
|
||||||
|
/* verify if the baud rate adjustment factor D value is valid
|
||||||
|
* @param[in] d D value to be validated
|
||||||
|
* @return if D value is valid
|
||||||
|
* @note only values in ISO/IEC 7816-3:2006(E) table 8 are valid
|
||||||
|
*/
|
||||||
|
bool iso7816_3_valid_d(uint8_t d);
|
||||||
|
/** calculate Waiting Time (WT)
|
||||||
|
* @param[in] wi Waiting Integer
|
||||||
|
* @param[in] fi clock rate conversion integer Fi value
|
||||||
|
* @param[in] di baud rate adjustment factor Di value
|
||||||
|
* @param[in] f clock rate conversion integer F value
|
||||||
|
* @param[in] d baud rate adjustment factor D value
|
||||||
|
* @return Waiting Time WT, in ETU, or < 0 on error (see code for return codes)
|
||||||
|
* @note this should happen after reset and T=0 protocol select (through PPS or implicit)
|
||||||
|
* @implements ISO/IEC 7816-3:2006(E) section 8.1 and 10.2
|
||||||
|
*/
|
||||||
|
int32_t iso7816_3_calculate_wt(uint8_t wi, uint16_t fi, uint8_t di, uint16_t f, uint8_t d);
|
||||||
@@ -21,10 +21,10 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
/* Table 7 of ISO 7816-3:2006 */
|
/* Table 7 of ISO 7816-3:2006 */
|
||||||
extern const uint16_t iso7816_3_fi_table[16];
|
extern const uint16_t fi_table[];
|
||||||
|
|
||||||
/* Table 8 from ISO 7816-3:2006 */
|
/* Table 8 from ISO 7816-3:2006 */
|
||||||
extern const uint8_t iso7816_3_di_table[16];
|
extern const uint8_t di_table[];
|
||||||
|
|
||||||
/* compute the F/D ratio based on F_index and D_index values */
|
/* compute the F/D ratio based on Fi and Di values */
|
||||||
int iso7816_3_compute_fd_ratio(uint8_t f_index, uint8_t d_index);
|
int compute_fidi_ratio(uint8_t fi, uint8_t di);
|
||||||
|
|||||||
@@ -230,17 +230,10 @@ struct cardemu_usb_msg_status {
|
|||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
/* phone-applied target voltage in mV */
|
/* phone-applied target voltage in mV */
|
||||||
uint16_t voltage_mv;
|
uint16_t voltage_mv;
|
||||||
/* F/D related information. Not actual Fn/Dn values but indexes into tables! */
|
uint8_t f; /*!< index of F and f_max values as encoded in ISO/IEC 7816-3:2006(E) Table 7 */
|
||||||
union {
|
uint8_t d; /*!< index of D value as encoded in ISO/IEC 7816-3:2006(E) Table 8 */
|
||||||
uint8_t F_index; /* <! Index to ISO7816-3 Table 7 (F and f_max values) */
|
uint8_t wi; /*!< Waiting Integer as defined in ISO/IEC 7816-3:2006(E) Section 10.2 */
|
||||||
uint8_t fi; /* <! old, wrong name for API compatibility */
|
uint32_t wt; /*!< Waiting Time in ETU as defined in ISO/IEC 7816-3:2006(E) Section 8.1 */
|
||||||
};
|
|
||||||
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));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
/* CEMU_USB_MSGT_DO_PTS */
|
/* CEMU_USB_MSGT_DO_PTS */
|
||||||
@@ -269,8 +262,6 @@ struct cardemu_usb_msg_error {
|
|||||||
struct cardemu_usb_msg_config {
|
struct cardemu_usb_msg_config {
|
||||||
/* bit-mask of CEMU_FEAT_F flags */
|
/* bit-mask of CEMU_FEAT_F flags */
|
||||||
uint32_t features;
|
uint32_t features;
|
||||||
/* the selected slot number (if an external mux is present) */
|
|
||||||
uint8_t slot_mux_nr;
|
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
|
|||||||
@@ -25,7 +25,6 @@
|
|||||||
#define USB_PRODUCT_QMOD_SAM3 0x4004
|
#define USB_PRODUCT_QMOD_SAM3 0x4004
|
||||||
#define USB_PRODUCT_SIMTRACE2_DFU 0x60e3 /* was 0x60e2 */
|
#define USB_PRODUCT_SIMTRACE2_DFU 0x60e3 /* was 0x60e2 */
|
||||||
#define USB_PRODUCT_SIMTRACE2 0x60e3
|
#define USB_PRODUCT_SIMTRACE2 0x60e3
|
||||||
#define USB_PRODUCT_OCTSIMTEST 0x616d
|
|
||||||
|
|
||||||
/* USB proprietary class */
|
/* USB proprietary class */
|
||||||
#define USB_CLASS_PROPRIETARY 0xff
|
#define USB_CLASS_PROPRIETARY 0xff
|
||||||
|
|||||||
@@ -7,5 +7,3 @@ void tc_etu_init(uint8_t chan_nr, void *handle);
|
|||||||
void tc_etu_enable(uint8_t chan_nr);
|
void tc_etu_enable(uint8_t chan_nr);
|
||||||
void tc_etu_disable(uint8_t chan_nr);
|
void tc_etu_disable(uint8_t chan_nr);
|
||||||
|
|
||||||
extern void tc_etu_wtime_half_expired(void *handle);
|
|
||||||
extern void tc_etu_wtime_expired(void *handle);
|
|
||||||
|
|||||||
@@ -42,15 +42,5 @@ int usb_drain_queue(uint8_t ep);
|
|||||||
void usb_buf_init(void);
|
void usb_buf_init(void);
|
||||||
struct usb_buffered_ep *usb_get_buf_ep(uint8_t ep);
|
struct usb_buffered_ep *usb_get_buf_ep(uint8_t ep);
|
||||||
|
|
||||||
struct usb_if {
|
int usb_refill_to_host(uint8_t ep);
|
||||||
uint8_t if_num; /* interface number */
|
int usb_refill_from_host(uint8_t ep);
|
||||||
uint8_t ep_out; /* OUT endpoint (0 if none) */
|
|
||||||
uint8_t ep_in; /* IN endpint (0 if none) */
|
|
||||||
uint8_t ep_int; /* INT endpoint (0 if none) */
|
|
||||||
void *data; /* opaque data, passed through */
|
|
||||||
struct {
|
|
||||||
/* call-back to be called for inclming messages on OUT EP */
|
|
||||||
void (*rx_out)(struct msgb *msg, const struct usb_if *usb_if);
|
|
||||||
} ops;
|
|
||||||
};
|
|
||||||
void usb_process(const struct usb_if *usb_if);
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* ISO7816-3 state machine for the card side
|
/* ISO7816-3 state machine for the card side
|
||||||
*
|
*
|
||||||
* (C) 2010-2021 by Harald Welte <laforge@gnumonks.org>
|
* (C) 2010-2019 by Harald Welte <laforge@gnumonks.org>
|
||||||
* (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
|
* (C) 2018-2019 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -26,16 +26,15 @@
|
|||||||
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
|
#include "iso7816_3.h"
|
||||||
#include "iso7816_fidi.h"
|
#include "iso7816_fidi.h"
|
||||||
|
#include "tc_etu.h"
|
||||||
#include "card_emu.h"
|
#include "card_emu.h"
|
||||||
#include "simtrace_prot.h"
|
#include "simtrace_prot.h"
|
||||||
#include "usb_buf.h"
|
#include "usb_buf.h"
|
||||||
#include <osmocom/core/linuxlist.h>
|
#include <osmocom/core/linuxlist.h>
|
||||||
#include <osmocom/core/msgb.h>
|
#include <osmocom/core/msgb.h>
|
||||||
|
|
||||||
#ifdef HAVE_SLOT_MUX
|
|
||||||
#include "mux.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define NUM_SLOTS 2
|
#define NUM_SLOTS 2
|
||||||
|
|
||||||
@@ -156,34 +155,54 @@ struct card_handle {
|
|||||||
bool in_reset; /*< if card is in reset (true = RST low/asserted, false = RST high/ released) */
|
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) */
|
bool clocked; /*< if clock is active ( true = active, false = inactive) */
|
||||||
|
|
||||||
/* All below variables with _index suffix are indexes from 0..15 into Tables 7 + 8
|
uint8_t tc_chan; /* TC channel number */
|
||||||
* of ISO7816-3. */
|
|
||||||
|
|
||||||
/*! Index to clock rate conversion integer Fi (ISO7816-3 Table 7).
|
|
||||||
* \note this represents the maximum value supported by the card, and can be indicated in TA1 */
|
|
||||||
uint8_t Fi_index;
|
|
||||||
/*! Current value of index to clock rate conversion integer F (ISO 7816-3 Section 7.1). */
|
|
||||||
uint8_t F_index;
|
|
||||||
|
|
||||||
/*! Index to baud rate adjustment factor Di (ISO7816-3 Table 8).
|
|
||||||
* \note this represents the maximum value supported by the card, and can be indicated in TA1 */
|
|
||||||
uint8_t Di_index;
|
|
||||||
/*! Current value of index to baud rate adjustment factor D (ISO 7816-3 Section 7.1). */
|
|
||||||
uint8_t D_index;
|
|
||||||
|
|
||||||
/*! Waiting Integer (ISO7816-3 Section 10.2).
|
|
||||||
* \note this value can be set in TA2 */
|
|
||||||
uint8_t wi;
|
|
||||||
|
|
||||||
/*! Waiting Time, in ETU (ISO7816-3 Section 8.1).
|
|
||||||
* \note this depends on Fi, Di, and WI if T=0 is used */
|
|
||||||
uint32_t waiting_time; /* in etu */
|
|
||||||
|
|
||||||
uint8_t uart_chan; /* UART channel */
|
uint8_t uart_chan; /* UART channel */
|
||||||
|
|
||||||
uint8_t in_ep; /* USB IN EP */
|
uint8_t in_ep; /* USB IN EP */
|
||||||
uint8_t irq_ep; /* USB IN EP */
|
uint8_t irq_ep; /* USB IN EP */
|
||||||
|
|
||||||
|
/*! clock rate conversion integer F
|
||||||
|
* @implements ISO/IEC 7816-3:2006(E) section 7.1
|
||||||
|
* @note this represents the current value used
|
||||||
|
*/
|
||||||
|
uint16_t f;
|
||||||
|
/*! baud rate adjustment factor D
|
||||||
|
* @implements ISO/IEC 7816-3:2006(E) section 7.1
|
||||||
|
* @note this represents the current value used
|
||||||
|
*/
|
||||||
|
uint8_t d;
|
||||||
|
/*! clock frequency in Hz
|
||||||
|
* @implements ISO/IEC 7816-3:2006(E) section 7.1
|
||||||
|
* @note the USART peripheral in slave mode does not provide the current value. we could measure it but this is not really useful. instead we remember the maximum possible value corresponding to the selected F value
|
||||||
|
*/
|
||||||
|
uint32_t f_cur;
|
||||||
|
/*! clock rate conversion integer Fi
|
||||||
|
* @implements ISO/IEC 7816-3:2006(E) Table 7
|
||||||
|
* @note this represents the maximum value supported by the card, and can be indicated in TA1
|
||||||
|
* @note this value can be set in TA1
|
||||||
|
*/
|
||||||
|
uint16_t fi;
|
||||||
|
/*! baud rate adjustment factor Di
|
||||||
|
* @implements ISO/IEC 7816-3:2006(E) Table 8
|
||||||
|
* @note this represents the maximum value supported by the card, and can be indicated in TA1
|
||||||
|
*/
|
||||||
|
uint8_t di;
|
||||||
|
/*! clock frequency, in Hz
|
||||||
|
* @implements ISO/IEC 7816-3:2006(E) Table 7
|
||||||
|
* @note this represents the maximum value supported by the card, and can be indicated in TA1
|
||||||
|
*/
|
||||||
|
uint32_t f_max;
|
||||||
|
/*! Waiting Integer
|
||||||
|
* @implements ISO/IEC 7816-3:2006(E) Section 10.2
|
||||||
|
* @note this value can be set in TA2
|
||||||
|
*/
|
||||||
|
uint8_t wi;
|
||||||
|
/*! Waiting Time, in ETU
|
||||||
|
* @implements ISO/IEC 7816-3:2006(E) Section 8.1
|
||||||
|
* @note this depends on Fi, Di, and WI if T=0 is used
|
||||||
|
*/
|
||||||
|
uint32_t wt;
|
||||||
|
|
||||||
/* ATR state machine */
|
/* ATR state machine */
|
||||||
struct {
|
struct {
|
||||||
uint8_t idx;
|
uint8_t idx;
|
||||||
@@ -223,7 +242,9 @@ static void card_handle_reset(struct card_handle *ch)
|
|||||||
{
|
{
|
||||||
struct msgb *msg;
|
struct msgb *msg;
|
||||||
|
|
||||||
card_emu_uart_update_wt(ch->uart_chan, 0);
|
#ifndef BOARD_simtrace
|
||||||
|
tc_etu_disable(ch->tc_chan);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* release any buffers we may still own */
|
/* release any buffers we may still own */
|
||||||
if (ch->uart_tx_msg) {
|
if (ch->uart_tx_msg) {
|
||||||
@@ -378,14 +399,16 @@ static void emu_update_fidi(struct card_handle *ch)
|
|||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = iso7816_3_compute_fd_ratio(ch->F_index, ch->D_index);
|
rc = compute_fidi_ratio(ch->fi, ch->di);
|
||||||
if (rc > 0 && rc < 0x400) {
|
if (rc > 0 && rc < 0x400) {
|
||||||
TRACE_INFO("%u: computed F(%u)/D(%u) ratio: %d\r\n", ch->num,
|
TRACE_INFO("%u: computed Fi(%u) Di(%u) ratio: %d\r\n",
|
||||||
ch->F_index, ch->D_index, rc);
|
ch->num, ch->fi, ch->di, rc);
|
||||||
/* make sure UART uses new F/D ratio */
|
/* make sure UART uses new F/D ratio */
|
||||||
card_emu_uart_update_fidi(ch->uart_chan, rc);
|
card_emu_uart_update_fidi(ch->uart_chan, rc);
|
||||||
|
/* notify ETU timer about this */
|
||||||
|
tc_etu_set_etu(ch->tc_chan, rc);
|
||||||
} else
|
} else
|
||||||
TRACE_INFO("%u: computed F/D ratio %d unsupported\r\n",
|
TRACE_INFO("%u: computed FiDi ration %d unsupported\r\n",
|
||||||
ch->num, rc);
|
ch->num, rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -405,35 +428,66 @@ static void card_set_state(struct card_handle *ch,
|
|||||||
case ISO_S_WAIT_POWER:
|
case ISO_S_WAIT_POWER:
|
||||||
case ISO_S_WAIT_CLK:
|
case ISO_S_WAIT_CLK:
|
||||||
case ISO_S_WAIT_RST:
|
case ISO_S_WAIT_RST:
|
||||||
/* disable Rx and Tx of UART */
|
card_emu_uart_enable(ch->uart_chan, 0); // disable Rx and Tx of UART
|
||||||
card_emu_uart_enable(ch->uart_chan, 0);
|
#ifdef BOARD_simtrace
|
||||||
/* disable timeout */
|
card_emu_uart_update_wt(ch->uart_chan, 0); // disable timeout
|
||||||
card_emu_uart_update_wt(ch->uart_chan, 0);
|
if (ISO_S_WAIT_POWER == new_state) {
|
||||||
|
card_emu_uart_io_set(ch->uart_chan, false); // pull I/O line low
|
||||||
|
} else {
|
||||||
|
card_emu_uart_io_set(ch->uart_chan, true); // pull I/O line high
|
||||||
|
}
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
case ISO_S_WAIT_ATR:
|
case ISO_S_WAIT_ATR:
|
||||||
/* Reset to initial Fi / Di ratio */
|
|
||||||
ch->Fi_index = ch->F_index = 1;
|
// reset the ETU-related values
|
||||||
ch->Di_index = ch->D_index = 1;
|
ch->f = ISO7816_3_DEFAULT_FD;
|
||||||
|
ch->d = ISO7816_3_DEFAULT_DD;
|
||||||
|
|
||||||
|
#ifdef BOARD_simtrace
|
||||||
|
card_emu_uart_update_fd(ch->uart_chan, ch->f, ch->d); // set baud rate
|
||||||
|
|
||||||
|
// reset values optionally specified in the ATR
|
||||||
|
ch->fi = ISO7816_3_DEFAULT_FI;
|
||||||
|
ch->di = ISO7816_3_DEFAULT_DI;
|
||||||
ch->wi = ISO7816_3_DEFAULT_WI;
|
ch->wi = ISO7816_3_DEFAULT_WI;
|
||||||
ch->waiting_time = ISO7816_3_INIT_WTIME;
|
int32_t wt = iso7816_3_calculate_wt(ch->wi, ch->fi, ch->di, ch->f, ch->d); // get default waiting time
|
||||||
emu_update_fidi(ch);
|
if (wt <= 0) {
|
||||||
/* enable TX to be able to use the timeout */
|
TRACE_FATAL("%u: invalid WT %ld\r\n", ch->num, wt);
|
||||||
card_emu_uart_enable(ch->uart_chan, ENABLE_TX_TIMER_ONLY);
|
}
|
||||||
|
ch->wt = wt;
|
||||||
|
card_emu_uart_enable(ch->uart_chan, ENABLE_TX); // enable TX to be able to use the timeout
|
||||||
/* the ATR should only be sent 400 to 40k clock cycles after the RESET.
|
/* the ATR should only be sent 400 to 40k clock cycles after the RESET.
|
||||||
* we use the UART timeout 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.
|
* since the initial ETU is Fd=372/Dd=1 clock cycles long, we have to wait 2-107 ETU.
|
||||||
*/
|
*/
|
||||||
card_emu_uart_update_wt(ch->uart_chan, 2);
|
card_emu_uart_update_wt(ch->uart_chan, 2);
|
||||||
|
#else
|
||||||
|
/* Reset to initial Fi / Di ratio */
|
||||||
|
ch->f = 1;
|
||||||
|
ch->d = 1;
|
||||||
|
emu_update_fidi(ch);
|
||||||
|
/* the ATR should only be sent 400 to 40k clock cycles after the RESET.
|
||||||
|
* we use the tc_etu mechanism to wait this time.
|
||||||
|
* since the initial ETU is Fd=372/Dd=1 clock cycles long, we have to wait 2-107 ETU.
|
||||||
|
*/
|
||||||
|
tc_etu_set_wtime(ch->tc_chan, 2);
|
||||||
|
/* enable the TC/ETU counter once reset has been released */
|
||||||
|
tc_etu_enable(ch->tc_chan);
|
||||||
|
#endif
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case ISO_S_IN_ATR:
|
case ISO_S_IN_ATR:
|
||||||
|
#ifndef BOARD_simtrace
|
||||||
/* initialize to default WI, this will be overwritten if we
|
/* initialize to default WI, this will be overwritten if we
|
||||||
* send TC2, and it will be programmed into hardware after
|
* send TC2, and it will be programmed into hardware after
|
||||||
* ATR is finished */
|
* ATR is finished */
|
||||||
ch->wi = ISO7816_3_DEFAULT_WI;
|
ch->wi = ISO7816_3_DEFAULT_WI;
|
||||||
/* update waiting time to initial waiting time */
|
/* update waiting time to initial waiting time */
|
||||||
ch->waiting_time = ISO7816_3_INIT_WTIME;
|
ch->wt = ISO7816_3_INIT_WTIME;
|
||||||
/* set initial waiting time */
|
/* set initial waiting time */
|
||||||
card_emu_uart_update_wt(ch->uart_chan, ch->waiting_time);
|
tc_etu_set_wtime(ch->tc_chan, ch->wt);
|
||||||
|
#endif
|
||||||
/* Set ATR sub-state to initial state */
|
/* Set ATR sub-state to initial state */
|
||||||
ch->atr.idx = 0;
|
ch->atr.idx = 0;
|
||||||
/* enable USART transmission to reader */
|
/* enable USART transmission to reader */
|
||||||
@@ -508,11 +562,15 @@ static int tx_byte_atr(struct card_handle *ch)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* update waiting time (see ISO 7816-3 10.2). We can drop the Fi
|
#ifdef BOARD_simtrace
|
||||||
* multiplier as we store the waiting time in units of 'etu', and
|
/* FIXME update waiting time in case of card is specific mode */
|
||||||
* don't really care what the number of clock cycles or the absolute
|
/* reset PTS to initial state */
|
||||||
* wall clock time is */
|
set_pts_state(ch, PTS_S_WAIT_REQ_PTSS);
|
||||||
ch->waiting_time = ch->wi * 960;
|
#else
|
||||||
|
/* update waiting time (see ISO 7816-3 10.2) */
|
||||||
|
ch->wt = ch->wi * 960 * ch->fi;
|
||||||
|
tc_etu_set_wtime(ch->tc_chan, ch->wt);
|
||||||
|
#endif
|
||||||
/* go to next state */
|
/* go to next state */
|
||||||
card_set_state(ch, ISO_S_WAIT_TPDU);
|
card_set_state(ch, ISO_S_WAIT_TPDU);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -578,9 +636,12 @@ from_pts3:
|
|||||||
return PTS_S_WAIT_REQ_PCK | is_resp;
|
return PTS_S_WAIT_REQ_PCK | is_resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! process incoming PTS byte
|
||||||
static int
|
* @param[in] ch card handle on which the byte has been received
|
||||||
process_byte_pts(struct card_handle *ch, uint8_t byte)
|
* @param[in] byte received PTS byte
|
||||||
|
* @return new iso7816_3_card_state or -1 at the end of PTS request
|
||||||
|
*/
|
||||||
|
static int process_byte_pts(struct card_handle *ch, uint8_t byte)
|
||||||
{
|
{
|
||||||
switch (ch->pts.state) {
|
switch (ch->pts.state) {
|
||||||
case PTS_S_WAIT_REQ_PTSS:
|
case PTS_S_WAIT_REQ_PTSS:
|
||||||
@@ -646,12 +707,17 @@ static int tx_byte_pts(struct card_handle *ch)
|
|||||||
break;
|
break;
|
||||||
case PTS_S_WAIT_RESP_PTS1:
|
case PTS_S_WAIT_RESP_PTS1:
|
||||||
byte = ch->pts.resp[_PTS1];
|
byte = ch->pts.resp[_PTS1];
|
||||||
/* This must be TA1 */
|
// TODO the value should have been validated when receiving the request
|
||||||
ch->F_index = byte >> 4;
|
ch->f = iso7816_3_fi_table[byte >> 4]; // save selected Fn
|
||||||
ch->D_index = byte & 0xf;
|
if (0 == ch->f) {
|
||||||
TRACE_DEBUG("%u: found F=%u D=%u\r\n", ch->num,
|
TRACE_ERROR("%u: invalid F index in PPS response: %u\r\n", ch->num, byte >> 4);
|
||||||
iso7816_3_fi_table[ch->F_index], iso7816_3_di_table[ch->D_index]);
|
// TODO become unresponsive to signal error condition
|
||||||
/* FIXME: if F or D are 0, become unresponsive to signal error condition */
|
}
|
||||||
|
ch->d = iso7816_3_di_table[byte & 0xf]; // save selected Dn
|
||||||
|
if (0 == ch->d) {
|
||||||
|
TRACE_ERROR("%u: invalid D index in PPS response: %u\r\n", ch->num, byte & 0xf);
|
||||||
|
// TODO become unresponsive to signal error condition
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case PTS_S_WAIT_RESP_PTS2:
|
case PTS_S_WAIT_RESP_PTS2:
|
||||||
byte = ch->pts.resp[_PTS2];
|
byte = ch->pts.resp[_PTS2];
|
||||||
@@ -676,8 +742,20 @@ static int tx_byte_pts(struct card_handle *ch)
|
|||||||
switch (ch->pts.state) {
|
switch (ch->pts.state) {
|
||||||
case PTS_S_WAIT_RESP_PCK:
|
case PTS_S_WAIT_RESP_PCK:
|
||||||
card_emu_uart_wait_tx_idle(ch->uart_chan);
|
card_emu_uart_wait_tx_idle(ch->uart_chan);
|
||||||
/* update baud rate generator with F/D */
|
#ifdef BOARD_simtrace
|
||||||
|
card_emu_uart_update_fd(ch->uart_chan, ch->f, ch->d); // set selected baud rate
|
||||||
|
int32_t wt = iso7816_3_calculate_wt(ch->wi, ch->fi, ch->di, ch->f, ch->d); // get new waiting time
|
||||||
|
if (wt <= 0) {
|
||||||
|
TRACE_ERROR("%u: invalid WT calculated: %ld\r\n", ch->num, wt);
|
||||||
|
// TODO become unresponsive to signal error condition
|
||||||
|
} else {
|
||||||
|
ch->wt = wt;
|
||||||
|
}
|
||||||
|
// FIXME disable WT
|
||||||
|
#else
|
||||||
|
/* update baud rate generator with Fi/Di */
|
||||||
emu_update_fidi(ch);
|
emu_update_fidi(ch);
|
||||||
|
#endif
|
||||||
/* Wait for the next TPDU */
|
/* Wait for the next TPDU */
|
||||||
card_set_state(ch, ISO_S_WAIT_TPDU);
|
card_set_state(ch, ISO_S_WAIT_TPDU);
|
||||||
set_pts_state(ch, PTS_S_WAIT_REQ_PTSS);
|
set_pts_state(ch, PTS_S_WAIT_REQ_PTSS);
|
||||||
@@ -748,6 +826,10 @@ static void set_tpdu_state(struct card_handle *ch, enum tpdu_state new_ts)
|
|||||||
{
|
{
|
||||||
if (ch->tpdu.state == new_ts)
|
if (ch->tpdu.state == new_ts)
|
||||||
return;
|
return;
|
||||||
|
if (ISO_S_IN_TPDU != ch->state && ISO_S_WAIT_TPDU != ch->state) {
|
||||||
|
TRACE_ERROR("%u: setting TPDU state in %s state\r\n", ch->num,
|
||||||
|
get_value_string(iso7816_3_card_state_names, ch->state));
|
||||||
|
}
|
||||||
|
|
||||||
TRACE_DEBUG("%u: 7816 TPDU state %s -> %s\r\n", ch->num,
|
TRACE_DEBUG("%u: 7816 TPDU state %s -> %s\r\n", ch->num,
|
||||||
get_value_string(tpdu_state_names, ch->tpdu.state),
|
get_value_string(tpdu_state_names, ch->tpdu.state),
|
||||||
@@ -755,29 +837,20 @@ static void set_tpdu_state(struct card_handle *ch, enum tpdu_state new_ts)
|
|||||||
ch->tpdu.state = new_ts;
|
ch->tpdu.state = new_ts;
|
||||||
|
|
||||||
switch (new_ts) {
|
switch (new_ts) {
|
||||||
case TPDU_S_WAIT_CLA:
|
case TPDU_S_WAIT_CLA: // we will be waiting for the next incoming TDPU
|
||||||
/* switch back to receiving mode */
|
card_emu_uart_enable(ch->uart_chan, ENABLE_RX); // switch back to receiving mode
|
||||||
card_emu_uart_enable(ch->uart_chan, ENABLE_RX);
|
card_emu_uart_update_wt(ch->uart_chan, 0); // disable waiting time since we don't expect any data
|
||||||
/* disable waiting time since we don't expect any data */
|
|
||||||
card_emu_uart_update_wt(ch->uart_chan, 0);
|
|
||||||
break;
|
break;
|
||||||
case TPDU_S_WAIT_INS:
|
case TPDU_S_WAIT_INS: // the reader started sending the TPDU header
|
||||||
/* start waiting for the rest of the header/body */
|
card_emu_uart_update_wt(ch->uart_chan, ch->wt); // start waiting for the rest of the header/body
|
||||||
card_emu_uart_update_wt(ch->uart_chan, ch->waiting_time);
|
|
||||||
break;
|
break;
|
||||||
case TPDU_S_WAIT_RX:
|
case TPDU_S_WAIT_RX: // the reader should send us the TPDU body data
|
||||||
/* switch to receive mode to receive the body */
|
card_emu_uart_enable(ch->uart_chan, ENABLE_RX); // switch to receive mode to receive the body
|
||||||
card_emu_uart_enable(ch->uart_chan, ENABLE_RX);
|
card_emu_uart_update_wt(ch->uart_chan, ch->wt); // start waiting for the rest body
|
||||||
/* start waiting for the body */
|
|
||||||
card_emu_uart_update_wt(ch->uart_chan, ch->waiting_time);
|
|
||||||
break;
|
break;
|
||||||
case TPDU_S_WAIT_PB:
|
case TPDU_S_WAIT_PB:
|
||||||
/* we just completed the TPDU header from reader to card
|
card_emu_uart_enable(ch->uart_chan, ENABLE_TX); // header is completely received, now we need to transmit the procedure byte
|
||||||
* and now need to disable the receiver, enable the
|
card_emu_uart_update_wt(ch->uart_chan, ch->wt); // prepare to extend the waiting time once half of it is reached
|
||||||
* transmitter and transmit the procedure byte */
|
|
||||||
card_emu_uart_enable(ch->uart_chan, ENABLE_TX);
|
|
||||||
/* prepare to extend the waiting time once half of it is reached */
|
|
||||||
card_emu_uart_update_wt(ch->uart_chan, ch->waiting_time);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -1061,11 +1134,11 @@ void card_emu_report_status(struct card_handle *ch, bool report_on_irq)
|
|||||||
sts->flags |= CEMU_STATUS_F_CLK_ACTIVE;
|
sts->flags |= CEMU_STATUS_F_CLK_ACTIVE;
|
||||||
if (ch->in_reset)
|
if (ch->in_reset)
|
||||||
sts->flags |= CEMU_STATUS_F_RESET_ACTIVE;
|
sts->flags |= CEMU_STATUS_F_RESET_ACTIVE;
|
||||||
/* FIXME: voltage + card insert */
|
/* FIXME set voltage and card insert values */
|
||||||
sts->F_index = ch->F_index;
|
sts->f = ch->f;
|
||||||
sts->D_index = ch->D_index;
|
sts->d = ch->d;
|
||||||
sts->wi = ch->wi;
|
sts->wi = ch->wi;
|
||||||
sts->waiting_time = ch->waiting_time;
|
sts->wt = ch->wt;
|
||||||
|
|
||||||
usb_buf_upd_len_and_submit(msg);
|
usb_buf_upd_len_and_submit(msg);
|
||||||
}
|
}
|
||||||
@@ -1082,12 +1155,6 @@ static void card_emu_report_config(struct card_handle *ch)
|
|||||||
|
|
||||||
cfg = (struct cardemu_usb_msg_config *) msgb_put(msg, sizeof(*cfg));
|
cfg = (struct cardemu_usb_msg_config *) msgb_put(msg, sizeof(*cfg));
|
||||||
cfg->features = ch->features;
|
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);
|
usb_buf_upd_len_and_submit(msg);
|
||||||
}
|
}
|
||||||
@@ -1126,7 +1193,7 @@ void card_emu_io_statechg(struct card_handle *ch, enum card_io io, int active)
|
|||||||
case CARD_IO_RST:
|
case CARD_IO_RST:
|
||||||
if (active == 0 && ch->in_reset) {
|
if (active == 0 && ch->in_reset) {
|
||||||
TRACE_INFO("%u: RST released\r\n", ch->num);
|
TRACE_INFO("%u: RST released\r\n", ch->num);
|
||||||
if (ch->vcc_active && ch->clocked && ch->state == ISO_S_WAIT_RST) {
|
if (ch->vcc_active && ch->clocked && ISO_S_WAIT_RST == ch->state) {
|
||||||
/* prepare to send the ATR */
|
/* prepare to send the ATR */
|
||||||
card_set_state(ch, ISO_S_WAIT_ATR);
|
card_set_state(ch, ISO_S_WAIT_ATR);
|
||||||
}
|
}
|
||||||
@@ -1135,10 +1202,14 @@ void card_emu_io_statechg(struct card_handle *ch, enum card_io io, int active)
|
|||||||
TRACE_INFO("%u: RST asserted\r\n", ch->num);
|
TRACE_INFO("%u: RST asserted\r\n", ch->num);
|
||||||
card_handle_reset(ch);
|
card_handle_reset(ch);
|
||||||
chg_mask |= CEMU_STATUS_F_RESET_ACTIVE;
|
chg_mask |= CEMU_STATUS_F_RESET_ACTIVE;
|
||||||
|
#ifdef BOARD_simtrace
|
||||||
card_set_state(ch, ISO_S_WAIT_RST);
|
card_set_state(ch, ISO_S_WAIT_RST);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
ch->in_reset = active;
|
ch->in_reset = active;
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (ch->state) {
|
switch (ch->state) {
|
||||||
@@ -1167,17 +1238,20 @@ int card_emu_set_atr(struct card_handle *ch, const uint8_t *atr, uint8_t len)
|
|||||||
if (len > sizeof(ch->atr.atr))
|
if (len > sizeof(ch->atr.atr))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
/* ignore new ATR for now since we PPS has not been tested
|
||||||
memcpy(ch->atr.atr, atr, len);
|
memcpy(ch->atr.atr, atr, len);
|
||||||
ch->atr.len = len;
|
ch->atr.len = len;
|
||||||
ch->atr.idx = 0;
|
ch->atr.idx = 0;
|
||||||
|
*/
|
||||||
|
|
||||||
#if TRACE_LEVEL >= TRACE_LEVEL_INFO
|
#if TRACE_LEVEL >= TRACE_LEVEL_INFO
|
||||||
uint8_t i;
|
uint8_t i;
|
||||||
TRACE_INFO("%u: ATR set: ", ch->num);
|
TRACE_INFO("%u: ATR set: ", ch->num);
|
||||||
for (i = 0; i < ch->atr.len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
TRACE_INFO_WP("%02x ", atr[i]);
|
TRACE_INFO_WP("%02x ", atr[i]);
|
||||||
}
|
}
|
||||||
TRACE_INFO_WP("\n\r");
|
TRACE_INFO_WP("\n\r");
|
||||||
|
TRACE_INFO("%u: ATR set currently ignored\n\r", ch->num);
|
||||||
#endif
|
#endif
|
||||||
/* FIXME: race condition with transmitting ATR to reader? */
|
/* FIXME: race condition with transmitting ATR to reader? */
|
||||||
|
|
||||||
@@ -1185,7 +1259,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 */
|
/* hardware driver informs us that one (more) ETU has expired */
|
||||||
void card_emu_wtime_half_expired(void *handle)
|
void card_emu_wt_halfed(void *handle)
|
||||||
{
|
{
|
||||||
struct card_handle *ch = handle;
|
struct card_handle *ch = handle;
|
||||||
/* transmit NULL procedure byte well before waiting time expires */
|
/* transmit NULL procedure byte well before waiting time expires */
|
||||||
@@ -1195,10 +1269,8 @@ void card_emu_wtime_half_expired(void *handle)
|
|||||||
case TPDU_S_WAIT_PB:
|
case TPDU_S_WAIT_PB:
|
||||||
case TPDU_S_WAIT_TX:
|
case TPDU_S_WAIT_TX:
|
||||||
putchar('N');
|
putchar('N');
|
||||||
/* we are waiting for data from the user. Send a procedure byte to ask the
|
card_emu_uart_tx(ch->uart_chan, ISO7816_3_PB_NULL); // we are waiting for data from the user. send a procedure byte to ask the reader to wait more time
|
||||||
* reader to wait more time */
|
card_emu_uart_reset_wt(ch->uart_chan); // reset WT
|
||||||
card_emu_uart_tx(ch->uart_chan, ISO7816_3_PB_NULL);
|
|
||||||
card_emu_uart_reset_wt(ch->uart_chan);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -1210,7 +1282,7 @@ void card_emu_wtime_half_expired(void *handle)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* hardware driver informs us that one (more) ETU has expired */
|
/* hardware driver informs us that one (more) ETU has expired */
|
||||||
void card_emu_wtime_expired(void *handle)
|
void card_emu_wt_expired(void *handle)
|
||||||
{
|
{
|
||||||
struct card_handle *ch = handle;
|
struct card_handle *ch = handle;
|
||||||
switch (ch->state) {
|
switch (ch->state) {
|
||||||
@@ -1219,6 +1291,7 @@ void card_emu_wtime_expired(void *handle)
|
|||||||
card_set_state(ch, ISO_S_IN_ATR);
|
card_set_state(ch, ISO_S_IN_ATR);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
// TODO become unresponsive
|
||||||
TRACE_ERROR("%u: wtime_exp\r\n", ch->num);
|
TRACE_ERROR("%u: wtime_exp\r\n", ch->num);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1226,20 +1299,21 @@ void card_emu_wtime_expired(void *handle)
|
|||||||
|
|
||||||
/* reasonable ATR offering all protocols and voltages
|
/* reasonable ATR offering all protocols and voltages
|
||||||
* smartphones might not care, but other readers do
|
* smartphones might not care, but other readers do
|
||||||
*
|
|
||||||
* TS = 0x3B Direct Convention
|
TS = 0x3B Direct Convention
|
||||||
* T0 = 0x80 Y(1): b1000, K: 0 (historical bytes)
|
T0 = 0x80 Y(1): b1000, K: 0 (historical bytes)
|
||||||
* TD(1) = 0x80 Y(i+1) = b1000, Protocol T=0
|
TD(1) = 0x80 Y(i+1) = b1000, Protocol T=0
|
||||||
* ----
|
----
|
||||||
* TD(2) = 0x81 Y(i+1) = b1000, Protocol T=1
|
TD(2) = 0x81 Y(i+1) = b1000, Protocol T=1
|
||||||
* ----
|
----
|
||||||
* TD(3) = 0x1F Y(i+1) = b0001, Protocol T=15
|
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
|
TA(4) = 0xC7 Clock stop: no preference - Class accepted by the card: (3G) A 5V B 3V C 1.8V
|
||||||
* ----
|
----
|
||||||
* Historical bytes
|
Historical bytes
|
||||||
* TCK = 0x59 correct checksum
|
TCK = 0x59 correct checksum
|
||||||
*/
|
|
||||||
|
* */
|
||||||
static const uint8_t default_atr[] = { 0x3B, 0x80, 0x80, 0x81 , 0x1F, 0xC7, 0x59};
|
static const uint8_t default_atr[] = { 0x3B, 0x80, 0x80, 0x81 , 0x1F, 0xC7, 0x59};
|
||||||
|
|
||||||
static struct card_handle card_handles[NUM_SLOTS];
|
static struct card_handle card_handles[NUM_SLOTS];
|
||||||
@@ -1250,19 +1324,13 @@ int card_emu_set_config(struct card_handle *ch, const struct cardemu_usb_msg_con
|
|||||||
if (scfg_len >= sizeof(uint32_t))
|
if (scfg_len >= sizeof(uint32_t))
|
||||||
ch->features = (scfg->features & SUPPORTED_FEATURES);
|
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 */
|
/* send back a report of our current configuration */
|
||||||
card_emu_report_config(ch);
|
card_emu_report_config(ch);
|
||||||
|
|
||||||
return 0;
|
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 *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 *ch;
|
struct card_handle *ch;
|
||||||
|
|
||||||
@@ -1275,6 +1343,7 @@ struct card_handle *card_emu_init(uint8_t slot_num, uint8_t uart_chan, uint8_t i
|
|||||||
|
|
||||||
INIT_LLIST_HEAD(&ch->uart_tx_queue);
|
INIT_LLIST_HEAD(&ch->uart_tx_queue);
|
||||||
|
|
||||||
|
/* initialize the card_handle with reasonable defaults */
|
||||||
ch->num = slot_num;
|
ch->num = slot_num;
|
||||||
ch->irq_ep = irq_ep;
|
ch->irq_ep = irq_ep;
|
||||||
ch->in_ep = in_ep;
|
ch->in_ep = in_ep;
|
||||||
@@ -1283,12 +1352,13 @@ struct card_handle *card_emu_init(uint8_t slot_num, uint8_t uart_chan, uint8_t i
|
|||||||
ch->in_reset = in_reset;
|
ch->in_reset = in_reset;
|
||||||
ch->clocked = clocked;
|
ch->clocked = clocked;
|
||||||
|
|
||||||
ch->Fi_index = ch->F_index = 1;
|
ch->fi = ISO7816_3_DEFAULT_FI;
|
||||||
ch->Di_index = ch->D_index = 1;
|
ch->di = ISO7816_3_DEFAULT_DI;
|
||||||
ch->wi = ISO7816_3_DEFAULT_WI;
|
ch->wi = ISO7816_3_DEFAULT_WI;
|
||||||
|
ch->wt = ISO7816_3_DEFAULT_WT;;
|
||||||
|
|
||||||
|
ch->tc_chan = tc_chan;
|
||||||
ch->uart_chan = uart_chan;
|
ch->uart_chan = uart_chan;
|
||||||
ch->waiting_time = ISO7816_3_INIT_WTIME;
|
|
||||||
|
|
||||||
ch->atr.idx = 0;
|
ch->atr.idx = 0;
|
||||||
ch->atr.len = sizeof(default_atr);
|
ch->atr.len = sizeof(default_atr);
|
||||||
@@ -1298,6 +1368,10 @@ struct card_handle *card_emu_init(uint8_t slot_num, uint8_t uart_chan, uint8_t i
|
|||||||
ch->tpdu.state = TPDU_S_WAIT_CLA;
|
ch->tpdu.state = TPDU_S_WAIT_CLA;
|
||||||
|
|
||||||
card_handle_reset(ch);
|
card_handle_reset(ch);
|
||||||
|
#ifndef BOARD_simtrace
|
||||||
|
/* simtrace uses uart timer instead */
|
||||||
|
tc_etu_init(ch->tc_chan, ch);
|
||||||
|
#endif
|
||||||
|
|
||||||
return ch;
|
return ch;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ static void usb_write_cb(uint8_t *arg, uint8_t status, uint32_t transferred,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* check if the spcified IN endpoint is idle and submit the next buffer from queue */
|
/* check if the spcified IN endpoint is idle and submit the next buffer from queue */
|
||||||
static int usb_refill_to_host(uint8_t ep)
|
int usb_refill_to_host(uint8_t ep)
|
||||||
{
|
{
|
||||||
struct usb_buffered_ep *bep = usb_get_buf_ep(ep);
|
struct usb_buffered_ep *bep = usb_get_buf_ep(ep);
|
||||||
struct msgb *msg;
|
struct msgb *msg;
|
||||||
@@ -130,7 +130,7 @@ static void usb_read_cb(uint8_t *arg, uint8_t status, uint32_t transferred,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* refill the read queue for data received from host PC on OUT EP, if needed */
|
/* refill the read queue for data received from host PC on OUT EP, if needed */
|
||||||
static int usb_refill_from_host(uint8_t ep)
|
int usb_refill_from_host(uint8_t ep)
|
||||||
{
|
{
|
||||||
struct usb_buffered_ep *bep = usb_get_buf_ep(ep);
|
struct usb_buffered_ep *bep = usb_get_buf_ep(ep);
|
||||||
struct msgb *msg;
|
struct msgb *msg;
|
||||||
@@ -198,45 +198,3 @@ int usb_drain_queue(uint8_t ep)
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* iterate over the queue of incoming USB commands and dispatch/execute
|
|
||||||
* them */
|
|
||||||
static void process_any_usb_commands(const struct usb_if *usb_if)
|
|
||||||
{
|
|
||||||
struct llist_head *queue = usb_get_queue(usb_if->ep_out);
|
|
||||||
struct llist_head *lh;
|
|
||||||
struct msgb *msg;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* limit the number of iterations to 10, to ensure we don't get
|
|
||||||
* stuck here without returning to main loop processing */
|
|
||||||
for (i = 0; i < 10; i++) {
|
|
||||||
/* de-queue the list head in an irq-safe way */
|
|
||||||
lh = llist_head_dequeue_irqsafe(queue);
|
|
||||||
if (!lh)
|
|
||||||
break;
|
|
||||||
msg = llist_entry(lh, struct msgb, list);
|
|
||||||
usb_if->ops.rx_out(msg, usb_if);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* perform any action related to USB processing (IRQ/INT/OUT EP refill, handling OUT) */
|
|
||||||
void usb_process(const struct usb_if *usb_if)
|
|
||||||
{
|
|
||||||
/* first try to send any pending messages on IRQ */
|
|
||||||
if (usb_if->ep_int)
|
|
||||||
usb_refill_to_host(usb_if->ep_int);
|
|
||||||
|
|
||||||
/* then try to send any pending messages on IN */
|
|
||||||
if (usb_if->ep_in)
|
|
||||||
usb_refill_to_host(usb_if->ep_in);
|
|
||||||
|
|
||||||
/* ensure we can handle incoming USB messages from the
|
|
||||||
* host */
|
|
||||||
if (usb_if->ep_out) {
|
|
||||||
usb_refill_from_host(usb_if->ep_out);
|
|
||||||
process_any_usb_commands(usb_if);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
123
firmware/libcommon/source/iso7816_3.c
Normal file
123
firmware/libcommon/source/iso7816_3.c
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
|
#include "iso7816_3.h"
|
||||||
|
|
||||||
|
const uint16_t iso7816_3_fi_table[16] = {
|
||||||
|
372, 372, 558, 744, 1116, 1488, 1860, 0,
|
||||||
|
0, 512, 768, 1024, 1536, 2048, 0, 0
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint32_t iso7816_3_fmax_table[16] = {
|
||||||
|
4000000, 5000000, 6000000, 8000000, 12000000, 16000000, 20000000, 0,
|
||||||
|
0, 5000000, 7500000, 10000000, 15000000, 20000000, 0, 0
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t iso7816_3_di_table[16] = {
|
||||||
|
0, 1, 2, 4, 8, 16, 32, 64,
|
||||||
|
12, 20, 0, 0, 0, 0, 0, 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* all values are based on the Elementary Time Unit (ETU), defined in ISO/IEC 7816-3 section 7.1
|
||||||
|
* this is the time required to transmit a bit, and is calculated as follows: 1 ETU = (F / D) x (1 / f) where:
|
||||||
|
* - F is the clock rate conversion integer
|
||||||
|
* - D is the baud rate adjustment factor
|
||||||
|
* - f is the clock frequency
|
||||||
|
* the possible F, f(max), and D values are defined in ISO/IEC 7816-3 table 7 and 8
|
||||||
|
* - the initial value for F (after reset) is Fd = 372
|
||||||
|
* - the initial value for D (after reset) is Dd = 1
|
||||||
|
* - the initial maximum frequency f(max) is 5 MHz
|
||||||
|
* the card must measure the ETU based on the clock signal provided by the reader
|
||||||
|
* one ETU (e.g. 1 bit) takes F/D clock cycles, which the card must count
|
||||||
|
*
|
||||||
|
* the card can indicate an alternative set of supported values Fi (with corresponding f(max)) and Di for higher baud rate in TA1 in the ATR (see ISO/IEC 7816-3 section 8.3)
|
||||||
|
* these values are selected according to ISO/IEC 7816-3 section 6.3.1:
|
||||||
|
* - card in specific mode: they are enforced if TA2 is present (the reader can deactivate the card if it does not support these values)
|
||||||
|
* - card in negotiable mode:
|
||||||
|
* -- they can be selected by the reader using the Protocol and Parameters Selection (PPS) procedure
|
||||||
|
* -- the first offered protocol and default values are used when no PPS is started
|
||||||
|
*
|
||||||
|
* PPS is done with Fd and Dd (see ISO/IEC 7816-3 section 9)
|
||||||
|
* the reader can propose any F and D values between from Fd to Fi, and from Dd to Di (Fi and Di are indicated in TA1)
|
||||||
|
* the in PPS agreed values F and D are called Fn and Dn and are applied after a successful exchange, corresponding to PPS1_Response bit 5
|
||||||
|
*
|
||||||
|
* the F and D values must be provided to the SAM3S USART peripheral (after reset and PPS)
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool iso7816_3_valid_f(uint16_t f)
|
||||||
|
{
|
||||||
|
if (0 == f) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
uint8_t i = 0;
|
||||||
|
for (i = 0; i < ARRAY_SIZE(iso7816_3_fi_table) && iso7816_3_fi_table[i] != f; i++);
|
||||||
|
return (i < ARRAY_SIZE(iso7816_3_fi_table) && iso7816_3_fi_table[i] == f);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool iso7816_3_valid_d(uint8_t d)
|
||||||
|
{
|
||||||
|
if (0 == d) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
uint8_t i = 0;
|
||||||
|
for (i = 0; i < ARRAY_SIZE(iso7816_3_di_table) && iso7816_3_di_table[i] != d; i++);
|
||||||
|
return (i < ARRAY_SIZE(iso7816_3_di_table) && iso7816_3_di_table[i] == d);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* the ETU is not only used to define the baud rate, but also the Waiting Time (WT) (see ISO/IEC 7816-3 section 8.1)
|
||||||
|
* when exceeding WT without card response, the reader flags the card as unresponsive, and resets it
|
||||||
|
* this can be used by the card to indicate errors or unsupported operations
|
||||||
|
* if the card requires more time to respond, it shall send a procedure byte to restart WT
|
||||||
|
* WT is calculated as follows (for T=0, see ISO/IEC 7816-3 section 10.2): WT = WI x 960 x (Fi / f(max)) where
|
||||||
|
* - WI is encoded in TC2 in the ATR (10 if absent)
|
||||||
|
* - WI does not depend on D/Di (used for the ETU)
|
||||||
|
* - after reset WT is 9600 ETU
|
||||||
|
* - WI (e.g. the new WT) is applied when T=0 is used (after 6.3.1), even if Fi is not Fn (this WT extension is important to know for the reader so to have the right timeout)
|
||||||
|
*/
|
||||||
|
|
||||||
|
int32_t iso7816_3_calculate_wt(uint8_t wi, uint16_t fi, uint8_t di, uint16_t f, uint8_t d)
|
||||||
|
{
|
||||||
|
// sanity checks
|
||||||
|
if (0 == wi) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!iso7816_3_valid_f(fi)) {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
if (!iso7816_3_valid_d(di)) {
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
if (!iso7816_3_valid_f(f)) {
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
if (!iso7816_3_valid_d(d)) {
|
||||||
|
return -5;
|
||||||
|
}
|
||||||
|
if (f > fi) {
|
||||||
|
return -6;
|
||||||
|
}
|
||||||
|
if (d > di) {
|
||||||
|
return -7;
|
||||||
|
}
|
||||||
|
|
||||||
|
return wi * 960UL * (fi/f) * (di/d); // calculate timeout value in ETU
|
||||||
|
}
|
||||||
@@ -23,38 +23,38 @@
|
|||||||
#include "iso7816_fidi.h"
|
#include "iso7816_fidi.h"
|
||||||
|
|
||||||
/* Table 7 of ISO 7816-3:2006 */
|
/* Table 7 of ISO 7816-3:2006 */
|
||||||
const uint16_t iso7816_3_fi_table[] = {
|
const uint16_t fi_table[] = {
|
||||||
372, 372, 558, 744, 1116, 1488, 1860, 0,
|
372, 372, 558, 744, 1116, 1488, 1860, 0,
|
||||||
0, 512, 768, 1024, 1536, 2048, 0, 0
|
0, 512, 768, 1024, 1536, 2048, 0, 0
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Table 8 from ISO 7816-3:2006 */
|
/* Table 8 from ISO 7816-3:2006 */
|
||||||
const uint8_t iso7816_3_di_table[] = {
|
const uint8_t di_table[] = {
|
||||||
0, 1, 2, 4, 8, 16, 32, 64,
|
0, 1, 2, 4, 8, 16, 32, 64,
|
||||||
12, 20, 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 */
|
/* compute the F/D ratio based on Fi and Di values */
|
||||||
int iso7816_3_compute_fd_ratio(uint8_t f_index, uint8_t d_index)
|
int compute_fidi_ratio(uint8_t fi, uint8_t di)
|
||||||
{
|
{
|
||||||
uint16_t f, d;
|
uint16_t f, d;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (f_index >= ARRAY_SIZE(iso7816_3_fi_table) ||
|
if (fi >= ARRAY_SIZE(fi_table) ||
|
||||||
d_index >= ARRAY_SIZE(iso7816_3_di_table))
|
di >= ARRAY_SIZE(di_table))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
f = iso7816_3_fi_table[f_index];
|
f = fi_table[fi];
|
||||||
if (f == 0)
|
if (f == 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
d = iso7816_3_di_table[d_index];
|
d = di_table[di];
|
||||||
if (d == 0)
|
if (d == 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* See table 7 of ISO 7816-3: From 1000 on we divide by 1/d,
|
/* See table 7 of ISO 7816-3: From 1000 on we divide by 1/d,
|
||||||
* which equals a multiplication by d */
|
* which equals a multiplication by d */
|
||||||
if (d_index < 8)
|
if (di < 8)
|
||||||
ret = f / d;
|
ret = f / d;
|
||||||
else
|
else
|
||||||
ret = f * d;
|
ret = f * d;
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include "simtrace.h"
|
#include "simtrace.h"
|
||||||
#include "ringbuffer.h"
|
#include "ringbuffer.h"
|
||||||
#include "card_emu.h"
|
#include "card_emu.h"
|
||||||
|
#include "iso7816_3.h"
|
||||||
#include "iso7816_fidi.h"
|
#include "iso7816_fidi.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include <osmocom/core/linuxlist.h>
|
#include <osmocom/core/linuxlist.h>
|
||||||
@@ -34,8 +35,6 @@
|
|||||||
|
|
||||||
#define TRACE_ENTRY() TRACE_DEBUG("%s entering\r\n", __func__)
|
#define TRACE_ENTRY() TRACE_DEBUG("%s entering\r\n", __func__)
|
||||||
|
|
||||||
static void dispatch_received_usb_msg(struct msgb *msg, const struct usb_if *usb_if);
|
|
||||||
|
|
||||||
#ifdef PINS_CARDSIM
|
#ifdef PINS_CARDSIM
|
||||||
static const Pin pins_cardsim[] = PINS_CARDSIM;
|
static const Pin pins_cardsim[] = PINS_CARDSIM;
|
||||||
#endif
|
#endif
|
||||||
@@ -44,10 +43,6 @@ static const Pin pins_cardsim[] = PINS_CARDSIM;
|
|||||||
static const Pin pins_usim1[] = {PINS_USIM1};
|
static const Pin pins_usim1[] = {PINS_USIM1};
|
||||||
static const Pin pin_usim1_rst = PIN_USIM1_nRST;
|
static const Pin pin_usim1_rst = PIN_USIM1_nRST;
|
||||||
static const Pin pin_usim1_vcc = PIN_USIM1_VCC;
|
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
|
#ifdef CARDEMU_SECOND_UART
|
||||||
static const Pin pins_usim2[] = {PINS_USIM2};
|
static const Pin pins_usim2[] = {PINS_USIM2};
|
||||||
@@ -60,17 +55,15 @@ struct cardem_inst {
|
|||||||
struct card_handle *ch;
|
struct card_handle *ch;
|
||||||
struct llist_head usb_out_queue;
|
struct llist_head usb_out_queue;
|
||||||
struct ringbuf rb;
|
struct ringbuf rb;
|
||||||
|
uint32_t wt; /*!< receiver waiting time to trigger timeout (0 to deactivate it) */
|
||||||
|
uint32_t wt_remaining; /*!< remaining waiting time */
|
||||||
|
bool wt_halfed; /*!< if at least half of the waiting time passed */
|
||||||
struct Usart_info usart_info;
|
struct Usart_info usart_info;
|
||||||
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;
|
int usb_pending_old;
|
||||||
struct usb_if usb_if;
|
uint8_t ep_out;
|
||||||
|
uint8_t ep_in;
|
||||||
|
uint8_t ep_int;
|
||||||
|
const Pin pin_io;
|
||||||
const Pin pin_insert;
|
const Pin pin_insert;
|
||||||
#ifdef DETECT_VCC_BY_ADC
|
#ifdef DETECT_VCC_BY_ADC
|
||||||
uint32_t vcc_uv;
|
uint32_t vcc_uv;
|
||||||
@@ -90,16 +83,10 @@ struct cardem_inst cardem_inst[] = {
|
|||||||
.id = ID_USART1,
|
.id = ID_USART1,
|
||||||
.state = USART_RCV
|
.state = USART_RCV
|
||||||
},
|
},
|
||||||
.usb_if = {
|
|
||||||
.if_num = 0,
|
|
||||||
.ep_out = SIMTRACE_CARDEM_USB_EP_USIM1_DATAOUT,
|
.ep_out = SIMTRACE_CARDEM_USB_EP_USIM1_DATAOUT,
|
||||||
.ep_in = SIMTRACE_CARDEM_USB_EP_USIM1_DATAIN,
|
.ep_in = SIMTRACE_CARDEM_USB_EP_USIM1_DATAIN,
|
||||||
.ep_int = SIMTRACE_CARDEM_USB_EP_USIM1_INT,
|
.ep_int = SIMTRACE_CARDEM_USB_EP_USIM1_INT,
|
||||||
.data = &cardem_inst[0],
|
.pin_io = PIN_USIM1_IO,
|
||||||
.ops = {
|
|
||||||
.rx_out = dispatch_received_usb_msg,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
#ifdef PIN_SET_USIM1_PRES
|
#ifdef PIN_SET_USIM1_PRES
|
||||||
.pin_insert = PIN_SET_USIM1_PRES,
|
.pin_insert = PIN_SET_USIM1_PRES,
|
||||||
#endif
|
#endif
|
||||||
@@ -112,16 +99,10 @@ struct cardem_inst cardem_inst[] = {
|
|||||||
.id = ID_USART0,
|
.id = ID_USART0,
|
||||||
.state = USART_RCV
|
.state = USART_RCV
|
||||||
},
|
},
|
||||||
.usb_if = {
|
|
||||||
.if_num = 1,
|
|
||||||
.ep_out = SIMTRACE_CARDEM_USB_EP_USIM2_DATAOUT,
|
.ep_out = SIMTRACE_CARDEM_USB_EP_USIM2_DATAOUT,
|
||||||
.ep_in = SIMTRACE_CARDEM_USB_EP_USIM2_DATAIN,
|
.ep_in = SIMTRACE_CARDEM_USB_EP_USIM2_DATAIN,
|
||||||
.ep_int = SIMTRACE_CARDEM_USB_EP_USIM2_INT,
|
.ep_int = SIMTRACE_CARDEM_USB_EP_USIM2_INT,
|
||||||
.data = &cardem_inst[1],
|
.pin_io = PIN_USIM2_IO,
|
||||||
.ops = {
|
|
||||||
.rx_out = dispatch_received_usb_msg,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
#ifdef PIN_SET_USIM2_PRES
|
#ifdef PIN_SET_USIM2_PRES
|
||||||
.pin_insert = PIN_SET_USIM2_PRES,
|
.pin_insert = PIN_SET_USIM2_PRES,
|
||||||
#endif
|
#endif
|
||||||
@@ -161,44 +142,22 @@ void card_emu_uart_wait_tx_idle(uint8_t uart_chan)
|
|||||||
wait_tx_idle(usart);
|
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 */
|
/* 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)
|
void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx)
|
||||||
{
|
{
|
||||||
Usart *usart = get_usart_by_chan(uart_chan);
|
Usart *usart = get_usart_by_chan(uart_chan);
|
||||||
switch (rxtx) {
|
switch (rxtx) {
|
||||||
case ENABLE_TX:
|
case ENABLE_TX:
|
||||||
card_emu_uart_set_direction(uart_chan, true);
|
USART_DisableIt(usart, ~US_IER_TXRDY);
|
||||||
USART_DisableIt(usart, ~(US_IER_TXRDY | US_IER_TIMEOUT));
|
|
||||||
/* as irritating as it is, we actually want to keep the
|
/* as irritating as it is, we actually want to keep the
|
||||||
* receiver enabled during transmit */
|
* receiver enabled during transmit */
|
||||||
USART_SetReceiverEnabled(usart, 1);
|
USART_SetReceiverEnabled(usart, 1);
|
||||||
usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
|
usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
|
||||||
|
#ifdef BOARD_simtrace
|
||||||
USART_EnableIt(usart, US_IER_TXRDY | US_IER_TIMEOUT);
|
USART_EnableIt(usart, US_IER_TXRDY | US_IER_TIMEOUT);
|
||||||
USART_SetTransmitterEnabled(usart, 1);
|
#else
|
||||||
break;
|
USART_EnableIt(usart, US_IER_TXRDY);
|
||||||
case ENABLE_TX_TIMER_ONLY:
|
#endif
|
||||||
/* 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);
|
USART_SetTransmitterEnabled(usart, 1);
|
||||||
break;
|
break;
|
||||||
case ENABLE_RX:
|
case ENABLE_RX:
|
||||||
@@ -207,9 +166,12 @@ void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx)
|
|||||||
* transmitter enabled during receive */
|
* transmitter enabled during receive */
|
||||||
USART_SetTransmitterEnabled(usart, 1);
|
USART_SetTransmitterEnabled(usart, 1);
|
||||||
wait_tx_idle(usart);
|
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->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
|
||||||
|
#ifdef BOARD_simtrace
|
||||||
|
USART_EnableIt(usart, US_IER_RXRDY | US_IER_TIMEOUT);
|
||||||
|
#else
|
||||||
USART_EnableIt(usart, US_IER_RXRDY);
|
USART_EnableIt(usart, US_IER_RXRDY);
|
||||||
|
#endif
|
||||||
USART_SetReceiverEnabled(usart, 1);
|
USART_SetReceiverEnabled(usart, 1);
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
@@ -247,101 +209,63 @@ int card_emu_uart_tx(uint8_t uart_chan, uint8_t byte)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint16_t compute_next_timeout(struct cardem_inst *ci)
|
|
||||||
{
|
|
||||||
uint32_t want_to_expire;
|
|
||||||
|
|
||||||
if (ci->wt.total == 0)
|
/* FIXME: integrate this with actual irq handler */
|
||||||
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)
|
static void usart_irq_rx(uint8_t inst_num)
|
||||||
{
|
{
|
||||||
OSMO_ASSERT(inst_num < ARRAY_SIZE(cardem_inst));
|
if (inst_num >= ARRAY_SIZE(cardem_inst)) {
|
||||||
|
TRACE_ERROR("%u: UART channel out of bounds\r\n", inst_num);
|
||||||
|
return;
|
||||||
|
}
|
||||||
Usart *usart = get_usart_by_chan(inst_num);
|
Usart *usart = get_usart_by_chan(inst_num);
|
||||||
struct cardem_inst *ci = &cardem_inst[inst_num];
|
struct cardem_inst *ci = &cardem_inst[inst_num];
|
||||||
uint32_t csr;
|
uint32_t csr;
|
||||||
uint8_t byte = 0;
|
uint8_t byte = 0;
|
||||||
|
uint32_t errflags = (US_CSR_OVRE | US_CSR_FRAME | US_CSR_PARE | US_CSR_NACK | (1 << 10));
|
||||||
|
#ifndef BOARD_simtrace
|
||||||
|
errflags |= US_CSR_TIMEOUT;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* get one atomic snapshot of state/flags before they get changed */
|
csr = usart->US_CSR & usart->US_IMR; // save 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) { // bytes has been received
|
||||||
if (csr & US_CSR_RXRDY) {
|
byte = (usart->US_RHR) & 0xFF; // ready out byte
|
||||||
/* read the bye from the holding register */
|
if (rbuf_write(&ci->rb, byte) < 0) // store byte in buffer
|
||||||
byte = (usart->US_RHR) & 0xFF;
|
TRACE_ERROR("rbuf overrun\r\n"); // error if could not store in buffer
|
||||||
/* 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) { // ready to transmit the next byte
|
||||||
if (csr & US_CSR_TXRDY) {
|
if (card_emu_tx_byte(ci->ch) == 0) // transmit next byte, and check if a byte is being transmitted
|
||||||
/* transmit next byte and check if more bytes are to be transmitted */
|
USART_DisableIt(usart, US_IER_TXRDY); // stop the TX ready signal if not byte has been 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check if any error flags are set */
|
if (csr & errflags) { // error flag set
|
||||||
if (csr & (US_CSR_OVRE|US_CSR_FRAME|US_CSR_PARE|US_CSR_NACK|(1<<10))) {
|
usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK; // reset UART state to clear flag
|
||||||
/* clear any error flags */
|
TRACE_ERROR("%u USART error on 0x%x status: 0x%lx\n", ci->num, byte, csr); // warn user about error
|
||||||
usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
|
|
||||||
TRACE_ERROR("%u USART error on 0x%x status: 0x%lx\n", ci->num, byte, csr);
|
|
||||||
}
|
}
|
||||||
|
#ifdef BOARD_simtrace
|
||||||
/* check if the timeout has expired. We "abuse" the receive timer for tracking
|
// handle timeout
|
||||||
* how many etu have expired since we last sent a byte. See section
|
if (csr & US_CSR_TIMEOUT) { // RX has been inactive for some time
|
||||||
* 33.7.3.11 "Receiver Time-out" of the SAM3S8 Data Sheet */
|
if (ci->wt_remaining <= (usart->US_RTOR & 0xffff)) { // waiting time has passed
|
||||||
if (csr & US_CSR_TIMEOUT) {
|
ci->wt_remaining = 0; // timeout reached (will stop the timer)
|
||||||
/* 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 {
|
} else {
|
||||||
/* subtract the actual timeout since the new might not have been set and
|
ci->wt_remaining -= (usart->US_RTOR & 0xffff); // be sure to subtract the actual timeout since the new might not have been set and reloaded yet
|
||||||
* reloaded yet */
|
|
||||||
ci->wt.remaining -= (usart->US_RTOR & 0xffff);
|
|
||||||
}
|
}
|
||||||
if (ci->wt.remaining == 0) {
|
if (0 == ci->wt_remaining) {
|
||||||
/* let the FSM know that WT has expired */
|
card_emu_wt_expired(ci->ch); // let the state know WT has expired
|
||||||
card_emu_wtime_expired(ci->ch);
|
} else if (ci->wt_remaining <= ci->wt / 2 && !ci->wt_halfed) {
|
||||||
/* don't automatically re-start in this case */
|
ci->wt_halfed = true;
|
||||||
|
card_emu_wt_halfed(ci->ch); // let the state know WT has half expired
|
||||||
|
}
|
||||||
|
if (ci->wt_remaining > 0xffff) { // value exceeds the USART TO range
|
||||||
|
usart->US_RTOR = 0xffff; // use the MAX
|
||||||
} else {
|
} else {
|
||||||
bool half_time_just_reached = false;
|
usart->US_RTOR = ci->wt_remaining;
|
||||||
|
|
||||||
if (ci->wt.remaining <= ci->wt.total / 2 && !ci->wt.half_time_notified) {
|
|
||||||
ci->wt.half_time_notified = true;
|
|
||||||
/* don't immediately call card_emu_wtime_half_expired(), as that
|
|
||||||
* in turn may calls card_emu_uart_update_wt() which will change
|
|
||||||
* the timeout but would be overridden 4 lines below */
|
|
||||||
half_time_just_reached = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* update the counter no matter if we reached half time or not */
|
|
||||||
usart->US_RTOR = compute_next_timeout(ci);
|
|
||||||
/* restart the counter (if wt is 0, the timeout is not started) */
|
|
||||||
usart->US_CR |= US_CR_RETTO;
|
|
||||||
|
|
||||||
if (half_time_just_reached)
|
|
||||||
card_emu_wtime_half_expired(ci->ch);
|
|
||||||
}
|
}
|
||||||
|
usart->US_CR |= US_CR_STTTO; // clear timeout flag (and stop timeout until next character is received)
|
||||||
|
usart->US_CR |= US_CR_RETTO; // restart the counter (it wt is 0, the timeout is not started)
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! ISR called for USART0 */
|
/*! ISR called for USART0 */
|
||||||
@@ -370,39 +294,89 @@ int card_emu_uart_update_fidi(uint8_t uart_chan, unsigned int fidi)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Update WT on USART peripheral. Will automatically re-start timer with new value.
|
// call-back from card_emu.c to change UART baud rate
|
||||||
* \param[in] usart USART peripheral to configure
|
void card_emu_uart_update_fd(uint8_t uart_chan, uint16_t f, uint8_t d)
|
||||||
* \param[in] wt inactivity Waiting Time before card_emu_wtime_expired is called (0 to disable) */
|
{
|
||||||
|
Usart *usart = get_usart_by_chan(uart_chan); // get the USART based on the card handle
|
||||||
|
if (NULL == usart) {
|
||||||
|
TRACE_ERROR("%u: USART not found by chan\r\n", uart_chan);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!iso7816_3_valid_f(f)) {
|
||||||
|
TRACE_ERROR("%u: invalid F: %u\r\n", uart_chan, f);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!iso7816_3_valid_d(d)) {
|
||||||
|
TRACE_ERROR("%u: invalid D: %u\r\n", uart_chan, d);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t ratio = f / d;
|
||||||
|
if (ratio > 0 && ratio < 2048) {
|
||||||
|
/* make sure USART uses new F/D ratio */
|
||||||
|
usart->US_CR |= US_CR_RXDIS | US_CR_RSTRX; // disable USART before changing baud rate
|
||||||
|
usart->US_FIDI = (ratio & 0x7ff); // change baud rate (ratio)
|
||||||
|
usart->US_CR |= US_CR_RXEN | US_CR_STTTO; // re-enable USART (and stop timeout)
|
||||||
|
TRACE_INFO("%u: USART F/D set to %u/%u\r\n", uart_chan, f, d);
|
||||||
|
} else {
|
||||||
|
TRACE_ERROR("%u: USART could not set F/D to %u/%u\r\n", uart_chan, f, d);
|
||||||
|
// TODO become unresponsive
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void card_emu_uart_update_wt(uint8_t uart_chan, uint32_t wt)
|
void card_emu_uart_update_wt(uint8_t uart_chan, uint32_t wt)
|
||||||
{
|
{
|
||||||
OSMO_ASSERT(uart_chan < ARRAY_SIZE(cardem_inst));
|
if (uart_chan >= ARRAY_SIZE(cardem_inst)) {
|
||||||
|
TRACE_ERROR("%u: UART channel out of bounds\r\n", uart_chan);
|
||||||
|
return;
|
||||||
|
}
|
||||||
struct cardem_inst *ci = &cardem_inst[uart_chan];
|
struct cardem_inst *ci = &cardem_inst[uart_chan];
|
||||||
Usart *usart = get_usart_by_chan(uart_chan);
|
Usart *usart = get_usart_by_chan(uart_chan); // get the USART based on the card handle
|
||||||
|
if (NULL == usart) {
|
||||||
if (ci->wt.total != wt) {
|
TRACE_ERROR("%u: USART not found by chan\r\n", uart_chan);
|
||||||
TRACE_DEBUG("%u: USART WT changed from %lu to %lu ETU\r\n", uart_chan,
|
return;
|
||||||
ci->wt.total, wt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ci->wt.total = wt;
|
ci->wt = wt; // save value
|
||||||
/* reset and start the timer */
|
card_emu_uart_reset_wt(uart_chan); // reset and start timer
|
||||||
card_emu_uart_reset_wt(uart_chan);
|
TRACE_INFO("%u: USART WT set to %lu ETU\r\n", uart_chan, wt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! 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)
|
void card_emu_uart_reset_wt(uint8_t uart_chan)
|
||||||
{
|
{
|
||||||
OSMO_ASSERT(uart_chan < ARRAY_SIZE(cardem_inst));
|
if (uart_chan >= ARRAY_SIZE(cardem_inst)) {
|
||||||
|
TRACE_ERROR("%u: UART channel out of bounds\r\n", uart_chan);
|
||||||
|
return;
|
||||||
|
}
|
||||||
struct cardem_inst *ci = &cardem_inst[uart_chan];
|
struct cardem_inst *ci = &cardem_inst[uart_chan];
|
||||||
Usart *usart = get_usart_by_chan(uart_chan);
|
Usart *usart = get_usart_by_chan(uart_chan); // get the USART based on the card handle
|
||||||
|
if (NULL == usart) {
|
||||||
|
TRACE_ERROR("%u: USART not found by chan\r\n", uart_chan);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* FIXME: guard against race with interrupt handler */
|
ci->wt_remaining = ci->wt; // reload WT value
|
||||||
ci->wt.remaining = ci->wt.total;
|
ci->wt_halfed = false; // reset half expired
|
||||||
ci->wt.half_time_notified = false;
|
if (ci->wt_remaining > 0xffff) { // value exceeds the USART TO range
|
||||||
usart->US_RTOR = compute_next_timeout(ci);
|
usart->US_RTOR = 0xffff; // use the MAX
|
||||||
/* restart the counter (if wt is 0, the timeout is not started) */
|
} else {
|
||||||
usart->US_CR |= US_CR_RETTO;
|
usart->US_RTOR = ci->wt_remaining;
|
||||||
|
}
|
||||||
|
usart->US_CR |= US_CR_RETTO; // restart the counter (if wt is 0, the timeout is not started)
|
||||||
|
}
|
||||||
|
|
||||||
|
void card_emu_uart_io_set(uint8_t uart_chan, bool set)
|
||||||
|
{
|
||||||
|
if (uart_chan >= ARRAY_SIZE(cardem_inst)) {
|
||||||
|
TRACE_ERROR("%u: UART channel out of bounds\r\n", uart_chan);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
struct cardem_inst *ci = &cardem_inst[uart_chan];
|
||||||
|
if (set) {
|
||||||
|
PIO_Set(&ci->pin_io);
|
||||||
|
} else {
|
||||||
|
PIO_Clear(&ci->pin_io);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* call-back from card_emu.c to force a USART interrupt */
|
/* call-back from card_emu.c to force a USART interrupt */
|
||||||
@@ -424,9 +398,6 @@ void card_emu_uart_interrupt(uint8_t uart_chan)
|
|||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
|
|
||||||
#ifdef DETECT_VCC_BY_ADC
|
#ifdef DETECT_VCC_BY_ADC
|
||||||
#if !defined(VCC_UV_THRESH_1V8) || !defined(VCC_UV_THRESH_3V)
|
|
||||||
#error "You must define VCC_UV_THRESH_{1V1,3V} if you use ADC VCC detection"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static volatile int adc_triggered = 0;
|
static volatile int adc_triggered = 0;
|
||||||
static int adc_sam3s_reva_errata = 0;
|
static int adc_sam3s_reva_errata = 0;
|
||||||
@@ -475,6 +446,9 @@ static int card_vcc_adc_init(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define VCC_UV_THRESH_1V8 1500000
|
||||||
|
#define VCC_UV_THRESH_3V 2500000
|
||||||
|
|
||||||
static void process_vcc_adc(struct cardem_inst *ci)
|
static void process_vcc_adc(struct cardem_inst *ci)
|
||||||
{
|
{
|
||||||
if (ci->vcc_uv >= VCC_UV_THRESH_3V &&
|
if (ci->vcc_uv >= VCC_UV_THRESH_3V &&
|
||||||
@@ -572,12 +546,20 @@ void mode_cardemu_init(void)
|
|||||||
|
|
||||||
TRACE_ENTRY();
|
TRACE_ENTRY();
|
||||||
|
|
||||||
|
#ifdef PINS_PWR_CARDEMU
|
||||||
|
// enable power on required peripherals, else disable
|
||||||
|
Pin pins_pwr_cardemu[] = { PINS_PWR_CARDEMU };
|
||||||
|
PIO_Configure(pins_pwr_cardemu, PIO_LISTSIZE(pins_pwr_cardemu));
|
||||||
|
#endif /* PINS_PWR_CARDEMU */
|
||||||
#ifdef PINS_CARDSIM
|
#ifdef PINS_CARDSIM
|
||||||
PIO_Configure(pins_cardsim, PIO_LISTSIZE(pins_cardsim));
|
PIO_Configure(pins_cardsim, PIO_LISTSIZE(pins_cardsim));
|
||||||
#endif
|
#endif
|
||||||
|
// ADC channel 6 and 7 are used to measure VCC (else they are grounded)
|
||||||
|
ADC->ADC_CHER |= ADC_CHER_CH6 | ADC_CHER_CH7; // enable the ADC channels to put them in high impedance (else they leak current)
|
||||||
#ifdef DETECT_VCC_BY_ADC
|
#ifdef DETECT_VCC_BY_ADC
|
||||||
card_vcc_adc_init();
|
card_vcc_adc_init(); // configure the ADC to measure VCC
|
||||||
#endif /* DETECT_VCC_BY_ADC */
|
#endif /* DETECT_VCC_BY_ADC */
|
||||||
|
// TODO pull SIMtrace board SIM lines low, else they can leak current back to VCC
|
||||||
|
|
||||||
INIT_LLIST_HEAD(&cardem_inst[0].usb_out_queue);
|
INIT_LLIST_HEAD(&cardem_inst[0].usb_out_queue);
|
||||||
rbuf_reset(&cardem_inst[0].rb);
|
rbuf_reset(&cardem_inst[0].rb);
|
||||||
@@ -585,7 +567,20 @@ void mode_cardemu_init(void)
|
|||||||
|
|
||||||
/* configure USART as ISO-7816 slave (e.g. card) */
|
/* configure USART as ISO-7816 slave (e.g. card) */
|
||||||
ISO7816_Init(&cardem_inst[0].usart_info, CLK_SLAVE);
|
ISO7816_Init(&cardem_inst[0].usart_info, CLK_SLAVE);
|
||||||
|
#ifdef BOARD_simtrace
|
||||||
|
/* simtrace board uses uart timeouts */
|
||||||
|
|
||||||
|
/* don't use receive timeout timer for now */
|
||||||
|
cardem_inst[0].usart_info.base->US_RTOR = 0;
|
||||||
|
/* enable interrupts to indicate when data has been received or timeout occurred */
|
||||||
|
USART_EnableIt(cardem_inst[0].usart_info.base, US_IER_RXRDY | US_IER_TIMEOUT);
|
||||||
|
#else
|
||||||
|
/* enable interrupts to indicate when data has been received */
|
||||||
|
USART_EnableIt(cardem_inst[0].usart_info.base, US_IER_RXRDY );
|
||||||
|
#endif
|
||||||
|
/* enable interrupt requests for the USART peripheral */
|
||||||
NVIC_EnableIRQ(USART1_IRQn);
|
NVIC_EnableIRQ(USART1_IRQn);
|
||||||
|
|
||||||
PIO_ConfigureIt(&pin_usim1_rst, usim1_rst_irqhandler);
|
PIO_ConfigureIt(&pin_usim1_rst, usim1_rst_irqhandler);
|
||||||
PIO_EnableIt(&pin_usim1_rst);
|
PIO_EnableIt(&pin_usim1_rst);
|
||||||
|
|
||||||
@@ -601,17 +596,21 @@ void mode_cardemu_init(void)
|
|||||||
do {} while (!adc_triggered); /* wait for first ADC reading */
|
do {} while (!adc_triggered); /* wait for first ADC reading */
|
||||||
#endif /* DETECT_VCC_BY_ADC */
|
#endif /* DETECT_VCC_BY_ADC */
|
||||||
|
|
||||||
cardem_inst[0].ch = card_emu_init(0, 0, SIMTRACE_CARDEM_USB_EP_USIM1_DATAIN,
|
cardem_inst[0].ch = card_emu_init(0, 2, 0, SIMTRACE_CARDEM_USB_EP_USIM1_DATAIN,
|
||||||
SIMTRACE_CARDEM_USB_EP_USIM1_INT, cardem_inst[0].vcc_active,
|
SIMTRACE_CARDEM_USB_EP_USIM1_INT, cardem_inst[0].vcc_active,
|
||||||
cardem_inst[0].rst_active, cardem_inst[0].vcc_active);
|
cardem_inst[0].rst_active, cardem_inst[0].vcc_active);
|
||||||
sim_switch_use_physical(0, 1);
|
sim_switch_use_physical(0, 1);
|
||||||
|
#ifndef DETECT_VCC_BY_ADC
|
||||||
|
usim1_vcc_irqhandler(NULL); // check VCC/CLK state
|
||||||
|
#endif
|
||||||
|
usim1_rst_irqhandler(NULL); // force RST state
|
||||||
|
|
||||||
#ifdef CARDEMU_SECOND_UART
|
#ifdef CARDEMU_SECOND_UART
|
||||||
INIT_LLIST_HEAD(&cardem_inst[1].usb_out_queue);
|
INIT_LLIST_HEAD(&cardem_inst[1].usb_out_queue);
|
||||||
rbuf_reset(&cardem_inst[1].rb);
|
rbuf_reset(&cardem_inst[1].rb);
|
||||||
PIO_Configure(pins_usim2, PIO_LISTSIZE(pins_usim2));
|
PIO_Configure(pins_usim2, PIO_LISTSIZE(pins_usim2));
|
||||||
ISO7816_Init(&cardem_inst[1].usart_info, CLK_SLAVE);
|
ISO7816_Init(&cardem_inst[1].usart_info, CLK_SLAVE);
|
||||||
/* TODO enable timeout */
|
// TODO enable timeout
|
||||||
NVIC_EnableIRQ(USART0_IRQn);
|
NVIC_EnableIRQ(USART0_IRQn);
|
||||||
PIO_ConfigureIt(&pin_usim2_rst, usim2_rst_irqhandler);
|
PIO_ConfigureIt(&pin_usim2_rst, usim2_rst_irqhandler);
|
||||||
PIO_EnableIt(&pin_usim2_rst);
|
PIO_EnableIt(&pin_usim2_rst);
|
||||||
@@ -624,11 +623,11 @@ void mode_cardemu_init(void)
|
|||||||
do {} while (!adc_triggered); /* wait for first ADC reading */
|
do {} while (!adc_triggered); /* wait for first ADC reading */
|
||||||
#endif /* DETECT_VCC_BY_ADC */
|
#endif /* DETECT_VCC_BY_ADC */
|
||||||
|
|
||||||
cardem_inst[1].ch = card_emu_init(1, 1, SIMTRACE_CARDEM_USB_EP_USIM2_DATAIN,
|
cardem_inst[1].ch = card_emu_init(1, 0, 1, SIMTRACE_CARDEM_USB_EP_USIM2_DATAIN,
|
||||||
SIMTRACE_CARDEM_USB_EP_USIM2_INT, cardem_inst[1].vcc_active,
|
SIMTRACE_CARDEM_USB_EP_USIM2_INT, cardem_inst[1].vcc_active,
|
||||||
cardem_inst[1].rst_active, cardem_inst[1].vcc_active);
|
cardem_inst[1].rst_active, cardem_inst[1].vcc_active);
|
||||||
sim_switch_use_physical(1, 1);
|
sim_switch_use_physical(1, 1);
|
||||||
/* TODO check RST and VCC */
|
// TODO check rst and vcc
|
||||||
#endif /* CARDEMU_SECOND_UART */
|
#endif /* CARDEMU_SECOND_UART */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -672,26 +671,6 @@ static void dispatch_usb_command_generic(struct msgb *msg, struct cardem_inst *c
|
|||||||
usb_buf_free(msg);
|
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 */
|
/* handle a single USB command as received from the USB host */
|
||||||
static void dispatch_usb_command_cardem(struct msgb *msg, struct cardem_inst *ci)
|
static void dispatch_usb_command_cardem(struct msgb *msg, struct cardem_inst *ci)
|
||||||
{
|
{
|
||||||
@@ -715,7 +694,18 @@ static void dispatch_usb_command_cardem(struct msgb *msg, struct cardem_inst *ci
|
|||||||
break;
|
break;
|
||||||
case SIMTRACE_MSGT_DT_CEMU_CARDINSERT:
|
case SIMTRACE_MSGT_DT_CEMU_CARDINSERT:
|
||||||
cardins = (struct cardemu_usb_msg_cardinsert *) msg->l2h;
|
cardins = (struct cardemu_usb_msg_cardinsert *) msg->l2h;
|
||||||
process_card_insert(ci, cardins->card_insert);
|
if (!ci->pin_insert.pio) {
|
||||||
|
TRACE_INFO("%u: skipping unsupported card_insert to %s\r\n",
|
||||||
|
ci->num, cardins->card_insert ? "INSERTED" : "REMOVED");
|
||||||
|
usb_buf_free(msg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
TRACE_INFO("%u: set card_insert to %s\r\n", ci->num,
|
||||||
|
cardins->card_insert ? "INSERTED" : "REMOVED");
|
||||||
|
if (cardins->card_insert)
|
||||||
|
PIO_Set(&ci->pin_insert);
|
||||||
|
else
|
||||||
|
PIO_Clear(&ci->pin_insert);
|
||||||
usb_buf_free(msg);
|
usb_buf_free(msg);
|
||||||
break;
|
break;
|
||||||
case SIMTRACE_MSGT_BD_CEMU_STATUS:
|
case SIMTRACE_MSGT_BD_CEMU_STATUS:
|
||||||
@@ -801,9 +791,8 @@ static void dispatch_usb_command_modem(struct msgb *msg, struct cardem_inst *ci)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* handle a single USB command as received from the USB host */
|
/* handle a single USB command as received from the USB host */
|
||||||
static void dispatch_usb_command(struct msgb *msg, const struct usb_if *usb_if)
|
static void dispatch_usb_command(struct msgb *msg, struct cardem_inst *ci)
|
||||||
{
|
{
|
||||||
struct cardem_inst *ci = usb_if->data;
|
|
||||||
struct simtrace_msg_hdr *sh = (struct simtrace_msg_hdr *) msg->l1h;
|
struct simtrace_msg_hdr *sh = (struct simtrace_msg_hdr *) msg->l1h;
|
||||||
|
|
||||||
if (msgb_length(msg) < sizeof(*sh)) {
|
if (msgb_length(msg) < sizeof(*sh)) {
|
||||||
@@ -832,8 +821,7 @@ static void dispatch_usb_command(struct msgb *msg, const struct usb_if *usb_if)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* handle a single USB transfer as received from the USB host */
|
static void dispatch_received_msg(struct msgb *msg, struct cardem_inst *ci)
|
||||||
static void dispatch_received_usb_msg(struct msgb *msg, const struct usb_if *usb_if)
|
|
||||||
{
|
{
|
||||||
struct msgb *segm;
|
struct msgb *segm;
|
||||||
struct simtrace_msg_hdr *mh;
|
struct simtrace_msg_hdr *mh;
|
||||||
@@ -844,7 +832,7 @@ static void dispatch_received_usb_msg(struct msgb *msg, const struct usb_if *usb
|
|||||||
mh = (struct simtrace_msg_hdr *) msg->data;
|
mh = (struct simtrace_msg_hdr *) msg->data;
|
||||||
if (mh->msg_len == msgb_length(msg)) {
|
if (mh->msg_len == msgb_length(msg)) {
|
||||||
/* fast path: only one message in buffer */
|
/* fast path: only one message in buffer */
|
||||||
dispatch_usb_command(msg, usb_if);
|
dispatch_usb_command(msg, ci);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -853,23 +841,23 @@ static void dispatch_received_usb_msg(struct msgb *msg, const struct usb_if *usb
|
|||||||
while (1) {
|
while (1) {
|
||||||
mh = (struct simtrace_msg_hdr *) msg->data;
|
mh = (struct simtrace_msg_hdr *) msg->data;
|
||||||
|
|
||||||
segm = usb_buf_alloc(usb_if->ep_out);
|
segm = usb_buf_alloc(ci->ep_out);
|
||||||
if (!segm) {
|
if (!segm) {
|
||||||
TRACE_ERROR("%u: ENOMEM during msg segmentation\r\n",
|
TRACE_ERROR("%u: ENOMEM during msg segmentation\r\n",
|
||||||
usb_if->if_num);
|
ci->num);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mh->msg_len > msgb_length(msg)) {
|
if (mh->msg_len > msgb_length(msg)) {
|
||||||
TRACE_ERROR("%u: Unexpected large message (%u bytes)\r\n",
|
TRACE_ERROR("%u: Unexpected large message (%u bytes)\r\n",
|
||||||
usb_if->if_num, mh->msg_len);
|
ci->num, mh->msg_len);
|
||||||
usb_buf_free(segm);
|
usb_buf_free(segm);
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
uint8_t *cur = msgb_put(segm, mh->msg_len);
|
uint8_t *cur = msgb_put(segm, mh->msg_len);
|
||||||
segm->l1h = segm->head;
|
segm->l1h = segm->head;
|
||||||
memcpy(cur, mh, mh->msg_len);
|
memcpy(cur, mh, mh->msg_len);
|
||||||
dispatch_usb_command(segm, usb_if);
|
dispatch_usb_command(segm, ci);
|
||||||
}
|
}
|
||||||
/* pull this message */
|
/* pull this message */
|
||||||
msgb_pull(msg, mh->msg_len);
|
msgb_pull(msg, mh->msg_len);
|
||||||
@@ -881,14 +869,35 @@ static void dispatch_received_usb_msg(struct msgb *msg, const struct usb_if *usb
|
|||||||
usb_buf_free(msg);
|
usb_buf_free(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* iterate over the queue of incoming USB commands and dispatch/execute
|
||||||
|
* them */
|
||||||
|
static void process_any_usb_commands(struct llist_head *main_q,
|
||||||
|
struct cardem_inst *ci)
|
||||||
|
{
|
||||||
|
struct llist_head *lh;
|
||||||
|
struct msgb *msg;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* limit the number of iterations to 10, to ensure we don't get
|
||||||
|
* stuck here without returning to main loop processing */
|
||||||
|
for (i = 0; i < 10; i++) {
|
||||||
|
/* de-queue the list head in an irq-safe way */
|
||||||
|
lh = llist_head_dequeue_irqsafe(main_q);
|
||||||
|
if (!lh)
|
||||||
|
break;
|
||||||
|
msg = llist_entry(lh, struct msgb, list);
|
||||||
|
dispatch_received_msg(msg, ci);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* main loop function, called repeatedly */
|
/* main loop function, called repeatedly */
|
||||||
void mode_cardemu_run(void)
|
void mode_cardemu_run(void)
|
||||||
{
|
{
|
||||||
|
struct llist_head *queue;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(cardem_inst); i++) {
|
for (i = 0; i < ARRAY_SIZE(cardem_inst); i++) {
|
||||||
struct cardem_inst *ci = &cardem_inst[i];
|
struct cardem_inst *ci = &cardem_inst[i];
|
||||||
struct usb_if *usb_if = &ci->usb_if;
|
|
||||||
|
|
||||||
/* drain the ring buffer from UART into card_emu */
|
/* drain the ring buffer from UART into card_emu */
|
||||||
while (1) {
|
while (1) {
|
||||||
@@ -905,6 +914,16 @@ void mode_cardemu_run(void)
|
|||||||
|
|
||||||
process_io_statechg(ci);
|
process_io_statechg(ci);
|
||||||
|
|
||||||
usb_process(&ci->usb_if);
|
/* first try to send any pending messages on IRQ */
|
||||||
|
usb_refill_to_host(ci->ep_int);
|
||||||
|
|
||||||
|
/* then try to send any pending messages on IN */
|
||||||
|
usb_refill_to_host(ci->ep_in);
|
||||||
|
|
||||||
|
/* ensure we can handle incoming USB messages from the
|
||||||
|
* host */
|
||||||
|
usb_refill_from_host(ci->ep_out);
|
||||||
|
queue = usb_get_queue(ci->ep_out);
|
||||||
|
process_any_usb_commands(queue, ci);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ void update_fidi(Usart_info *usart, uint8_t fidi)
|
|||||||
|
|
||||||
uint8_t fi = fidi >> 4;
|
uint8_t fi = fidi >> 4;
|
||||||
uint8_t di = fidi & 0xf;
|
uint8_t di = fidi & 0xf;
|
||||||
int ratio = iso7816_3_compute_fd_ratio(fi, di);
|
int ratio = compute_fidi_ratio(fi, di);
|
||||||
|
|
||||||
if (ratio > 0 && ratio < 0x8000) {
|
if (ratio > 0 && ratio < 0x8000) {
|
||||||
/* make sure USART uses new F/D ratio */
|
/* make sure USART uses new F/D ratio */
|
||||||
|
|||||||
@@ -658,10 +658,9 @@ static void process_byte_pps(uint8_t byte)
|
|||||||
fn = 1;
|
fn = 1;
|
||||||
dn = 1;
|
dn = 1;
|
||||||
}
|
}
|
||||||
TRACE_INFO("PPS negotiation successful: Fn=%u Dn=%u\n\r",
|
TRACE_INFO("PPS negotiation successful: Fn=%u Dn=%u\n\r", fi_table[fn], di_table[dn]);
|
||||||
iso7816_3_fi_table[fn], iso7816_3_di_table[dn]);
|
|
||||||
update_fidi(&sniff_usart, pps_cur[2]);
|
update_fidi(&sniff_usart, pps_cur[2]);
|
||||||
update_wt(0, iso7816_3_di_table[dn]);
|
update_wt(0, di_table[dn]);
|
||||||
usb_send_fidi(pps_cur[2]); /* send Fi/Di change notification to host software over USB */
|
usb_send_fidi(pps_cur[2]); /* send Fi/Di change notification to host software over USB */
|
||||||
} else { /* checksum is invalid */
|
} else { /* checksum is invalid */
|
||||||
TRACE_INFO("PPS negotiation failed\n\r");
|
TRACE_INFO("PPS negotiation failed\n\r");
|
||||||
@@ -975,42 +974,20 @@ static void usb_send_change(uint32_t flags)
|
|||||||
usb_msg_upd_len_and_submit(usb_msg);
|
usb_msg_upd_len_and_submit(usb_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* handle incoming message from USB OUT EP */
|
|
||||||
static void dispatch_usb_out(struct msgb *msg, const struct usb_if *usb_if)
|
|
||||||
{
|
|
||||||
struct simtrace_msg_hdr *sh = (struct simtrace_msg_hdr *) msg->l1h;
|
|
||||||
|
|
||||||
if (msgb_length(msg) < sizeof(*sh)) {
|
|
||||||
usb_buf_free(msg);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
msg->l2h = msg->l1h + sizeof(*sh);
|
|
||||||
|
|
||||||
switch (sh->msg_class) {
|
|
||||||
case SIMTRACE_MSGC_GENERIC:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
usb_buf_free(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct usb_if sniffer_usb_if = {
|
|
||||||
.if_num = 0,
|
|
||||||
.ep_in = SIMTRACE_USB_EP_CARD_DATAIN,
|
|
||||||
.ep_int = SIMTRACE_USB_EP_CARD_INT,
|
|
||||||
.ep_out = SIMTRACE_USB_EP_CARD_DATAOUT,
|
|
||||||
.ops = {
|
|
||||||
.rx_out = dispatch_usb_out,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Main (idle/busy) loop of this USB configuration */
|
/* Main (idle/busy) loop of this USB configuration */
|
||||||
void Sniffer_run(void)
|
void Sniffer_run(void)
|
||||||
{
|
{
|
||||||
/* Handle USB queue */
|
/* Handle USB queue */
|
||||||
usb_process(&sniffer_usb_if);
|
/* first try to send any pending messages on INT */
|
||||||
|
usb_refill_to_host(SIMTRACE_USB_EP_CARD_INT);
|
||||||
|
/* then try to send any pending messages on IN */
|
||||||
|
usb_refill_to_host(SIMTRACE_USB_EP_CARD_DATAIN);
|
||||||
|
/* ensure we can handle incoming USB messages from the host */
|
||||||
|
/* currently we don't need any incoming data
|
||||||
|
usb_refill_from_host(SIMTRACE_USB_EP_CARD_DATAOUT);
|
||||||
|
struct llist_head *queue = usb_get_queue(SIMTRACE_USB_EP_CARD_DATAOUT);
|
||||||
|
process_any_usb_commands(queue);
|
||||||
|
*/
|
||||||
|
|
||||||
/* WARNING: the signal data and flags are not synchronized. We have to hope
|
/* WARNING: the signal data and flags are not synchronized. We have to hope
|
||||||
* the processing is fast enough to not land in the wrong state while data
|
* the processing is fast enough to not land in the wrong state while data
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
#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");
|
|
||||||
}
|
|
||||||
@@ -23,6 +23,9 @@
|
|||||||
|
|
||||||
#include "chip.h"
|
#include "chip.h"
|
||||||
|
|
||||||
|
void card_emu_wt_halfed(void *handle);
|
||||||
|
void card_emu_wt_expired(void *handle);
|
||||||
|
|
||||||
/* pins for Channel 0 of TC-block 0, we only use TCLK + TIOB */
|
/* pins for Channel 0 of TC-block 0, we only use TCLK + TIOB */
|
||||||
#define PIN_TCLK0 {PIO_PA4, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT }
|
#define PIN_TCLK0 {PIO_PA4, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT }
|
||||||
#define PIN_TIOA0 {PIO_PA0, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
|
#define PIN_TIOA0 {PIO_PA0, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
|
||||||
@@ -85,7 +88,7 @@ static void tc_etu_irq(struct tc_etu_state *te)
|
|||||||
te->nr_events++;
|
te->nr_events++;
|
||||||
if (te->nr_events == te->wait_events/2) {
|
if (te->nr_events == te->wait_events/2) {
|
||||||
/* Indicate that half the waiting tim has expired */
|
/* Indicate that half the waiting tim has expired */
|
||||||
tc_etu_wtime_half_expired(te->handle);
|
card_emu_wt_halfed(te->handle);
|
||||||
}
|
}
|
||||||
if (te->nr_events >= te->wait_events) {
|
if (te->nr_events >= te->wait_events) {
|
||||||
TcChannel *chan = te->chan;
|
TcChannel *chan = te->chan;
|
||||||
@@ -96,7 +99,7 @@ static void tc_etu_irq(struct tc_etu_state *te)
|
|||||||
chan->TC_CCR = TC_CCR_CLKEN;
|
chan->TC_CCR = TC_CCR_CLKEN;
|
||||||
|
|
||||||
/* Indicate that the waiting tim has expired */
|
/* Indicate that the waiting tim has expired */
|
||||||
tc_etu_wtime_expired(te->handle);
|
card_emu_wt_expired(te->handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ const char *get_value_string_or_null(const struct value_string *vs,
|
|||||||
int get_string_value(const struct value_string *vs, const char *str);
|
int get_string_value(const struct value_string *vs, const char *str);
|
||||||
|
|
||||||
char osmo_bcd2char(uint8_t bcd);
|
char osmo_bcd2char(uint8_t bcd);
|
||||||
/* only works for numbers in ascci */
|
/* only works for numbers in ASCII */
|
||||||
uint8_t osmo_char2bcd(char c);
|
uint8_t osmo_char2bcd(char c);
|
||||||
|
|
||||||
int osmo_hexparse(const char *str, uint8_t *b, int max_len);
|
int osmo_hexparse(const char *str, uint8_t *b, int max_len);
|
||||||
@@ -60,7 +60,7 @@ do { \
|
|||||||
rem -= ret; \
|
rem -= ret; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/*! Helper macro to terminate when an assertion failes
|
/*! Helper macro to terminate when an assertion fails
|
||||||
* \param[in] exp Predicate to verify
|
* \param[in] exp Predicate to verify
|
||||||
* This function will generate a backtrace and terminate the program if
|
* This function will generate a backtrace and terminate the program if
|
||||||
* the predicate evaluates to false (0).
|
* the predicate evaluates to false (0).
|
||||||
@@ -75,7 +75,7 @@ do { \
|
|||||||
/*! duplicate a string using talloc and release its prior content (if any)
|
/*! duplicate a string using talloc and release its prior content (if any)
|
||||||
* \param[in] ctx Talloc context to use for allocation
|
* \param[in] ctx Talloc context to use for allocation
|
||||||
* \param[out] dst pointer to string, will be updated with ptr to new string
|
* \param[out] dst pointer to string, will be updated with ptr to new string
|
||||||
* \param[in] newstr String that will be copieed to newly allocated string */
|
* \param[in] newstr String that will be copied to newly allocated string */
|
||||||
static inline void osmo_talloc_replace_string(void *ctx, char **dst, const char *newstr)
|
static inline void osmo_talloc_replace_string(void *ctx, char **dst, const char *newstr)
|
||||||
{
|
{
|
||||||
if (*dst)
|
if (*dst)
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ static osmo_panic_handler_t osmo_panic_handler = (void*)0;
|
|||||||
__attribute__ ((format (printf, 1, 0)))
|
__attribute__ ((format (printf, 1, 0)))
|
||||||
static void osmo_panic_default(const char *fmt, va_list args)
|
static void osmo_panic_default(const char *fmt, va_list args)
|
||||||
{
|
{
|
||||||
vfprintf_sync(stderr, fmt, args);
|
vfprintf(stderr, fmt, args);
|
||||||
osmo_generate_backtrace();
|
osmo_generate_backtrace();
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,20 +13,6 @@
|
|||||||
#define PHONE_INT 2
|
#define PHONE_INT 2
|
||||||
#define PHONE_DATAOUT 3
|
#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
|
* stub functions required by card_emu.c
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
@@ -64,9 +50,6 @@ void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx)
|
|||||||
case ENABLE_TX:
|
case ENABLE_TX:
|
||||||
rts = "TX";
|
rts = "TX";
|
||||||
break;
|
break;
|
||||||
case ENABLE_TX_TIMER_ONLY:
|
|
||||||
rts = "TX-TIMER-ONLY";
|
|
||||||
break;
|
|
||||||
case ENABLE_RX:
|
case ENABLE_RX:
|
||||||
rts = "RX";
|
rts = "RX";
|
||||||
break;
|
break;
|
||||||
@@ -83,14 +66,29 @@ void card_emu_uart_interrupt(uint8_t uart_chan)
|
|||||||
printf("uart_interrupt(uart_chan=%u)\n", uart_chan);
|
printf("uart_interrupt(uart_chan=%u)\n", uart_chan);
|
||||||
}
|
}
|
||||||
|
|
||||||
void card_emu_uart_update_wt(uint8_t uart_chan, uint32_t wt)
|
void tc_etu_set_wtime(uint8_t tc_chan, uint16_t wtime)
|
||||||
{
|
{
|
||||||
printf("%s(uart_chan=%u, wtime=%u)\n", __func__, uart_chan, wt);
|
printf("tc_etu_set_wtime(tc_chan=%u, wtime=%u)\n", tc_chan, wtime);
|
||||||
}
|
}
|
||||||
|
|
||||||
void card_emu_uart_reset_wt(uint8_t uart_chan)
|
void tc_etu_set_etu(uint8_t tc_chan, uint16_t etu)
|
||||||
{
|
{
|
||||||
printf("%s(uart_chan=%u\n", __func__, 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -138,7 +136,7 @@ static void io_start_card(struct card_handle *ch)
|
|||||||
/* release from reset and verify th ATR */
|
/* release from reset and verify th ATR */
|
||||||
card_emu_io_statechg(ch, CARD_IO_RST, 0);
|
card_emu_io_statechg(ch, CARD_IO_RST, 0);
|
||||||
/* simulate waiting time before ATR expired */
|
/* simulate waiting time before ATR expired */
|
||||||
card_emu_wtime_expired(ch);
|
tc_etu_wtime_expired(ch);
|
||||||
verify_atr(ch);
|
verify_atr(ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -410,7 +408,7 @@ int main(int argc, char **argv)
|
|||||||
struct card_handle *ch;
|
struct card_handle *ch;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
ch = card_emu_init(0, 42, PHONE_DATAIN, PHONE_INT, false, true, false);
|
ch = card_emu_init(0, 23, 42, PHONE_DATAIN, PHONE_INT, false, true, false);
|
||||||
assert(ch);
|
assert(ch);
|
||||||
|
|
||||||
usb_buf_init();
|
usb_buf_init();
|
||||||
|
|||||||
3
host/.gitignore
vendored
3
host/.gitignore
vendored
@@ -34,4 +34,5 @@ libtool
|
|||||||
|
|
||||||
simtrace2-list
|
simtrace2-list
|
||||||
simtrace2-sniff
|
simtrace2-sniff
|
||||||
simtrace2-cardem-pcsc
|
simtrace2-remsim
|
||||||
|
simtrace2-remsim-usb2udp
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6
|
|||||||
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include
|
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include
|
||||||
SUBDIRS = include lib src contrib #tests examples doc
|
SUBDIRS = include lib src contrib #tests examples doc
|
||||||
|
|
||||||
EXTRA_DIST = .version
|
EXTRA_DIST = .version git-version-gen
|
||||||
|
|
||||||
pkgconfigdir = $(libdir)/pkgconfig
|
pkgconfigdir = $(libdir)/pkgconfig
|
||||||
pkgconfig_DATA = libosmo-simtrace2.pc
|
pkgconfig_DATA = libosmo-simtrace2.pc
|
||||||
|
|||||||
28
host/Makefile.old
Normal file
28
host/Makefile.old
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
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/
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
AC_INIT([simtrace2],
|
AC_INIT([simtrace2],
|
||||||
m4_esyscmd([../git-version-gen ../.tarball-version]),
|
m4_esyscmd([./git-version-gen .tarball-version]),
|
||||||
[simtrace@lists.osmocom.org])
|
[simtrace@lists.osmocom.org])
|
||||||
|
|
||||||
dnl *This* is the root dir, even if an install-sh exists in ../ or ../../
|
dnl *This* is the root dir, even if an install-sh exists in ../ or ../../
|
||||||
@@ -100,5 +100,4 @@ AC_OUTPUT(
|
|||||||
src/Makefile
|
src/Makefile
|
||||||
lib/Makefile
|
lib/Makefile
|
||||||
contrib/Makefile
|
contrib/Makefile
|
||||||
contrib/simtrace2.spec
|
|
||||||
Makefile)
|
Makefile)
|
||||||
|
|||||||
@@ -1,99 +0,0 @@
|
|||||||
#
|
|
||||||
# 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
|
|
||||||
151
host/git-version-gen
Executable file
151
host/git-version-gen
Executable file
@@ -0,0 +1,151 @@
|
|||||||
|
#!/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:
|
||||||
@@ -12,8 +12,6 @@ struct osmo_st2_transport {
|
|||||||
uint8_t out;
|
uint8_t out;
|
||||||
uint8_t irq_in;
|
uint8_t irq_in;
|
||||||
} usb_ep;
|
} usb_ep;
|
||||||
/* use non-blocking / asynchronous libusb I/O */
|
|
||||||
bool usb_async;
|
|
||||||
|
|
||||||
/* UDP */
|
/* UDP */
|
||||||
int udp_fd;
|
int udp_fd;
|
||||||
@@ -41,6 +39,8 @@ struct osmo_st2_cardem_inst {
|
|||||||
void *priv;
|
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,
|
int osmo_st2_slot_tx_msg(struct osmo_st2_slot *slot, struct msgb *msg,
|
||||||
uint8_t msg_class, uint8_t msg_type);
|
uint8_t msg_class, uint8_t msg_type);
|
||||||
|
|
||||||
|
|||||||
@@ -44,13 +44,9 @@
|
|||||||
#include <osmocom/core/utils.h>
|
#include <osmocom/core/utils.h>
|
||||||
#include <osmocom/core/socket.h>
|
#include <osmocom/core/socket.h>
|
||||||
#include <osmocom/core/msgb.h>
|
#include <osmocom/core/msgb.h>
|
||||||
#include <osmocom/core/logging.h>
|
|
||||||
#include <osmocom/sim/class_tables.h>
|
#include <osmocom/sim/class_tables.h>
|
||||||
#include <osmocom/sim/sim.h>
|
#include <osmocom/sim/sim.h>
|
||||||
|
|
||||||
#define LOGSLOT(slot, lvl, fmt, args...) \
|
|
||||||
LOGP(DLINP, lvl, "[%u] " fmt, (slot)->slot_nr, ## args)
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* SIMTRACE core protocol
|
* SIMTRACE core protocol
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
@@ -61,60 +57,23 @@ static struct msgb *st_msgb_alloc(void)
|
|||||||
return msgb_alloc_headroom(1024+32, 32, "SIMtrace");
|
return msgb_alloc_headroom(1024+32, 32, "SIMtrace");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void usb_out_xfer_cb(struct libusb_transfer *xfer)
|
|
||||||
{
|
|
||||||
struct msgb *msg = xfer->user_data;
|
|
||||||
|
|
||||||
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 */
|
/*! \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 osmo_st2_transp_tx_msg(struct osmo_st2_transport *transp, struct msgb *msg)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
printf("<- %s\n", msgb_hexdump(msg));
|
||||||
|
|
||||||
|
if (transp->udp_fd < 0) {
|
||||||
int xfer_len;
|
int xfer_len;
|
||||||
|
|
||||||
rc = libusb_bulk_transfer(transp->usb_devh, transp->usb_ep.out,
|
rc = libusb_bulk_transfer(transp->usb_devh, transp->usb_ep.out,
|
||||||
msgb_data(msg), msgb_length(msg),
|
msgb_data(msg), msgb_length(msg),
|
||||||
&xfer_len, 100000);
|
&xfer_len, 100000);
|
||||||
|
} else {
|
||||||
|
rc = write(transp->udp_fd, msgb_data(msg), msgb_length(msg));
|
||||||
|
}
|
||||||
|
|
||||||
msgb_free(msg);
|
msgb_free(msg);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -139,23 +98,9 @@ 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,
|
int osmo_st2_slot_tx_msg(struct osmo_st2_slot *slot, struct msgb *msg,
|
||||||
uint8_t msg_class, uint8_t msg_type)
|
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);
|
st_push_hdr(msg, msg_class, msg_type, slot->slot_nr);
|
||||||
|
|
||||||
if (transp->udp_fd < 0) {
|
return osmo_st2_transp_tx_msg(slot->transp, msg);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
@@ -169,8 +114,6 @@ int osmo_st2_cardem_request_card_insert(struct osmo_st2_cardem_inst *ci, bool in
|
|||||||
struct msgb *msg = st_msgb_alloc();
|
struct msgb *msg = st_msgb_alloc();
|
||||||
struct cardemu_usb_msg_cardinsert *cins;
|
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));
|
cins = (struct cardemu_usb_msg_cardinsert *) msgb_put(msg, sizeof(*cins));
|
||||||
memset(cins, 0, sizeof(*cins));
|
memset(cins, 0, sizeof(*cins));
|
||||||
if (inserted)
|
if (inserted)
|
||||||
@@ -186,7 +129,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;
|
struct cardemu_usb_msg_tx_data *txd;
|
||||||
txd = (struct cardemu_usb_msg_tx_data *) msgb_put(msg, sizeof(*txd));
|
txd = (struct cardemu_usb_msg_tx_data *) msgb_put(msg, sizeof(*txd));
|
||||||
|
|
||||||
LOGSLOT(ci->slot, LOGL_DEBUG, "<= %s(pb=%02x, le=%u)\n", __func__, pb, le);
|
printf("<= %s(%02x, %d)\n", __func__, pb, le);
|
||||||
|
|
||||||
memset(txd, 0, sizeof(*txd));
|
memset(txd, 0, sizeof(*txd));
|
||||||
txd->data_len = 1;
|
txd->data_len = 1;
|
||||||
@@ -207,7 +150,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));
|
txd = (struct cardemu_usb_msg_tx_data *) msgb_put(msg, sizeof(*txd));
|
||||||
|
|
||||||
LOGSLOT(ci->slot, LOGL_DEBUG, "<= %s(pb=%02x, tx=%s, len=%d)\n", __func__, pb,
|
printf("<= %s(%02x, %s, %d)\n", __func__, pb,
|
||||||
osmo_hexdump(data, data_len_in), data_len_in);
|
osmo_hexdump(data, data_len_in), data_len_in);
|
||||||
|
|
||||||
memset(txd, 0, sizeof(*txd));
|
memset(txd, 0, sizeof(*txd));
|
||||||
@@ -231,7 +174,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));
|
txd = (struct cardemu_usb_msg_tx_data *) msgb_put(msg, sizeof(*txd));
|
||||||
|
|
||||||
LOGSLOT(ci->slot, LOGL_DEBUG, "<= %s(sw=%02x%02x)\n", __func__, sw[0], sw[1]);
|
printf("<= %s(%02x %02x)\n", __func__, sw[0], sw[1]);
|
||||||
|
|
||||||
memset(txd, 0, sizeof(*txd));
|
memset(txd, 0, sizeof(*txd));
|
||||||
txd->data_len = 2;
|
txd->data_len = 2;
|
||||||
@@ -251,7 +194,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));
|
satr = (struct cardemu_usb_msg_set_atr *) msgb_put(msg, sizeof(*satr));
|
||||||
|
|
||||||
LOGSLOT(ci->slot, LOGL_NOTICE, "<= %s(%s)\n", __func__, osmo_hexdump(atr, atr_len));
|
printf("<= %s(%s)\n", __func__, osmo_hexdump(atr, atr_len));
|
||||||
|
|
||||||
memset(satr, 0, sizeof(*satr));
|
memset(satr, 0, sizeof(*satr));
|
||||||
satr->atr_len = atr_len;
|
satr->atr_len = atr_len;
|
||||||
@@ -268,7 +211,7 @@ int osmo_st2_cardem_request_config(struct osmo_st2_cardem_inst *ci, uint32_t fea
|
|||||||
|
|
||||||
cfg = (struct cardemu_usb_msg_config *) msgb_put(msg, sizeof(*cfg));
|
cfg = (struct cardemu_usb_msg_config *) msgb_put(msg, sizeof(*cfg));
|
||||||
|
|
||||||
LOGSLOT(ci->slot, LOGL_NOTICE, "<= %s(features=%08x)\n", __func__, features);
|
printf("<= %s(%08x)\n", __func__, features);
|
||||||
|
|
||||||
memset(cfg, 0, sizeof(*cfg));
|
memset(cfg, 0, sizeof(*cfg));
|
||||||
cfg->features = features;
|
cfg->features = features;
|
||||||
@@ -285,9 +228,6 @@ static int _modem_reset(struct osmo_st2_slot *slot, uint8_t asserted, uint16_t p
|
|||||||
struct msgb *msg = st_msgb_alloc();
|
struct msgb *msg = st_msgb_alloc();
|
||||||
struct st_modem_reset *sr ;
|
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 = (struct st_modem_reset *) msgb_put(msg, sizeof(*sr));
|
||||||
sr->asserted = asserted;
|
sr->asserted = asserted;
|
||||||
sr->pulse_duration_msec = pulse_ms;
|
sr->pulse_duration_msec = pulse_ms;
|
||||||
@@ -318,8 +258,6 @@ static int _modem_sim_select(struct osmo_st2_slot *slot, uint8_t remote_sim)
|
|||||||
struct msgb *msg = st_msgb_alloc();
|
struct msgb *msg = st_msgb_alloc();
|
||||||
struct st_modem_sim_select *ss;
|
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 = (struct st_modem_sim_select *) msgb_put(msg, sizeof(*ss));
|
||||||
ss->remote_sim = remote_sim;
|
ss->remote_sim = remote_sim;
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,5 @@ const struct dev_id osmo_st2_compatible_dev_ids[] = {
|
|||||||
{ USB_VENDOR_OPENMOKO, USB_PRODUCT_OWHW_SAM3 },
|
{ USB_VENDOR_OPENMOKO, USB_PRODUCT_OWHW_SAM3 },
|
||||||
{ USB_VENDOR_OPENMOKO, USB_PRODUCT_QMOD_SAM3 },
|
{ USB_VENDOR_OPENMOKO, USB_PRODUCT_QMOD_SAM3 },
|
||||||
{ USB_VENDOR_OPENMOKO, USB_PRODUCT_SIMTRACE2 },
|
{ USB_VENDOR_OPENMOKO, USB_PRODUCT_SIMTRACE2 },
|
||||||
{ USB_VENDOR_OPENMOKO, USB_PRODUCT_OCTSIMTEST },
|
|
||||||
{ 0, 0 }
|
{ 0, 0 }
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ AM_LDFLAGS=$(COVERAGE_LDFLAGS)
|
|||||||
LDADD= $(top_builddir)/lib/libosmo-simtrace2.la \
|
LDADD= $(top_builddir)/lib/libosmo-simtrace2.la \
|
||||||
$(LIBOSMOCORE_LIBS) $(LIBOSMOSIM_LIBS) $(LIBOSMOUSB_LIBS) $(LIBUSB_LIBS)
|
$(LIBOSMOCORE_LIBS) $(LIBOSMOSIM_LIBS) $(LIBOSMOUSB_LIBS) $(LIBUSB_LIBS)
|
||||||
|
|
||||||
bin_PROGRAMS = simtrace2-cardem-pcsc simtrace2-list simtrace2-sniff simtrace2-tool
|
bin_PROGRAMS = simtrace2-remsim simtrace2-remsim-usb2udp simtrace2-list simtrace2-sniff
|
||||||
|
|
||||||
simtrace2_cardem_pcsc_SOURCES = simtrace2-cardem-pcsc.c
|
simtrace2_remsim_SOURCES = simtrace2-remsim.c
|
||||||
|
|
||||||
|
simtrace2_remsim_usb2udp_SOURCES = usb2udp.c
|
||||||
|
|
||||||
simtrace2_list_SOURCES = simtrace2_usb.c
|
simtrace2_list_SOURCES = simtrace2_usb.c
|
||||||
|
|
||||||
simtrace2_sniff_SOURCES = simtrace2-sniff.c
|
simtrace2_sniff_SOURCES = simtrace2-sniff.c
|
||||||
|
|
||||||
simtrace2_tool_SOURCES = simtrace2-tool.c
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* simtrace2-cardem-pcsc - main program for the host PC to provide a remote SIM
|
/* simtrace2-remsim - main program for the host PC to provide a remote SIM
|
||||||
* using the SIMtrace 2 firmware in card emulation mode
|
* using the SIMtrace 2 firmware in card emulation mode
|
||||||
*
|
*
|
||||||
* (C) 2016-2021 by Harald Welte <hwelte@hmw-consulting.de>
|
* (C) 2016-2017 by Harald Welte <hwelte@hmw-consulting.de>
|
||||||
* (C) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
|
* (C) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
@@ -47,13 +47,28 @@
|
|||||||
#include <osmocom/core/utils.h>
|
#include <osmocom/core/utils.h>
|
||||||
#include <osmocom/core/socket.h>
|
#include <osmocom/core/socket.h>
|
||||||
#include <osmocom/core/msgb.h>
|
#include <osmocom/core/msgb.h>
|
||||||
#include <osmocom/core/select.h>
|
|
||||||
#include <osmocom/core/logging.h>
|
|
||||||
#include <osmocom/core/application.h>
|
|
||||||
#include <osmocom/sim/class_tables.h>
|
#include <osmocom/sim/class_tables.h>
|
||||||
#include <osmocom/sim/sim.h>
|
#include <osmocom/sim/sim.h>
|
||||||
|
|
||||||
#define LOGCI(ci, lvl, fmt, args ...) printf(fmt, ## args)
|
/*
|
||||||
|
reasonable ATR offering all protocols and voltages
|
||||||
|
smartphones might not care, but other readers do
|
||||||
|
|
||||||
|
TS = 0x3B Direct Convention
|
||||||
|
T0 = 0x80 Y(1): b1000, K: 0 (historical bytes)
|
||||||
|
TD(1) = 0x80 Y(i+1) = b1000, Protocol T=0
|
||||||
|
----
|
||||||
|
TD(2) = 0x81 Y(i+1) = b1000, Protocol T=1
|
||||||
|
----
|
||||||
|
TD(3) = 0x1F Y(i+1) = b0001, Protocol T=15
|
||||||
|
----
|
||||||
|
TA(4) = 0xC7 Clock stop: no preference - Class accepted by the card: (3G) A 5V B 3V C 1.8V
|
||||||
|
----
|
||||||
|
Historical bytes
|
||||||
|
TCK = 0x59 correct checksum
|
||||||
|
*/
|
||||||
|
static uint8_t real_atr[] = { 0x3B, 0x80, 0x80, 0x81 , 0x1F, 0xC7, 0x59};
|
||||||
|
|
||||||
|
|
||||||
static void atr_update_csum(uint8_t *atr, unsigned int atr_len)
|
static void atr_update_csum(uint8_t *atr, unsigned int atr_len)
|
||||||
{
|
{
|
||||||
@@ -66,37 +81,6 @@ static void atr_update_csum(uint8_t *atr, unsigned int atr_len)
|
|||||||
atr[atr_len-1] = csum;
|
atr[atr_len-1] = csum;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cemu_flags2str(char *out, unsigned int out_len, uint32_t flags)
|
|
||||||
{
|
|
||||||
snprintf(out, out_len, "%s%s%s%s%s",
|
|
||||||
flags & CEMU_STATUS_F_RESET_ACTIVE ? "RESET " : "",
|
|
||||||
flags & CEMU_STATUS_F_VCC_PRESENT ? "VCC " : "",
|
|
||||||
flags & CEMU_STATUS_F_CLK_ACTIVE ? "CLK " : "",
|
|
||||||
flags & CEMU_STATUS_F_CARD_INSERT ? "CARD_PRES " : "",
|
|
||||||
flags & CEMU_STATUS_F_RCEMU_ACTIVE ? "RCEMU " : "");
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t last_flags = 0;
|
|
||||||
|
|
||||||
static void update_flags(struct osmo_st2_cardem_inst *ci, uint32_t flags)
|
|
||||||
{
|
|
||||||
struct osim_card_hdl *card = ci->chan->card;
|
|
||||||
|
|
||||||
if ((flags & CEMU_STATUS_F_VCC_PRESENT) && (flags & CEMU_STATUS_F_CLK_ACTIVE) &&
|
|
||||||
!(flags & CEMU_STATUS_F_RESET_ACTIVE)) {
|
|
||||||
if (last_flags & CEMU_STATUS_F_RESET_ACTIVE) {
|
|
||||||
/* a reset has just ended, forward it to the real card */
|
|
||||||
bool cold_reset = true;
|
|
||||||
if (last_flags & CEMU_STATUS_F_VCC_PRESENT)
|
|
||||||
cold_reset = false;
|
|
||||||
LOGCI(ci, LOGL_NOTICE, "%s Resetting card in reader...\n",
|
|
||||||
cold_reset ? "Cold" : "Warm");
|
|
||||||
osim_card_reset(card, cold_reset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
last_flags = flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* Incoming Messages
|
* Incoming Messages
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
@@ -104,15 +88,12 @@ static void update_flags(struct osmo_st2_cardem_inst *ci, uint32_t flags)
|
|||||||
/*! \brief Process a STATUS message from the SIMtrace2 */
|
/*! \brief Process a STATUS message from the SIMtrace2 */
|
||||||
static int process_do_status(struct osmo_st2_cardem_inst *ci, uint8_t *buf, int len)
|
static int process_do_status(struct osmo_st2_cardem_inst *ci, uint8_t *buf, int len)
|
||||||
{
|
{
|
||||||
struct cardemu_usb_msg_status *status = (struct cardemu_usb_msg_status *) buf;
|
struct cardemu_usb_msg_status *status;
|
||||||
char fbuf[80];
|
status = (struct cardemu_usb_msg_status *) buf;
|
||||||
|
|
||||||
cemu_flags2str(fbuf, sizeof(fbuf), status->flags);
|
printf("=> STATUS: flags=0x%x, F=%u, D=%u, WI=%u WT=%u\n",
|
||||||
printf("=> STATUS: flags=0x%x, fi=%u, di=%u, wi=%u wtime=%u (%s)\n",
|
status->flags, status->f, status->d, status->wi,
|
||||||
status->flags, status->fi, status->di, status->wi,
|
status->wt);
|
||||||
status->waiting_time, fbuf);
|
|
||||||
|
|
||||||
update_flags(ci, status->flags);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -197,9 +178,6 @@ static int process_usb_msg(struct osmo_st2_cardem_inst *ci, uint8_t *buf, int le
|
|||||||
case SIMTRACE_MSGT_DO_CEMU_RX_DATA:
|
case SIMTRACE_MSGT_DO_CEMU_RX_DATA:
|
||||||
rc = process_do_rx_da(ci, buf, len);
|
rc = process_do_rx_da(ci, buf, len);
|
||||||
break;
|
break;
|
||||||
case SIMTRACE_MSGT_BD_CEMU_CONFIG:
|
|
||||||
/* firmware confirms configuration change; ignore */
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
printf("unknown simtrace msg type 0x%02x\n", sh->msg_type);
|
printf("unknown simtrace msg type 0x%02x\n", sh->msg_type);
|
||||||
rc = -1;
|
rc = -1;
|
||||||
@@ -209,161 +187,20 @@ static int process_usb_msg(struct osmo_st2_cardem_inst *ci, uint8_t *buf, int le
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \brief Process a STATUS message on IRQ endpoint from the SIMtrace2 */
|
|
||||||
static int process_irq_status(struct osmo_st2_cardem_inst *ci, const uint8_t *buf, int len)
|
|
||||||
{
|
|
||||||
const struct cardemu_usb_msg_status *status = (struct cardemu_usb_msg_status *) buf;
|
|
||||||
char fbuf[80];
|
|
||||||
|
|
||||||
cemu_flags2str(fbuf, sizeof(fbuf), status->flags);
|
|
||||||
LOGCI(ci, LOGL_INFO, "SIMtrace IRQ STATUS: flags=0x%x, fi=%u, di=%u, wi=%u wtime=%u (%s)\n",
|
|
||||||
status->flags, status->fi, status->di, status->wi,
|
|
||||||
status->waiting_time, fbuf);
|
|
||||||
|
|
||||||
update_flags(ci, status->flags);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int process_usb_msg_irq(struct osmo_st2_cardem_inst *ci, const uint8_t *buf, unsigned int len)
|
|
||||||
{
|
|
||||||
struct simtrace_msg_hdr *sh = (struct simtrace_msg_hdr *)buf;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
LOGCI(ci, LOGL_INFO, "SIMtrace IRQ %s\n", osmo_hexdump(buf, len));
|
|
||||||
|
|
||||||
buf += sizeof(*sh);
|
|
||||||
|
|
||||||
switch (sh->msg_type) {
|
|
||||||
case SIMTRACE_MSGT_BD_CEMU_STATUS:
|
|
||||||
rc = process_irq_status(ci, buf, len);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LOGCI(ci, LOGL_ERROR, "unknown simtrace msg type 0x%02x\n", sh->msg_type);
|
|
||||||
rc = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void usb_in_xfer_cb(struct libusb_transfer *xfer)
|
|
||||||
{
|
|
||||||
struct osmo_st2_cardem_inst *ci = xfer->user_data;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
switch (xfer->status) {
|
|
||||||
case LIBUSB_TRANSFER_COMPLETED:
|
|
||||||
/* hand the message up the stack */
|
|
||||||
process_usb_msg(ci, xfer->buffer, xfer->actual_length);
|
|
||||||
break;
|
|
||||||
case LIBUSB_TRANSFER_NO_DEVICE:
|
|
||||||
LOGCI(ci, LOGL_FATAL, "USB device disappeared\n");
|
|
||||||
exit(1);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LOGCI(ci, LOGL_FATAL, "USB IN transfer failed, status=%u\n", xfer->status);
|
|
||||||
exit(1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* re-submit the IN transfer */
|
|
||||||
rc = libusb_submit_transfer(xfer);
|
|
||||||
OSMO_ASSERT(rc == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void allocate_and_submit_in(struct osmo_st2_cardem_inst *ci)
|
|
||||||
{
|
|
||||||
struct osmo_st2_transport *transp = ci->slot->transp;
|
|
||||||
struct libusb_transfer *xfer;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
xfer = libusb_alloc_transfer(0);
|
|
||||||
OSMO_ASSERT(xfer);
|
|
||||||
xfer->dev_handle = transp->usb_devh;
|
|
||||||
xfer->flags = 0;
|
|
||||||
xfer->type = LIBUSB_TRANSFER_TYPE_BULK;
|
|
||||||
xfer->endpoint = transp->usb_ep.in;
|
|
||||||
xfer->timeout = 0;
|
|
||||||
xfer->user_data = ci;
|
|
||||||
xfer->length = 16*256;
|
|
||||||
|
|
||||||
xfer->buffer = libusb_dev_mem_alloc(xfer->dev_handle, xfer->length);
|
|
||||||
OSMO_ASSERT(xfer->buffer);
|
|
||||||
xfer->callback = usb_in_xfer_cb;
|
|
||||||
|
|
||||||
/* submit the IN transfer */
|
|
||||||
rc = libusb_submit_transfer(xfer);
|
|
||||||
OSMO_ASSERT(rc == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void usb_irq_xfer_cb(struct libusb_transfer *xfer)
|
|
||||||
{
|
|
||||||
struct osmo_st2_cardem_inst *ci = xfer->user_data;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
switch (xfer->status) {
|
|
||||||
case LIBUSB_TRANSFER_COMPLETED:
|
|
||||||
process_usb_msg_irq(ci, xfer->buffer, xfer->actual_length);
|
|
||||||
break;
|
|
||||||
case LIBUSB_TRANSFER_NO_DEVICE:
|
|
||||||
LOGCI(ci, LOGL_FATAL, "USB device disappeared\n");
|
|
||||||
exit(1);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LOGCI(ci, LOGL_FATAL, "USB IN transfer failed, status=%u\n", xfer->status);
|
|
||||||
exit(1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* re-submit the IN transfer */
|
|
||||||
rc = libusb_submit_transfer(xfer);
|
|
||||||
OSMO_ASSERT(rc == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void allocate_and_submit_irq(struct osmo_st2_cardem_inst *ci)
|
|
||||||
{
|
|
||||||
struct osmo_st2_transport *transp = ci->slot->transp;
|
|
||||||
struct libusb_transfer *xfer;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
xfer = libusb_alloc_transfer(0);
|
|
||||||
OSMO_ASSERT(xfer);
|
|
||||||
xfer->dev_handle = transp->usb_devh;
|
|
||||||
xfer->flags = 0;
|
|
||||||
xfer->type = LIBUSB_TRANSFER_TYPE_INTERRUPT;
|
|
||||||
xfer->endpoint = transp->usb_ep.irq_in;
|
|
||||||
xfer->timeout = 0;
|
|
||||||
xfer->user_data = ci;
|
|
||||||
xfer->length = 64;
|
|
||||||
|
|
||||||
xfer->buffer = libusb_dev_mem_alloc(xfer->dev_handle, xfer->length);
|
|
||||||
OSMO_ASSERT(xfer->buffer);
|
|
||||||
xfer->callback = usb_irq_xfer_cb;
|
|
||||||
|
|
||||||
/* submit the IN transfer */
|
|
||||||
rc = libusb_submit_transfer(xfer);
|
|
||||||
OSMO_ASSERT(rc == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void print_welcome(void)
|
static void print_welcome(void)
|
||||||
{
|
{
|
||||||
printf("simtrace2-cardem-pcsc - Using PC/SC reader as SIM\n"
|
printf("simtrace2-remsim - Remote SIM card forwarding\n"
|
||||||
"(C) 2010-2020, Harald Welte <laforge@gnumonks.org>\n"
|
"(C) 2010-2017, Harald Welte <laforge@gnumonks.org>\n"
|
||||||
"(C) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>\n\n");
|
"(C) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_help(void)
|
static void print_help(void)
|
||||||
{
|
{
|
||||||
printf( "\t-h\t--help\n"
|
printf( "\t-r\t--remote-udp-host HOST\n"
|
||||||
|
"\t-p\t--remote-udp-port PORT\n"
|
||||||
|
"\t-h\t--help\n"
|
||||||
"\t-i\t--gsmtap-ip\tA.B.C.D\n"
|
"\t-i\t--gsmtap-ip\tA.B.C.D\n"
|
||||||
"\t-a\t--skip-atr\n"
|
"\t-a\t--skip-atr\n"
|
||||||
"\t-t\t--set-atr\tATR-STRING in HEX\n"
|
|
||||||
"\t-k\t--keep-running\n"
|
"\t-k\t--keep-running\n"
|
||||||
"\t-n\t--pcsc-reader-num\n"
|
"\t-n\t--pcsc-reader-num\n"
|
||||||
"\t-V\t--usb-vendor\tVENDOR_ID\n"
|
"\t-V\t--usb-vendor\tVENDOR_ID\n"
|
||||||
@@ -378,9 +215,10 @@ static void print_help(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct option opts[] = {
|
static const struct option opts[] = {
|
||||||
|
{ "remote-udp-host", 1, 0, 'r' },
|
||||||
|
{ "remote-udp-port", 1, 0, 'p' },
|
||||||
{ "gsmtap-ip", 1, 0, 'i' },
|
{ "gsmtap-ip", 1, 0, 'i' },
|
||||||
{ "skip-atr", 0, 0, 'a' },
|
{ "skip-atr", 0, 0, 'a' },
|
||||||
{ "set-atr", 1, 0, 't' },
|
|
||||||
{ "help", 0, 0, 'h' },
|
{ "help", 0, 0, 'h' },
|
||||||
{ "keep-running", 0, 0, 'k' },
|
{ "keep-running", 0, 0, 'k' },
|
||||||
{ "pcsc-reader-num", 1, 0, 'n' },
|
{ "pcsc-reader-num", 1, 0, 'n' },
|
||||||
@@ -396,9 +234,40 @@ static const struct option opts[] = {
|
|||||||
|
|
||||||
static void run_mainloop(struct osmo_st2_cardem_inst *ci)
|
static void run_mainloop(struct osmo_st2_cardem_inst *ci)
|
||||||
{
|
{
|
||||||
|
struct osmo_st2_transport *transp = ci->slot->transp;
|
||||||
|
unsigned int msg_count, byte_count = 0;
|
||||||
|
uint8_t buf[16*265];
|
||||||
|
int xfer_len;
|
||||||
|
int rc;
|
||||||
|
|
||||||
printf("Entering main loop\n");
|
printf("Entering main loop\n");
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
osmo_select_main(0);
|
/* read data from SIMtrace2 device (local or via USB) */
|
||||||
|
if (transp->udp_fd < 0) {
|
||||||
|
rc = libusb_bulk_transfer(transp->usb_devh, transp->usb_ep.in,
|
||||||
|
buf, sizeof(buf), &xfer_len, 100);
|
||||||
|
if (rc < 0 && rc != LIBUSB_ERROR_TIMEOUT &&
|
||||||
|
rc != LIBUSB_ERROR_INTERRUPTED &&
|
||||||
|
rc != LIBUSB_ERROR_IO) {
|
||||||
|
fprintf(stderr, "BULK IN transfer error; rc=%d\n", rc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rc = read(transp->udp_fd, buf, sizeof(buf));
|
||||||
|
if (rc <= 0) {
|
||||||
|
fprintf(stderr, "shor read from UDP\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
xfer_len = rc;
|
||||||
|
}
|
||||||
|
/* dispatch any incoming data */
|
||||||
|
if (xfer_len > 0) {
|
||||||
|
printf("URB: %s\n", osmo_hexdump(buf, xfer_len));
|
||||||
|
process_usb_msg(ci, buf, xfer_len);
|
||||||
|
msg_count++;
|
||||||
|
byte_count += xfer_len;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -427,8 +296,6 @@ static void signal_handler(int signal)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct log_info log_info = {};
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
struct osmo_st2_transport *transp = ci->slot->transp;
|
struct osmo_st2_transport *transp = ci->slot->transp;
|
||||||
@@ -436,34 +303,31 @@ int main(int argc, char **argv)
|
|||||||
int rc;
|
int rc;
|
||||||
int c, ret = 1;
|
int c, ret = 1;
|
||||||
int skip_atr = 0;
|
int skip_atr = 0;
|
||||||
char *atr = NULL;
|
|
||||||
uint8_t override_atr[OSIM_MAX_ATR_LEN];
|
|
||||||
int override_atr_len = 0;
|
|
||||||
int keep_running = 0;
|
int keep_running = 0;
|
||||||
|
int remote_udp_port = 52342;
|
||||||
int if_num = 0, vendor_id = -1, product_id = -1;
|
int if_num = 0, vendor_id = -1, product_id = -1;
|
||||||
int config_id = -1, altsetting = 0, addr = -1;
|
int config_id = -1, altsetting = 0, addr = -1;
|
||||||
int reader_num = 0;
|
int reader_num = 0;
|
||||||
|
char *remote_udp_host = NULL;
|
||||||
char *path = NULL;
|
char *path = NULL;
|
||||||
struct osim_reader_hdl *reader;
|
struct osim_reader_hdl *reader;
|
||||||
struct osim_card_hdl *card;
|
struct osim_card_hdl *card;
|
||||||
|
|
||||||
print_welcome();
|
print_welcome();
|
||||||
|
|
||||||
rc = osmo_libusb_init(NULL);
|
|
||||||
if (rc < 0) {
|
|
||||||
fprintf(stderr, "libusb initialization failed\n");
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
osmo_init_logging2(NULL, &log_info);
|
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
|
|
||||||
c = getopt_long(argc, argv, "hi:V:P:C:I:S:A:H:akn:t:", opts, &option_index);
|
c = getopt_long(argc, argv, "r:p:hi:V:P:C:I:S:A:H:akn:", opts, &option_index);
|
||||||
if (c == -1)
|
if (c == -1)
|
||||||
break;
|
break;
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
case 'r':
|
||||||
|
remote_udp_host = optarg;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
remote_udp_port = atoi(optarg);
|
||||||
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
print_help();
|
print_help();
|
||||||
exit(0);
|
exit(0);
|
||||||
@@ -474,9 +338,6 @@ int main(int argc, char **argv)
|
|||||||
case 'a':
|
case 'a':
|
||||||
skip_atr = 1;
|
skip_atr = 1;
|
||||||
break;
|
break;
|
||||||
case 't':
|
|
||||||
atr = optarg;
|
|
||||||
break;
|
|
||||||
case 'k':
|
case 'k':
|
||||||
keep_running = 1;
|
keep_running = 1;
|
||||||
break;
|
break;
|
||||||
@@ -507,27 +368,30 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (atr) {
|
if (!remote_udp_host && (vendor_id < 0 || product_id < 0)) {
|
||||||
override_atr_len = osmo_hexparse(atr, override_atr, sizeof(override_atr));
|
|
||||||
if (override_atr_len < 2) {
|
|
||||||
fprintf(stderr, "Invalid ATR - please omit a leading 0x and only use valid hex "
|
|
||||||
"digits and whitespace. ATRs need to be between 2 and 33 bytes long.\n");
|
|
||||||
goto do_exit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vendor_id < 0 || product_id < 0) {
|
|
||||||
fprintf(stderr, "You have to specify the vendor and product ID\n");
|
fprintf(stderr, "You have to specify the vendor and product ID\n");
|
||||||
goto do_exit;
|
goto do_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
transp->udp_fd = -1;
|
||||||
|
|
||||||
ci->card_prof = &osim_uicc_sim_cic_profile;
|
ci->card_prof = &osim_uicc_sim_cic_profile;
|
||||||
|
|
||||||
|
if (!remote_udp_host) {
|
||||||
rc = libusb_init(NULL);
|
rc = libusb_init(NULL);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
fprintf(stderr, "libusb initialization failed\n");
|
fprintf(stderr, "libusb initialization failed\n");
|
||||||
goto do_exit;
|
goto do_exit;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
transp->udp_fd = osmo_sock_init(AF_INET, SOCK_DGRAM, IPPROTO_UDP,
|
||||||
|
remote_udp_host, remote_udp_port+if_num,
|
||||||
|
OSMO_SOCK_F_CONNECT);
|
||||||
|
if (transp->udp_fd < 0) {
|
||||||
|
fprintf(stderr, "error binding UDP port\n");
|
||||||
|
goto do_exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rc = osmo_st2_gsmtap_init(gsmtap_host);
|
rc = osmo_st2_gsmtap_init(gsmtap_host);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
@@ -556,6 +420,7 @@ int main(int argc, char **argv)
|
|||||||
signal(SIGINT, &signal_handler);
|
signal(SIGINT, &signal_handler);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
if (transp->udp_fd < 0) {
|
||||||
struct usb_interface_match _ifm, *ifm = &_ifm;
|
struct usb_interface_match _ifm, *ifm = &_ifm;
|
||||||
ifm->vendor = vendor_id;
|
ifm->vendor = vendor_id;
|
||||||
ifm->product = product_id;
|
ifm->product = product_id;
|
||||||
@@ -565,33 +430,25 @@ int main(int argc, char **argv)
|
|||||||
ifm->addr = addr;
|
ifm->addr = addr;
|
||||||
if (path)
|
if (path)
|
||||||
osmo_strlcpy(ifm->path, path, sizeof(ifm->path));
|
osmo_strlcpy(ifm->path, path, sizeof(ifm->path));
|
||||||
transp->udp_fd = -1;
|
|
||||||
transp->usb_async = true;
|
|
||||||
transp->usb_devh = osmo_libusb_open_claim_interface(NULL, NULL, ifm);
|
transp->usb_devh = osmo_libusb_open_claim_interface(NULL, NULL, ifm);
|
||||||
if (!transp->usb_devh) {
|
if (!transp->usb_devh) {
|
||||||
fprintf(stderr, "can't open USB device\n");
|
fprintf(stderr, "can't open USB device\n");
|
||||||
goto close;
|
goto close_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = libusb_claim_interface(transp->usb_devh, if_num);
|
rc = libusb_claim_interface(transp->usb_devh, if_num);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
fprintf(stderr, "can't claim interface %d; rc=%d\n", if_num, rc);
|
fprintf(stderr, "can't claim interface %d; rc=%d\n", if_num, rc);
|
||||||
goto close;
|
goto close_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = osmo_libusb_get_ep_addrs(transp->usb_devh, if_num, &transp->usb_ep.out,
|
rc = osmo_libusb_get_ep_addrs(transp->usb_devh, if_num, &transp->usb_ep.out,
|
||||||
&transp->usb_ep.in, &transp->usb_ep.irq_in);
|
&transp->usb_ep.in, &transp->usb_ep.irq_in);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
fprintf(stderr, "can't obtain EP addrs; rc=%d\n", rc);
|
fprintf(stderr, "can't obtain EP addrs; rc=%d\n", rc);
|
||||||
goto close;
|
goto close_exit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
allocate_and_submit_irq(ci);
|
|
||||||
for (int i = 0; i < 4; i++)
|
|
||||||
allocate_and_submit_in(ci);
|
|
||||||
|
|
||||||
/* request firmware to generate STATUS on IRQ endpoint */
|
|
||||||
osmo_st2_cardem_request_config(ci, CEMU_FEAT_F_STATUS_IRQ);
|
|
||||||
|
|
||||||
/* simulate card-insert to modem (owhw, not qmod) */
|
/* simulate card-insert to modem (owhw, not qmod) */
|
||||||
osmo_st2_cardem_request_card_insert(ci, true);
|
osmo_st2_cardem_request_card_insert(ci, true);
|
||||||
@@ -600,15 +457,8 @@ int main(int argc, char **argv)
|
|||||||
osmo_st2_modem_sim_select_remote(ci->slot);
|
osmo_st2_modem_sim_select_remote(ci->slot);
|
||||||
|
|
||||||
if (!skip_atr) {
|
if (!skip_atr) {
|
||||||
/* set the ATR */
|
atr_update_csum(real_atr, sizeof(real_atr));
|
||||||
if (override_atr_len) {
|
osmo_st2_cardem_request_set_atr(ci, real_atr, sizeof(real_atr));
|
||||||
/* user has specified an override-ATR */
|
|
||||||
atr_update_csum(override_atr, override_atr_len);
|
|
||||||
osmo_st2_cardem_request_set_atr(ci, override_atr, override_atr_len);
|
|
||||||
} else {
|
|
||||||
/* use the real ATR of the card */
|
|
||||||
osmo_st2_cardem_request_set_atr(ci, card->atr, card->atr_len);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* select remote (forwarded) SIM */
|
/* select remote (forwarded) SIM */
|
||||||
@@ -617,21 +467,16 @@ int main(int argc, char **argv)
|
|||||||
run_mainloop(ci);
|
run_mainloop(ci);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
|
if (transp->udp_fd < 0)
|
||||||
libusb_release_interface(transp->usb_devh, 0);
|
libusb_release_interface(transp->usb_devh, 0);
|
||||||
|
close_exit:
|
||||||
close:
|
if (transp->usb_devh)
|
||||||
if (transp->usb_devh) {
|
|
||||||
libusb_close(transp->usb_devh);
|
libusb_close(transp->usb_devh);
|
||||||
transp->usb_devh = NULL;
|
|
||||||
}
|
|
||||||
if (keep_running)
|
if (keep_running)
|
||||||
sleep(1);
|
sleep(1);
|
||||||
} while (keep_running);
|
} while (keep_running);
|
||||||
|
|
||||||
close_exit:
|
if (transp->udp_fd < 0)
|
||||||
if (transp->usb_devh)
|
|
||||||
libusb_close(transp->usb_devh);
|
|
||||||
|
|
||||||
libusb_exit(NULL);
|
libusb_exit(NULL);
|
||||||
do_exit:
|
do_exit:
|
||||||
return ret;
|
return ret;
|
||||||
@@ -1,338 +0,0 @@
|
|||||||
/* simtrace2-tool - main program for the host PC to provide a remote SIM
|
|
||||||
* using the SIMtrace 2 firmware in card emulation mode
|
|
||||||
*
|
|
||||||
* (C) 2019 by Harald Welte <hwelte@hmw-consulting.de>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* as published by the Free Software Foundation; either version 2
|
|
||||||
* of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#define _GNU_SOURCE
|
|
||||||
#include <getopt.h>
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
#include <libusb.h>
|
|
||||||
|
|
||||||
#include <osmocom/usb/libusb.h>
|
|
||||||
#include <osmocom/simtrace2/simtrace2_api.h>
|
|
||||||
#include <osmocom/simtrace2/simtrace_prot.h>
|
|
||||||
#include <osmocom/simtrace2/gsmtap.h>
|
|
||||||
|
|
||||||
#include <osmocom/core/utils.h>
|
|
||||||
#include <osmocom/core/msgb.h>
|
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* Incoming Messages
|
|
||||||
***********************************************************************/
|
|
||||||
|
|
||||||
static void print_welcome(void)
|
|
||||||
{
|
|
||||||
printf("simtrace2-tool\n"
|
|
||||||
"(C) 2019 Harald Welte <laforge@gnumonks.org>\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void print_help(void)
|
|
||||||
{
|
|
||||||
printf( "simtrace2-tool [OPTIONS] COMMAND\n\n");
|
|
||||||
printf( "Options:\n"
|
|
||||||
"\t-h\t--help\n"
|
|
||||||
"\t-V\t--usb-vendor\tVENDOR_ID\n"
|
|
||||||
"\t-P\t--usb-product\tPRODUCT_ID\n"
|
|
||||||
"\t-C\t--usb-config\tCONFIG_ID\n"
|
|
||||||
"\t-I\t--usb-interface\tINTERFACE_ID\n"
|
|
||||||
"\t-S\t--usb-altsetting ALTSETTING_ID\n"
|
|
||||||
"\t-A\t--usb-address\tADDRESS\n"
|
|
||||||
"\t-H\t--usb-path\tPATH\n"
|
|
||||||
"\n"
|
|
||||||
);
|
|
||||||
printf( "Commands:\n"
|
|
||||||
"\tmodem reset (enable|disable|cycle)\n"
|
|
||||||
"\tmodem sim-switch (local|remote)\n"
|
|
||||||
"\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct option opts[] = {
|
|
||||||
{ "help", 0, 0, 'h' },
|
|
||||||
{ "usb-vendor", 1, 0, 'V' },
|
|
||||||
{ "usb-product", 1, 0, 'P' },
|
|
||||||
{ "usb-config", 1, 0, 'C' },
|
|
||||||
{ "usb-interface", 1, 0, 'I' },
|
|
||||||
{ "usb-altsetting", 1, 0, 'S' },
|
|
||||||
{ "usb-address", 1, 0, 'A' },
|
|
||||||
{ "usb-path", 1, 0, 'H' },
|
|
||||||
{ NULL, 0, 0, 0 }
|
|
||||||
};
|
|
||||||
|
|
||||||
static void run_mainloop(struct osmo_st2_cardem_inst *ci)
|
|
||||||
{
|
|
||||||
struct osmo_st2_transport *transp = ci->slot->transp;
|
|
||||||
uint8_t buf[16*265];
|
|
||||||
int xfer_len;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
/* read data from SIMtrace2 device */
|
|
||||||
rc = libusb_bulk_transfer(transp->usb_devh, transp->usb_ep.in,
|
|
||||||
buf, sizeof(buf), &xfer_len, 100);
|
|
||||||
if (rc < 0 && rc != LIBUSB_ERROR_TIMEOUT &&
|
|
||||||
rc != LIBUSB_ERROR_INTERRUPTED &&
|
|
||||||
rc != LIBUSB_ERROR_IO) {
|
|
||||||
fprintf(stderr, "BULK IN transfer error; rc=%d\n", rc);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* break the loop if no new messages arrive within 100ms */
|
|
||||||
if (rc == LIBUSB_ERROR_TIMEOUT)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct osmo_st2_transport _transp;
|
|
||||||
|
|
||||||
static struct osmo_st2_slot _slot = {
|
|
||||||
.transp = &_transp,
|
|
||||||
.slot_nr = 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct osmo_st2_cardem_inst _ci = {
|
|
||||||
.slot = &_slot,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct osmo_st2_cardem_inst *ci = &_ci;
|
|
||||||
|
|
||||||
/* perform a modem reset */
|
|
||||||
static int do_modem_reset(int argc, char **argv)
|
|
||||||
{
|
|
||||||
char *command;
|
|
||||||
if (argc < 1)
|
|
||||||
command = "cycle";
|
|
||||||
else {
|
|
||||||
command = argv[0];
|
|
||||||
argc--;
|
|
||||||
argv++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!strcmp(command, "enable")) {
|
|
||||||
printf("Activating Modem RESET\n");
|
|
||||||
return osmo_st2_modem_reset_active(ci->slot);
|
|
||||||
} else if (!strcmp(command, "disable")) {
|
|
||||||
printf("Deactivating Modem RESET\n");
|
|
||||||
return osmo_st2_modem_reset_inactive(ci->slot);
|
|
||||||
} else if (!strcmp(command, "cycle")) {
|
|
||||||
printf("Pulsing Modem RESET (1s)\n");
|
|
||||||
return osmo_st2_modem_reset_pulse(ci->slot, 1000);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Unsupported modem reset command: '%s'\n", command);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* switch between local and remote (emulated) SIM */
|
|
||||||
static int do_modem_sim_switch(int argc, char **argv)
|
|
||||||
{
|
|
||||||
char *command;
|
|
||||||
if (argc < 1)
|
|
||||||
return -EINVAL;
|
|
||||||
command = argv[0];
|
|
||||||
argc--;
|
|
||||||
argv++;
|
|
||||||
|
|
||||||
if (!strcmp(command, "local")) {
|
|
||||||
printf("Setting SIM=LOCAL; Modem reset recommended\n");
|
|
||||||
return osmo_st2_modem_sim_select_local(ci->slot);
|
|
||||||
} else if (!strcmp(command, "remote")) {
|
|
||||||
printf("Setting SIM=REMOTE; Modem reset recommended\n");
|
|
||||||
return osmo_st2_modem_sim_select_remote(ci->slot);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Unsupported modem sim-switch command: '%s'\n", command);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int do_subsys_modem(int argc, char **argv)
|
|
||||||
{
|
|
||||||
char *command;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
if (argc < 1)
|
|
||||||
return -EINVAL;
|
|
||||||
command = argv[0];
|
|
||||||
argc--;
|
|
||||||
argv++;
|
|
||||||
|
|
||||||
if (!strcmp(command, "reset")) {
|
|
||||||
rc = do_modem_reset(argc, argv);
|
|
||||||
} else if (!strcmp(command, "sim-switch")) {
|
|
||||||
rc = do_modem_sim_switch(argc, argv);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Unsupported command for subsystem modem: '%s'\n", command);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int do_command(int argc, char **argv)
|
|
||||||
{
|
|
||||||
char *subsys;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
if (argc < 1)
|
|
||||||
return -EINVAL;
|
|
||||||
subsys = argv[0];
|
|
||||||
argc--;
|
|
||||||
argv++;
|
|
||||||
|
|
||||||
if (!strcmp(subsys, "modem"))
|
|
||||||
rc = do_subsys_modem(argc, argv);
|
|
||||||
else {
|
|
||||||
fprintf(stderr, "Unsupported subsystem '%s'\n", subsys);
|
|
||||||
rc = -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
struct osmo_st2_transport *transp = ci->slot->transp;
|
|
||||||
int rc;
|
|
||||||
int c, ret = 1;
|
|
||||||
int if_num = 0, vendor_id = -1, product_id = -1;
|
|
||||||
int config_id = -1, altsetting = 0, addr = -1;
|
|
||||||
char *path = NULL;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
int option_index = 0;
|
|
||||||
|
|
||||||
c = getopt_long(argc, argv, "hV:P:C:I:S:A:H:", opts, &option_index);
|
|
||||||
if (c == -1)
|
|
||||||
break;
|
|
||||||
switch (c) {
|
|
||||||
case 'h':
|
|
||||||
print_help();
|
|
||||||
exit(0);
|
|
||||||
break;
|
|
||||||
case 'V':
|
|
||||||
vendor_id = strtol(optarg, NULL, 16);
|
|
||||||
break;
|
|
||||||
case 'P':
|
|
||||||
product_id = strtol(optarg, NULL, 16);
|
|
||||||
break;
|
|
||||||
case 'C':
|
|
||||||
config_id = atoi(optarg);
|
|
||||||
break;
|
|
||||||
case 'I':
|
|
||||||
if_num = atoi(optarg);
|
|
||||||
break;
|
|
||||||
case 'S':
|
|
||||||
altsetting = atoi(optarg);
|
|
||||||
break;
|
|
||||||
case 'A':
|
|
||||||
addr = atoi(optarg);
|
|
||||||
break;
|
|
||||||
case 'H':
|
|
||||||
path = optarg;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((vendor_id < 0 || product_id < 0)) {
|
|
||||||
fprintf(stderr, "You have to specify the vendor and product ID\n");
|
|
||||||
goto do_exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
transp->udp_fd = -1;
|
|
||||||
|
|
||||||
rc = libusb_init(NULL);
|
|
||||||
if (rc < 0) {
|
|
||||||
fprintf(stderr, "libusb initialization failed\n");
|
|
||||||
goto do_exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
print_welcome();
|
|
||||||
|
|
||||||
do {
|
|
||||||
if (transp->udp_fd < 0) {
|
|
||||||
struct usb_interface_match _ifm, *ifm = &_ifm;
|
|
||||||
ifm->vendor = vendor_id;
|
|
||||||
ifm->product = product_id;
|
|
||||||
ifm->configuration = config_id;
|
|
||||||
ifm->interface = if_num;
|
|
||||||
ifm->altsetting = altsetting;
|
|
||||||
ifm->addr = addr;
|
|
||||||
if (path)
|
|
||||||
osmo_strlcpy(ifm->path, path, sizeof(ifm->path));
|
|
||||||
transp->usb_devh = osmo_libusb_open_claim_interface(NULL, NULL, ifm);
|
|
||||||
if (!transp->usb_devh) {
|
|
||||||
fprintf(stderr, "can't open USB device\n");
|
|
||||||
goto close_exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = libusb_claim_interface(transp->usb_devh, if_num);
|
|
||||||
if (rc < 0) {
|
|
||||||
fprintf(stderr, "can't claim interface %d; rc=%d\n", if_num, rc);
|
|
||||||
goto close_exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = osmo_libusb_get_ep_addrs(transp->usb_devh, if_num, &transp->usb_ep.out,
|
|
||||||
&transp->usb_ep.in, &transp->usb_ep.irq_in);
|
|
||||||
if (rc < 0) {
|
|
||||||
fprintf(stderr, "can't obtain EP addrs; rc=%d\n", rc);
|
|
||||||
goto close_exit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (argc - optind <= 0) {
|
|
||||||
fprintf(stderr, "You have to specify a command to execute\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = do_command(argc-optind, argv+optind);
|
|
||||||
switch (rc) {
|
|
||||||
case 0:
|
|
||||||
break;
|
|
||||||
case -EINVAL:
|
|
||||||
fprintf(stderr, "Error: Invalid command/syntax\n");
|
|
||||||
exit(1);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fprintf(stderr, "Error executing command: %d\n", rc);
|
|
||||||
exit(1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
run_mainloop(ci);
|
|
||||||
ret = 0;
|
|
||||||
|
|
||||||
libusb_release_interface(transp->usb_devh, 0);
|
|
||||||
close_exit:
|
|
||||||
if (transp->usb_devh)
|
|
||||||
libusb_close(transp->usb_devh);
|
|
||||||
} while (0);
|
|
||||||
|
|
||||||
libusb_exit(NULL);
|
|
||||||
do_exit:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
@@ -25,7 +25,13 @@
|
|||||||
|
|
||||||
#include <osmocom/usb/libusb.h>
|
#include <osmocom/usb/libusb.h>
|
||||||
#include <osmocom/simtrace2/simtrace_usb.h>
|
#include <osmocom/simtrace2/simtrace_usb.h>
|
||||||
#include <osmocom/simtrace2/usb_util.h>
|
|
||||||
|
static const struct dev_id compatible_dev_ids[] = {
|
||||||
|
{ USB_VENDOR_OPENMOKO, USB_PRODUCT_OWHW_SAM3 },
|
||||||
|
{ USB_VENDOR_OPENMOKO, USB_PRODUCT_QMOD_SAM3 },
|
||||||
|
{ USB_VENDOR_OPENMOKO, USB_PRODUCT_SIMTRACE2 },
|
||||||
|
{ 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
static int find_devices(void)
|
static int find_devices(void)
|
||||||
{
|
{
|
||||||
@@ -33,7 +39,7 @@ static int find_devices(void)
|
|||||||
int rc, i, num_interfaces;
|
int rc, i, num_interfaces;
|
||||||
|
|
||||||
/* scan for USB devices matching SIMtrace USB ID with proprietary class */
|
/* scan for USB devices matching SIMtrace USB ID with proprietary class */
|
||||||
rc = osmo_libusb_find_matching_interfaces(NULL, osmo_st2_compatible_dev_ids,
|
rc = osmo_libusb_find_matching_interfaces(NULL, compatible_dev_ids,
|
||||||
USB_CLASS_PROPRIETARY, -1, -1, ifm, ARRAY_SIZE(ifm));
|
USB_CLASS_PROPRIETARY, -1, -1, ifm, ARRAY_SIZE(ifm));
|
||||||
printf("USB matches: %d\n", rc);
|
printf("USB matches: %d\n", rc);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
|
|||||||
285
host/src/usb2udp.c
Normal file
285
host/src/usb2udp.c
Normal file
@@ -0,0 +1,285 @@
|
|||||||
|
/* simtrace - main program for the host PC
|
||||||
|
*
|
||||||
|
* (C) 2010-2016 by Harald Welte <hwelte@hmw-consulting.de>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <time.h>
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <poll.h>
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include <libusb.h>
|
||||||
|
|
||||||
|
#include <osmocom/usb/libusb.h>
|
||||||
|
#include <osmocom/simtrace2/simtrace_usb.h>
|
||||||
|
#include <osmocom/simtrace2/simtrace_prot.h>
|
||||||
|
|
||||||
|
#include <osmocom/core/utils.h>
|
||||||
|
#include <osmocom/core/socket.h>
|
||||||
|
#include <osmocom/core/select.h>
|
||||||
|
|
||||||
|
struct libusb_device_handle *g_devh;
|
||||||
|
static struct sockaddr_in g_sa_remote;
|
||||||
|
static struct osmo_fd g_udp_ofd;
|
||||||
|
|
||||||
|
static void print_welcome(void)
|
||||||
|
{
|
||||||
|
printf("usb2udp - UDP/IP forwarding of SIMtrace card emulation\n"
|
||||||
|
"(C) 2016 by Harald Welte <laforge@gnumonks.org>\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_help(void)
|
||||||
|
{
|
||||||
|
printf( "\t-h\t--help\n"
|
||||||
|
"\t-i\t--interface <0-255>\n"
|
||||||
|
"\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ep_buf {
|
||||||
|
uint8_t ep;
|
||||||
|
uint8_t buf[1024];
|
||||||
|
struct libusb_transfer *xfer;
|
||||||
|
};
|
||||||
|
static struct ep_buf g_buf_in;
|
||||||
|
static struct ep_buf g_buf_out;
|
||||||
|
|
||||||
|
static void usb_in_xfer_cb(struct libusb_transfer *xfer)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
printf("xfer_cb(ep=%02x): status=%d, flags=0x%x, type=%u, len=%u, act_len=%u\n",
|
||||||
|
xfer->endpoint, xfer->status, xfer->flags, xfer->type, xfer->length, xfer->actual_length);
|
||||||
|
switch (xfer->status) {
|
||||||
|
case LIBUSB_TRANSFER_COMPLETED:
|
||||||
|
if (xfer->endpoint == g_buf_in.ep) {
|
||||||
|
/* process the data */
|
||||||
|
printf("read %d bytes from SIMTRACE, forwarding to UDP\n", xfer->actual_length);
|
||||||
|
rc = sendto(g_udp_ofd.fd, xfer->buffer, xfer->actual_length, 0, (struct sockaddr *)&g_sa_remote, sizeof(g_sa_remote));
|
||||||
|
if (rc <= 0) {
|
||||||
|
fprintf(stderr, "error writing to UDP\n");
|
||||||
|
}
|
||||||
|
/* and re-submit the URB */
|
||||||
|
libusb_submit_transfer(xfer);
|
||||||
|
} else if (xfer->endpoint == g_buf_out.ep) {
|
||||||
|
/* re-enable reading from the UDP side */
|
||||||
|
g_udp_ofd.when |= BSC_FD_READ;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "xfer_cb(ERROR '%s')\n", osmo_hexdump_nospc(xfer->buffer, xfer->actual_length));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_ep_buf(struct ep_buf *epb)
|
||||||
|
{
|
||||||
|
if (!epb->xfer)
|
||||||
|
epb->xfer = libusb_alloc_transfer(0);
|
||||||
|
|
||||||
|
epb->xfer->flags = 0;
|
||||||
|
|
||||||
|
libusb_fill_bulk_transfer(epb->xfer, g_devh, epb->ep, epb->buf, sizeof(epb->buf), usb_in_xfer_cb, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* libosmocore main loop integration of libusb async I/O
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
static int g_libusb_pending = 0;
|
||||||
|
|
||||||
|
static int ofd_libusb_cb(struct osmo_fd *ofd, unsigned int what)
|
||||||
|
{
|
||||||
|
/* FIXME */
|
||||||
|
g_libusb_pending = 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* call-back when libusb adds a FD */
|
||||||
|
static void libusb_fd_added_cb(int fd, short events, void *user_data)
|
||||||
|
{
|
||||||
|
struct osmo_fd *ofd = talloc_zero(NULL, struct osmo_fd);
|
||||||
|
|
||||||
|
printf("%s(%u, %x)\n", __func__, fd, events);
|
||||||
|
|
||||||
|
ofd->fd = fd;
|
||||||
|
ofd->cb = &ofd_libusb_cb;
|
||||||
|
if (events & POLLIN)
|
||||||
|
ofd->when |= BSC_FD_READ;
|
||||||
|
if (events & POLLOUT)
|
||||||
|
ofd->when |= BSC_FD_WRITE;
|
||||||
|
|
||||||
|
osmo_fd_register(ofd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* call-back when libusb removes a FD */
|
||||||
|
static void libusb_fd_removed_cb(int fd, void *user_data)
|
||||||
|
{
|
||||||
|
|
||||||
|
printf("%s(%u)\n", __func__, fd);
|
||||||
|
#if 0
|
||||||
|
struct osmo_fd *ofd;
|
||||||
|
/* FIXME: This needs new export in libosmocore! */
|
||||||
|
ofd = osmo_fd_get_by_fd(fd);
|
||||||
|
|
||||||
|
if (ofd) {
|
||||||
|
osmo_fd_unregister(ofd);
|
||||||
|
talloc_free(ofd);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* call-back when the UDP socket is readable */
|
||||||
|
static int ofd_udp_cb(struct osmo_fd *ofd, unsigned int what)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
socklen_t addrlen = sizeof(g_sa_remote);
|
||||||
|
|
||||||
|
rc = recvfrom(ofd->fd, g_buf_out.buf, sizeof(g_buf_out.buf), 0,
|
||||||
|
(struct sockaddr *)&g_sa_remote, &addrlen);
|
||||||
|
if (rc <= 0) {
|
||||||
|
fprintf(stderr, "error reading from UDP\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
printf("read %d bytes from UDP, forwarding to SIMTRACE\n", rc);
|
||||||
|
g_buf_out.xfer->length = rc;
|
||||||
|
|
||||||
|
/* disable further READ interest for the UDP socket */
|
||||||
|
ofd->when &= ~BSC_FD_READ;
|
||||||
|
|
||||||
|
/* submit the URB on the OUT end point */
|
||||||
|
libusb_submit_transfer(g_buf_out.xfer);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void run_mainloop(void)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
printf("Entering main loop\n");
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
osmo_select_main(0);
|
||||||
|
if (g_libusb_pending) {
|
||||||
|
struct timeval tv;
|
||||||
|
memset(&tv, 0, sizeof(tv));
|
||||||
|
rc = libusb_handle_events_timeout_completed(NULL, &tv, NULL);
|
||||||
|
if (rc != 0) {
|
||||||
|
fprintf(stderr, "handle_events_timeout_completed == %d\n", rc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
int c, ret = 1;
|
||||||
|
int local_udp_port = 52342;
|
||||||
|
unsigned int if_num = 0;
|
||||||
|
|
||||||
|
print_welcome();
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
int option_index = 0;
|
||||||
|
static const struct option opts[] = {
|
||||||
|
{ "udp-port", 1, 0, 'u' },
|
||||||
|
{ "interface", 1, 0, 'I' },
|
||||||
|
{ "help", 0, 0, 'h' },
|
||||||
|
{ NULL, 0, 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
c = getopt_long(argc, argv, "u:I:h", opts, &option_index);
|
||||||
|
if (c == -1)
|
||||||
|
break;
|
||||||
|
switch (c) {
|
||||||
|
case 'u':
|
||||||
|
local_udp_port = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 'I':
|
||||||
|
if_num = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
print_help();
|
||||||
|
exit(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = libusb_init(NULL);
|
||||||
|
if (rc < 0) {
|
||||||
|
fprintf(stderr, "libusb initialization failed\n");
|
||||||
|
goto close_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
libusb_set_pollfd_notifiers(NULL, &libusb_fd_added_cb, &libusb_fd_removed_cb, NULL);
|
||||||
|
|
||||||
|
g_devh = libusb_open_device_with_vid_pid(NULL, USB_VENDOR_OPENMOKO, USB_PRODUCT_OWHW_SAM3);
|
||||||
|
if (!g_devh) {
|
||||||
|
fprintf(stderr, "can't open USB device\n");
|
||||||
|
goto close_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = libusb_claim_interface(g_devh, if_num);
|
||||||
|
if (rc < 0) {
|
||||||
|
fprintf(stderr, "can't claim interface %u; rc=%d\n", if_num, rc);
|
||||||
|
goto close_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open UDP socket, register with select handling and mark it
|
||||||
|
* readable */
|
||||||
|
g_udp_ofd.cb = ofd_udp_cb;
|
||||||
|
osmo_sock_init_ofd(&g_udp_ofd, AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, local_udp_port + if_num, OSMO_SOCK_F_BIND);
|
||||||
|
|
||||||
|
rc = osmo_libusb_get_ep_addrs(g_devh, if_num, &g_buf_out.ep, &g_buf_in.ep, NULL);
|
||||||
|
if (rc < 0) {
|
||||||
|
fprintf(stderr, "couldn't find enpdoint addresses; rc=%d\n", rc);
|
||||||
|
goto close_exit;
|
||||||
|
}
|
||||||
|
/* initialize USB buffers / transfers */
|
||||||
|
init_ep_buf(&g_buf_out);
|
||||||
|
init_ep_buf(&g_buf_in);
|
||||||
|
|
||||||
|
/* submit the first transfer for the IN endpoint */
|
||||||
|
libusb_submit_transfer(g_buf_in.xfer);
|
||||||
|
|
||||||
|
run_mainloop();
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
libusb_release_interface(g_devh, 0);
|
||||||
|
close_exit:
|
||||||
|
if (g_devh)
|
||||||
|
libusb_close(g_devh);
|
||||||
|
|
||||||
|
libusb_exit(NULL);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user