2 Commits

Author SHA1 Message Date
Harald Welte
9ba5b5c1b9 host/lib/gsmtap.c: Add GPLv2 disclaimer
Change-Id: Ie163af869c6aa2f3e2bd9007432dc6945384aaf2
2020-01-17 10:59:41 +01:00
Harald Welte
2c673c38f5 host: Add COPYING file for host software (GPLv2)
Change-Id: I0f89a204939b0648eed94cc4f6e7c4f735c118fa
2020-01-17 10:59:32 +01:00
82 changed files with 1471 additions and 1793 deletions

5
.gitignore vendored
View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

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

View File

@@ -21,14 +21,11 @@ mkdir "$deps" || true
osmo-build-dep.sh libosmocore "" '--disable-doxygen --enable-gnutls' osmo-build-dep.sh libosmocore "" '--disable-doxygen --enable-gnutls'
# verify only after building the dependency (to ensure we have most recent source of dependency)
verify_value_string_arrays_are_terminated.py $(find . -name "*.[hc]")
export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH" export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH"
export LD_LIBRARY_PATH="$inst/lib" export LD_LIBRARY_PATH="$inst/lib"
BUILDS="" BUILDS=""
BUILDS+="simtrace/dfu simtrace/trace " BUILDS+="simtrace/dfu simtrace/cardem simtrace/trace " # simtrace/triple_play
BUILDS+="qmod/dfu qmod/cardem " BUILDS+="qmod/dfu qmod/cardem "
BUILDS+="owhw/dfu owhw/cardem " BUILDS+="owhw/dfu owhw/cardem "
@@ -63,12 +60,9 @@ make dist
# make -C "$base/doc/manuals" publish # make -C "$base/doc/manuals" publish
#fi #fi
rm -rf $TOPDIR/firmware/bin/simtrace-cardem*
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
[rita.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

View File

@@ -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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -78,11 +78,11 @@
/* Phone USIM slot 1 RST pin (active low; RST_PHONE in schematic) */ /* 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_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_USIM1_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_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_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) */

View File

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

View File

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

View File

@@ -21,10 +21,10 @@
#include <stdint.h> #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);

View File

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

View File

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

View File

@@ -62,8 +62,6 @@ enum simtrace_msg_type_cardem {
SIMTRACE_MSGT_DO_CEMU_RX_DATA, SIMTRACE_MSGT_DO_CEMU_RX_DATA,
/* Indicate PTS request from phone */ /* Indicate PTS request from phone */
SIMTRACE_MSGT_DO_CEMU_PTS, SIMTRACE_MSGT_DO_CEMU_PTS,
/* Set configurable parameters */
SIMTRACE_MSGT_BD_CEMU_CONFIG,
}; };
/* SIMTRACE_MSGC_MODEM */ /* SIMTRACE_MSGC_MODEM */
@@ -231,10 +229,10 @@ struct cardemu_usb_msg_status {
/* phone-applied target voltage in mV */ /* phone-applied target voltage in mV */
uint16_t voltage_mv; uint16_t voltage_mv;
/* Fi/Di related information */ /* Fi/Di related information */
uint8_t F_index; /* <! Index to ISO7816-3 Table 7 (F and f_max values) */ uint8_t fi;
uint8_t D_index; /* <! Index into ISO7816-3 Table 8 (D value) */ uint8_t di;
uint8_t wi; /* <! Waiting Integer as defined in ISO7816-3 Section 10.2 */ uint8_t wi;
uint32_t waiting_time; /* <! Waiting Time in etu as defined in ISO7816-3 Section 8.1 */ uint32_t waiting_time;
} __attribute__ ((packed)); } __attribute__ ((packed));
/* CEMU_USB_MSGT_DO_PTS */ /* CEMU_USB_MSGT_DO_PTS */
@@ -256,15 +254,6 @@ struct cardemu_usb_msg_error {
uint8_t msg[0]; uint8_t msg[0];
} __attribute__ ((packed)); } __attribute__ ((packed));
/* enable/disable the generation of DO_STATUS on IRQ endpoint */
#define CEMU_FEAT_F_STATUS_IRQ 0x00000001
/* SIMTRACE_MSGT_BD_CEMU_CONFIG */
struct cardemu_usb_msg_config {
/* bit-mask of CEMU_FEAT_F flags */
uint32_t features;
} __attribute__ ((packed));
/*********************************************************************** /***********************************************************************
* MODEM CONTROL * MODEM CONTROL
***********************************************************************/ ***********************************************************************/

View File

@@ -64,4 +64,4 @@
#define SIMTRACE_CARDEM_USB_EP_USIM2_INT 3 #define SIMTRACE_CARDEM_USB_EP_USIM2_INT 3
/*! Maximum number of endpoints */ /*! Maximum number of endpoints */
#define BOARD_USB_NUMENDPOINTS 7 /* 0 (control) + 2 (interfaces) * 3 (endpoints) */ #define BOARD_USB_NUMENDPOINTS 6

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
/* 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-2017 by Harald Welte <laforge@gnumonks.org>
* (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de> * (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@@ -27,6 +27,7 @@
#include "utils.h" #include "utils.h"
#include "trace.h" #include "trace.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"
@@ -36,9 +37,6 @@
#define NUM_SLOTS 2 #define NUM_SLOTS 2
/* bit-mask of supported CEMU_FEAT_F_ flags */
#define SUPPORTED_FEATURES (CEMU_FEAT_F_STATUS_IRQ)
#define ISO7816_3_INIT_WTIME 9600 #define ISO7816_3_INIT_WTIME 9600
#define ISO7816_3_DEFAULT_WI 10 #define ISO7816_3_DEFAULT_WI 10
#define ISO7816_3_ATR_LEN_MAX (1+32) /* TS plus 32 chars */ #define ISO7816_3_ATR_LEN_MAX (1+32) /* TS plus 32 chars */
@@ -57,15 +55,42 @@ enum iso7816_3_card_state {
}; };
const struct value_string iso7816_3_card_state_names[] = { const struct value_string iso7816_3_card_state_names[] = {
{ ISO_S_WAIT_POWER, "WAIT_POWER" }, {
{ ISO_S_WAIT_CLK, "WAIT_CLK" }, .value = ISO_S_WAIT_POWER,
{ ISO_S_WAIT_RST, "WAIT_RST" }, .str = "WAIT_POWER",
{ ISO_S_WAIT_ATR, "WAIT_ATR" }, },
{ ISO_S_IN_ATR, "IN_ATR" }, {
{ ISO_S_IN_PTS, "IN_PTS" }, .value = ISO_S_WAIT_CLK,
{ ISO_S_WAIT_TPDU, "WAIT_TPDU" }, .str = "WAIT_CLK",
{ ISO_S_IN_TPDU, "IN_TPDU" }, },
{ 0, NULL } {
.value = ISO_S_WAIT_RST,
.str = "WAIT_RST",
},
{
.value = ISO_S_WAIT_ATR,
.str = "WAIT_ATR",
},
{
.value = ISO_S_IN_ATR,
.str = "IN_ATR",
},
{
.value = ISO_S_IN_PTS,
.str = "IN_PTS",
},
{
.value = ISO_S_WAIT_TPDU,
.str = "WAIT_TPDU",
},
{
.value = ISO_S_IN_TPDU,
.str = "IN_TPDU",
},
{
.value = 0,
.str = NULL,
},
}; };
@@ -85,22 +110,6 @@ enum pts_state {
PTS_S_WAIT_RESP_PCK = PTS_S_WAIT_REQ_PCK | 0x10, PTS_S_WAIT_RESP_PCK = PTS_S_WAIT_REQ_PCK | 0x10,
}; };
const struct value_string pts_state_names[] = {
{ PTS_S_WAIT_REQ_PTSS, "WAIT_REQ_PTSS" },
{ PTS_S_WAIT_REQ_PTS0, "WAIT_REQ_PTS0" },
{ PTS_S_WAIT_REQ_PTS1, "WAIT_REQ_PTS1" },
{ PTS_S_WAIT_REQ_PTS2, "WAIT_REQ_PTS2" },
{ PTS_S_WAIT_REQ_PTS3, "WAIT_REQ_PTS3" },
{ PTS_S_WAIT_REQ_PCK, "WAIT_REQ_PCK" },
{ PTS_S_WAIT_RESP_PTSS, "WAIT_RESP_PTSS" },
{ PTS_S_WAIT_RESP_PTS0, "WAIT_RESP_PTS0" },
{ PTS_S_WAIT_RESP_PTS1, "WAIT_RESP_PTS1" },
{ PTS_S_WAIT_RESP_PTS2, "WAIT_RESP_PTS2" },
{ PTS_S_WAIT_RESP_PTS3, "WAIT_RESP_PTS3" },
{ PTS_S_WAIT_RESP_PCK, "WAIT_RESP_PCK" },
{ 0, NULL }
};
/* PTS field byte index */ /* PTS field byte index */
#define _PTSS 0 #define _PTSS 0
#define _PTS0 1 #define _PTS0 1
@@ -122,15 +131,42 @@ enum tpdu_state {
}; };
const struct value_string tpdu_state_names[] = { const struct value_string tpdu_state_names[] = {
{ TPDU_S_WAIT_CLA, "WAIT_CLA" }, {
{ TPDU_S_WAIT_INS, "WAIT_INS" }, .value = TPDU_S_WAIT_CLA,
{ TPDU_S_WAIT_P1, "WAIT_P1" }, .str = "WAIT_CLA",
{ TPDU_S_WAIT_P2, "WAIT_P2" }, },
{ TPDU_S_WAIT_P3, "WAIT_P3" }, {
{ TPDU_S_WAIT_PB, "WAIT_PB" }, .value = TPDU_S_WAIT_INS,
{ TPDU_S_WAIT_RX, "WAIT_RX" }, .str = "WAIT_INS",
{ TPDU_S_WAIT_TX, "WAIT_TX" }, },
{ 0, NULL } {
.value = TPDU_S_WAIT_P1,
.str = "WAIT_P1",
},
{
.value = TPDU_S_WAIT_P2,
.str = "WAIT_P2",
},
{
.value = TPDU_S_WAIT_P3,
.str = "WAIT_P3",
},
{
.value = TPDU_S_WAIT_PB,
.str = "WAIT_PB",
},
{
.value = TPDU_S_WAIT_RX,
.str = "WAIT_RX",
},
{
.value = TPDU_S_WAIT_TX,
.str = "WAIT_TX",
},
{
.value = 0,
.str = NULL,
},
}; };
/* TPDU field byte index */ /* TPDU field byte index */
@@ -143,9 +179,6 @@ const struct value_string tpdu_state_names[] = {
struct card_handle { struct card_handle {
unsigned int num; unsigned int num;
/* bit-mask of enabled optional features (CEMU_FEAT_F_*) */
uint32_t features;
enum iso7816_3_card_state state; enum iso7816_3_card_state state;
/* signal levels */ /* signal levels */
@@ -153,35 +186,19 @@ 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 /* timing parameters, from PTS */
* of ISO7816-3. */ uint8_t fi;
uint8_t di;
/*! Index to clock rate conversion integer Fi (ISO7816-3 Table 7).
* \note this represents the maximum value supported by the card, and can be indicated in TA1 */
uint8_t Fi_index;
/*! Current value of index to clock rate conversion integer F (ISO 7816-3 Section 7.1). */
uint8_t F_index;
/*! Index to baud rate adjustment factor Di (ISO7816-3 Table 8).
* \note this represents the maximum value supported by the card, and can be indicated in TA1 */
uint8_t Di_index;
/*! Current value of index to baud rate adjustment factor D (ISO 7816-3 Section 7.1). */
uint8_t D_index;
/*! Waiting Integer (ISO7816-3 Section 10.2).
* \note this value can be set in TA2 */
uint8_t wi; uint8_t 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 tc_chan; /* TC channel number */ uint8_t tc_chan; /* TC channel number */
uint8_t uart_chan; /* UART channel */ uint8_t uart_chan; /* UART channel */
uint8_t in_ep; /* USB IN EP */ uint8_t in_ep; /* USB IN EP */
uint8_t irq_ep; /* USB IN EP */ uint8_t irq_ep; /* USB IN EP */
uint32_t waiting_time; /* in clocks */
/* ATR state machine */ /* ATR state machine */
struct { struct {
uint8_t idx; uint8_t idx;
@@ -216,27 +233,6 @@ struct card_handle {
} stats; } stats;
}; };
/* reset all the 'dynamic' state of the card handle to the initial/default values */
static void card_handle_reset(struct card_handle *ch)
{
struct msgb *msg;
card_emu_uart_update_wt(ch->uart_chan, 0);
/* release any buffers we may still own */
if (ch->uart_tx_msg) {
usb_buf_free(ch->uart_tx_msg);
ch->uart_tx_msg = NULL;
}
if (ch->uart_rx_msg) {
usb_buf_free(ch->uart_rx_msg);
ch->uart_rx_msg = NULL;
}
while ((msg = msgb_dequeue(&ch->uart_tx_queue))) {
usb_buf_free(msg);
}
}
struct llist_head *card_emu_get_uart_tx_queue(struct card_handle *ch) struct llist_head *card_emu_get_uart_tx_queue(struct card_handle *ch)
{ {
return &ch->uart_tx_queue; return &ch->uart_tx_queue;
@@ -264,18 +260,18 @@ struct msgb *usb_buf_alloc_st(uint8_t ep, uint8_t msg_class, uint8_t msg_type)
while (!msg) { while (!msg) {
msg = usb_buf_alloc(ep); // try to allocate some memory msg = usb_buf_alloc(ep); // try to allocate some memory
if (!msg) { // allocation failed, we might be out of memory if (!msg) { // allocation failed, we might be out of memory
struct usb_buffered_ep *bep = usb_get_buf_ep(ep); struct llist_head *queue = usb_get_queue(ep);
if (!bep) { if (!queue) {
TRACE_ERROR("ep %u: %s queue does not exist\n\r", TRACE_ERROR("ep %u: %s queue does not exist\n\r",
ep, __func__); ep, __func__);
return NULL; return NULL;
} }
if (llist_empty(&bep->queue)) { if (llist_empty(queue)) {
TRACE_ERROR("ep %u: %s EOMEM (queue already empty)\n\r", TRACE_ERROR("ep %u: %s EOMEM (queue already empty)\n\r",
ep, __func__); ep, __func__);
return NULL; return NULL;
} }
msg = msgb_dequeue_count(&bep->queue, &bep->queue_len); msg = msgb_dequeue(queue);
if (!msg) { if (!msg) {
TRACE_ERROR("ep %u: %s no msg in non-empty queue\n\r", TRACE_ERROR("ep %u: %s no msg in non-empty queue\n\r",
ep, __func__); ep, __func__);
@@ -376,14 +372,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,23 +403,26 @@ static void card_set_state(struct card_handle *ch,
case ISO_S_WAIT_RST: case ISO_S_WAIT_RST:
/* disable Rx and Tx of UART */ /* disable Rx and Tx of UART */
card_emu_uart_enable(ch->uart_chan, 0); card_emu_uart_enable(ch->uart_chan, 0);
/* disable timeout */ /* check end activation state (only necessary if the reader to not respect the activation sequence) */
card_emu_uart_update_wt(ch->uart_chan, 0); if (ch->vcc_active && ch->clocked && !ch->in_reset) {
/* enable the TC/ETU counter once reset has been released */
tc_etu_enable(ch->tc_chan);
/* prepare to send the ATR */
card_set_state(ch, ISO_S_WAIT_ATR);
}
break; break;
case ISO_S_WAIT_ATR: case ISO_S_WAIT_ATR:
/* Reset to initial Fi / Di ratio */ /* Reset to initial Fi / Di ratio */
ch->Fi_index = ch->F_index = 1; ch->fi = 1;
ch->Di_index = ch->D_index = 1; ch->di = 1;
ch->wi = ISO7816_3_DEFAULT_WI;
ch->waiting_time = ISO7816_3_INIT_WTIME;
emu_update_fidi(ch); emu_update_fidi(ch);
/* enable TX to be able to use the timeout */
card_emu_uart_enable(ch->uart_chan, ENABLE_TX_TIMER_ONLY);
/* the ATR should only be sent 400 to 40k clock cycles after the RESET. /* 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 tc_etu mechanism to wait this time.
* since the initial ETU is Fd=372/Dd=1 clock cycles long, we have to wait 2-107 ETU. * since the initial ETU is Fd=372/Dd=1 clock cycles long, we have to wait 2-107 ETU.
*/ */
card_emu_uart_update_wt(ch->uart_chan, 2); tc_etu_set_wtime(ch->tc_chan, 2);
/* ensure the TC_ETU timer is enabled */
tc_etu_enable(ch->tc_chan);
break; break;
case ISO_S_IN_ATR: case ISO_S_IN_ATR:
/* initialize to default WI, this will be overwritten if we /* initialize to default WI, this will be overwritten if we
@@ -431,7 +432,7 @@ static void card_set_state(struct card_handle *ch,
/* update waiting time to initial waiting time */ /* update waiting time to initial waiting time */
ch->waiting_time = ISO7816_3_INIT_WTIME; ch->waiting_time = ISO7816_3_INIT_WTIME;
/* set initial waiting time */ /* set initial waiting time */
card_emu_uart_update_wt(ch->tc_chan, ch->waiting_time); tc_etu_set_wtime(ch->tc_chan, ch->waiting_time);
/* Set ATR sub-state to initial state */ /* Set ATR sub-state to initial state */
ch->atr.idx = 0; ch->atr.idx = 0;
/* enable USART transmission to reader */ /* enable USART transmission to reader */
@@ -507,7 +508,10 @@ static int tx_byte_atr(struct card_handle *ch)
} }
} }
/* update waiting time (see ISO 7816-3 10.2) */ /* update waiting time (see ISO 7816-3 10.2) */
ch->waiting_time = ch->wi * 960 * iso7816_3_fi_table[ch->F_index]; ch->waiting_time = ch->wi * 960 * ch->fi;
tc_etu_set_wtime(ch->tc_chan, ch->waiting_time);
/* reset PTS to initial state */
set_pts_state(ch, PTS_S_WAIT_REQ_PTSS);
/* 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;
@@ -524,9 +528,8 @@ static int tx_byte_atr(struct card_handle *ch)
/* Update the PTS sub-state */ /* Update the PTS sub-state */
static void set_pts_state(struct card_handle *ch, enum pts_state new_ptss) static void set_pts_state(struct card_handle *ch, enum pts_state new_ptss)
{ {
TRACE_DEBUG("%u: 7816 PTS state %s -> %s\r\n", ch->num, TRACE_DEBUG("%u: 7816 PTS state %u -> %u\r\n",
get_value_string(pts_state_names, ch->pts.state), ch->num, ch->pts.state, new_ptss);
get_value_string(pts_state_names, new_ptss));
ch->pts.state = new_ptss; ch->pts.state = new_ptss;
} }
@@ -606,8 +609,8 @@ process_byte_pts(struct card_handle *ch, uint8_t byte)
memcpy(ch->pts.resp, ch->pts.req, sizeof(ch->pts.resp)); memcpy(ch->pts.resp, ch->pts.req, sizeof(ch->pts.resp));
break; break;
default: default:
TRACE_ERROR("%u: process_byte_pts() in invalid PTS state %s\r\n", ch->num, TRACE_ERROR("%u: process_byte_pts() in invalid state %u\r\n",
get_value_string(pts_state_names, ch->pts.state)); ch->num, ch->pts.state);
break; break;
} }
/* calculate the next state and set it */ /* calculate the next state and set it */
@@ -642,11 +645,10 @@ static int tx_byte_pts(struct card_handle *ch)
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 */ /* This must be TA1 */
ch->F_index = byte >> 4; ch->fi = byte >> 4;
ch->D_index = byte & 0xf; ch->di = byte & 0xf;
TRACE_DEBUG("%u: found F=%u D=%u\r\n", ch->num, TRACE_DEBUG("%u: found Fi=%u Di=%u\r\n", ch->num,
iso7816_3_fi_table[ch->F_index], iso7816_3_di_table[ch->D_index]); ch->fi, ch->di);
/* FIXME: if F or D are 0, 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];
@@ -658,8 +660,8 @@ static int tx_byte_pts(struct card_handle *ch)
byte = ch->pts.resp[_PCK]; byte = ch->pts.resp[_PCK];
break; break;
default: default:
TRACE_ERROR("%u: get_byte_pts() in invalid PTS state %s\r\n", ch->num, TRACE_ERROR("%u: get_byte_pts() in invalid state %u\r\n",
get_value_string(pts_state_names, ch->pts.state)); ch->num, ch->pts.state);
return 0; return 0;
} }
@@ -671,7 +673,7 @@ 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 */ /* update baud rate generator with Fi/Di */
emu_update_fidi(ch); emu_update_fidi(ch);
/* 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);
@@ -751,28 +753,14 @@ static void set_tpdu_state(struct card_handle *ch, enum tpdu_state new_ts)
switch (new_ts) { switch (new_ts) {
case TPDU_S_WAIT_CLA: case TPDU_S_WAIT_CLA:
/* switch back to receiving mode */
card_emu_uart_enable(ch->uart_chan, ENABLE_RX);
/* disable waiting time since we don't expect any data */
card_emu_uart_update_wt(ch->uart_chan, 0);
break;
case TPDU_S_WAIT_INS:
/* start waiting for the rest of the header/body */
card_emu_uart_update_wt(ch->uart_chan, ch->waiting_time);
break;
case TPDU_S_WAIT_RX: case TPDU_S_WAIT_RX:
/* switch to receive mode to receive the body */
card_emu_uart_enable(ch->uart_chan, ENABLE_RX); card_emu_uart_enable(ch->uart_chan, ENABLE_RX);
/* start waiting for the body */
card_emu_uart_update_wt(ch->uart_chan, ch->waiting_time);
break; break;
case TPDU_S_WAIT_PB: case TPDU_S_WAIT_PB:
/* we just completed the TPDU header from reader to card /* we just completed the TPDU header from reader to card
* and now need to disable the receiver, enable the * and now need to disable the receiver, enable the
* transmitter and transmit the procedure byte */ * transmitter and transmit the procedure byte */
card_emu_uart_enable(ch->uart_chan, ENABLE_TX); 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;
@@ -879,8 +867,8 @@ process_byte_tpdu(struct card_handle *ch, uint8_t byte)
add_tpdu_byte(ch, byte); add_tpdu_byte(ch, byte);
break; break;
default: default:
TRACE_ERROR("%u: process_byte_tpdu() in invalid TPDU state %s\r\n", ch->num, TRACE_ERROR("%u: process_byte_tpdu() in invalid state %u\r\n",
get_value_string(tpdu_state_names, ch->tpdu.state)); ch->num, ch->tpdu.state);
} }
/* ensure we stay in TPDU ISO state */ /* ensure we stay in TPDU ISO state */
@@ -967,8 +955,6 @@ void card_emu_process_rx_byte(struct card_handle *ch, uint8_t byte)
switch (ch->state) { switch (ch->state) {
case ISO_S_WAIT_TPDU: case ISO_S_WAIT_TPDU:
if (byte == 0xff) { if (byte == 0xff) {
/* reset PTS to initial state */
set_pts_state(ch, PTS_S_WAIT_REQ_PTSS);
new_state = process_byte_pts(ch, byte); new_state = process_byte_pts(ch, byte);
ch->stats.pps++; ch->stats.pps++;
goto out_silent; goto out_silent;
@@ -981,8 +967,8 @@ void card_emu_process_rx_byte(struct card_handle *ch, uint8_t byte)
new_state = process_byte_pts(ch, byte); new_state = process_byte_pts(ch, byte);
goto out_silent; goto out_silent;
default: default:
TRACE_ERROR("%u: Received UART char in invalid 7816 state %s\r\n", ch->num, TRACE_ERROR("%u: Received UART char in invalid 7816 state "
get_value_string(iso7816_3_card_state_names, ch->state)); "%u\r\n", ch->num, ch->state);
break; break;
} }
@@ -1035,16 +1021,13 @@ 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)
{ {
struct msgb *msg; struct msgb *msg;
struct cardemu_usb_msg_status *sts; struct cardemu_usb_msg_status *sts;
uint8_t ep = ch->in_ep;
if (report_on_irq) msg = usb_buf_alloc_st(ch->in_ep, SIMTRACE_MSGC_CARDEM,
ep = ch->irq_ep; SIMTRACE_MSGT_BD_CEMU_STATUS);
msg = usb_buf_alloc_st(ep, SIMTRACE_MSGC_CARDEM, SIMTRACE_MSGT_BD_CEMU_STATUS);
if (!msg) if (!msg)
return; return;
@@ -1057,46 +1040,26 @@ void card_emu_report_status(struct card_handle *ch, bool report_on_irq)
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: voltage + card insert */
sts->F_index = ch->F_index; sts->fi = ch->fi;
sts->D_index = ch->D_index; sts->di = ch->di;
sts->wi = ch->wi; sts->wi = ch->wi;
sts->waiting_time = ch->waiting_time; sts->waiting_time = ch->waiting_time;
usb_buf_upd_len_and_submit(msg); usb_buf_upd_len_and_submit(msg);
} }
static void card_emu_report_config(struct card_handle *ch)
{
struct msgb *msg;
struct cardemu_usb_msg_config *cfg;
uint8_t ep = ch->in_ep;
msg = usb_buf_alloc_st(ch->in_ep, SIMTRACE_MSGC_CARDEM, SIMTRACE_MSGT_BD_CEMU_CONFIG);
if (!msg)
return;
cfg = (struct cardemu_usb_msg_config *) msgb_put(msg, sizeof(*cfg));
cfg->features = ch->features;
usb_buf_upd_len_and_submit(msg);
}
/* hardware driver informs us that a card I/O signal has changed */ /* hardware driver informs us that a card I/O signal has changed */
void card_emu_io_statechg(struct card_handle *ch, enum card_io io, int active) void card_emu_io_statechg(struct card_handle *ch, enum card_io io, int active)
{ {
uint32_t chg_mask = 0;
switch (io) { switch (io) {
case CARD_IO_VCC: case CARD_IO_VCC:
if (active == 0 && ch->vcc_active == 1) { if (active == 0 && ch->vcc_active == 1) {
TRACE_INFO("%u: VCC deactivated\r\n", ch->num); TRACE_INFO("%u: VCC deactivated\r\n", ch->num);
card_handle_reset(ch); tc_etu_disable(ch->tc_chan);
card_set_state(ch, ISO_S_WAIT_POWER); card_set_state(ch, ISO_S_WAIT_POWER);
chg_mask |= CEMU_STATUS_F_VCC_PRESENT;
} else if (active == 1 && ch->vcc_active == 0) { } else if (active == 1 && ch->vcc_active == 0) {
TRACE_INFO("%u: VCC activated\r\n", ch->num); TRACE_INFO("%u: VCC activated\r\n", ch->num);
card_set_state(ch, ISO_S_WAIT_CLK); card_set_state(ch, ISO_S_WAIT_CLK);
chg_mask |= CEMU_STATUS_F_VCC_PRESENT;
} }
ch->vcc_active = active; ch->vcc_active = active;
break; break;
@@ -1105,49 +1068,27 @@ void card_emu_io_statechg(struct card_handle *ch, enum card_io io, int active)
TRACE_INFO("%u: CLK activated\r\n", ch->num); TRACE_INFO("%u: CLK activated\r\n", ch->num);
if (ch->state == ISO_S_WAIT_CLK) if (ch->state == ISO_S_WAIT_CLK)
card_set_state(ch, ISO_S_WAIT_RST); card_set_state(ch, ISO_S_WAIT_RST);
chg_mask |= CEMU_STATUS_F_CLK_ACTIVE;
} else if (active == 0 && ch->clocked == 1) { } else if (active == 0 && ch->clocked == 1) {
TRACE_INFO("%u: CLK deactivated\r\n", ch->num); TRACE_INFO("%u: CLK deactivated\r\n", ch->num);
chg_mask |= CEMU_STATUS_F_CLK_ACTIVE;
} }
ch->clocked = active; ch->clocked = active;
break; break;
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) {
/* enable the TC/ETU counter once reset has been released */
tc_etu_enable(ch->tc_chan);
/* prepare to send the ATR */ /* prepare to send the ATR */
card_set_state(ch, ISO_S_WAIT_ATR); card_set_state(ch, ISO_S_WAIT_ATR);
} }
chg_mask |= CEMU_STATUS_F_RESET_ACTIVE;
} else if (active && !ch->in_reset) { } else if (active && !ch->in_reset) {
TRACE_INFO("%u: RST asserted\r\n", ch->num); TRACE_INFO("%u: RST asserted\r\n", ch->num);
card_handle_reset(ch); tc_etu_disable(ch->tc_chan);
chg_mask |= CEMU_STATUS_F_RESET_ACTIVE;
card_set_state(ch, ISO_S_WAIT_RST);
} }
ch->in_reset = active; ch->in_reset = active;
break; break;
} }
switch (ch->state) {
case ISO_S_WAIT_POWER:
case ISO_S_WAIT_CLK:
case ISO_S_WAIT_RST:
/* check end activation state (even if the reader does
* not respect the activation sequence) */
if (ch->vcc_active && ch->clocked && !ch->in_reset) {
/* prepare to send the ATR */
card_set_state(ch, ISO_S_WAIT_ATR);
}
break;
default:
break;
}
/* notify the host about the state change */
if ((ch->features & CEMU_FEAT_F_STATUS_IRQ) && chg_mask)
card_emu_report_status(ch, true);
} }
/* User sets a new ATR to be returned during next card reset */ /* User sets a new ATR to be returned during next card reset */
@@ -1174,7 +1115,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 tc_etu_wtime_half_expired(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 */
@@ -1184,10 +1125,7 @@ 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
* reader to wait more time */
card_emu_uart_tx(ch->uart_chan, ISO7816_3_PB_NULL); 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;
@@ -1199,7 +1137,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 tc_etu_wtime_expired(void *handle)
{ {
struct card_handle *ch = handle; struct card_handle *ch = handle;
switch (ch->state) { switch (ch->state) {
@@ -1213,38 +1151,11 @@ void card_emu_wtime_expired(void *handle)
} }
} }
/* reasonable ATR offering all protocols and voltages /* shortest ATR possible (uses default speed and no options) */
* smartphones might not care, but other readers do static const uint8_t default_atr[] = { 0x3B, 0x00 };
*
* TS = 0x3B Direct Convention
* T0 = 0x80 Y(1): b1000, K: 0 (historical bytes)
* TD(1) = 0x80 Y(i+1) = b1000, Protocol T=0
* ----
* TD(2) = 0x81 Y(i+1) = b1000, Protocol T=1
* ----
* TD(3) = 0x1F Y(i+1) = b0001, Protocol T=15
* ----
* TA(4) = 0xC7 Clock stop: no preference - Class accepted by the card: (3G) A 5V B 3V C 1.8V
* ----
* Historical bytes
* TCK = 0x59 correct checksum
*/
static const uint8_t default_atr[] = { 0x3B, 0x80, 0x80, 0x81 , 0x1F, 0xC7, 0x59 };
static struct card_handle card_handles[NUM_SLOTS]; static struct card_handle card_handles[NUM_SLOTS];
int card_emu_set_config(struct card_handle *ch, const struct cardemu_usb_msg_config *scfg,
unsigned int scfg_len)
{
if (scfg_len >= sizeof(uint32_t))
ch->features = (scfg->features & SUPPORTED_FEATURES);
/* send back a report of our current configuration */
card_emu_report_config(ch);
return 0;
}
struct card_handle *card_emu_init(uint8_t slot_num, uint8_t tc_chan, uint8_t uart_chan, uint8_t in_ep, uint8_t irq_ep, bool vcc_active, bool in_reset, bool clocked) struct card_handle *card_emu_init(uint8_t slot_num, uint8_t 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;
@@ -1266,8 +1177,8 @@ struct card_handle *card_emu_init(uint8_t slot_num, uint8_t tc_chan, uint8_t uar
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 = 0;
ch->Di_index = ch->D_index = 1; ch->di = 1;
ch->wi = ISO7816_3_DEFAULT_WI; ch->wi = ISO7816_3_DEFAULT_WI;
ch->tc_chan = tc_chan; ch->tc_chan = tc_chan;
@@ -1281,7 +1192,7 @@ struct card_handle *card_emu_init(uint8_t slot_num, uint8_t tc_chan, uint8_t uar
ch->pts.state = PTS_S_WAIT_REQ_PTSS; ch->pts.state = PTS_S_WAIT_REQ_PTSS;
ch->tpdu.state = TPDU_S_WAIT_CLA; ch->tpdu.state = TPDU_S_WAIT_CLA;
card_handle_reset(ch); tc_etu_init(ch->tc_chan, ch);
return ch; return ch;
} }

View File

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

View File

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

View File

@@ -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;

View File

@@ -1,54 +0,0 @@
/* SIMtrace 2 firmware common main helpers
*
* (C) 2015-2019 by Harald Welte <hwelte@hmw-consulting.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "board.h"
#include "utils.h"
void print_banner(void)
{
printf("\n\r\n\r"
"=============================================================================\n\r"
"SIMtrace2 firmware " GIT_VERSION ", BOARD=" BOARD ", APP=" APPLICATION "\n\r"
"(C) 2010-2019 by Harald Welte, 2018-2019 by Kevin Redon\n\r"
"=============================================================================\n\r");
#if (TRACE_LEVEL >= TRACE_LEVEL_INFO)
/* print chip-unique ID */
unsigned int unique_id[4];
EEFC_ReadUniqueID(unique_id);
TRACE_INFO("Chip ID: 0x%08lx (Ext 0x%08lx)\n\r", CHIPID->CHIPID_CIDR, CHIPID->CHIPID_EXID);
TRACE_INFO("Serial Nr. %08x-%08x-%08x-%08x\n\r",
unique_id[0], unique_id[1], unique_id[2], unique_id[3]);
/* print reset cause */
uint8_t reset_cause = (RSTC->RSTC_SR & RSTC_SR_RSTTYP_Msk) >> RSTC_SR_RSTTYP_Pos;
static const char* reset_causes[] = {
"general reset (first power-up reset)",
"backup reset (return from backup mode)",
"watchdog reset (watchdog fault occurred)",
"software reset (processor reset required by the software)",
"user reset (NRST pin detected low)",
};
if (reset_cause < ARRAY_SIZE(reset_causes)) {
TRACE_INFO("Reset Cause: %s\n\r", reset_causes[reset_cause]);
} else {
TRACE_INFO("Reset Cause: 0x%lx\n\r", (RSTC->RSTC_SR & RSTC_SR_RSTTYP_Msk) >> RSTC_SR_RSTTYP_Pos);
}
#endif
}

View File

@@ -1,7 +1,7 @@
/* card emulation mode /* card emulation mode
* *
* (C) 2015-2017 by Harald Welte <laforge@gnumonks.org> * (C) 2015-2017 by Harald Welte <laforge@gnumonks.org>
* (C) 2018-2019 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de> * (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
* *
* This program is free software; you can redistribute it and/or modify * 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
@@ -55,27 +55,13 @@ struct cardem_inst {
struct llist_head usb_out_queue; struct llist_head usb_out_queue;
struct ringbuf rb; struct ringbuf rb;
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;
uint8_t ep_out; uint8_t ep_out;
uint8_t ep_in; uint8_t ep_in;
uint8_t ep_int; uint8_t ep_int;
const Pin pin_insert; const Pin pin_insert;
#ifdef DETECT_VCC_BY_ADC
uint32_t vcc_uv; uint32_t vcc_uv;
uint32_t vcc_uv_last; uint32_t vcc_uv_last;
#endif
bool vcc_active;
bool vcc_active_last;
bool rst_active;
bool rst_active_last;
}; };
struct cardem_inst cardem_inst[] = { struct cardem_inst cardem_inst[] = {
@@ -149,23 +135,12 @@ 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:
USART_DisableIt(usart, ~(US_IER_TXRDY | US_IER_TIMEOUT)); USART_DisableIt(usart, ~US_IER_TXRDY);
/* 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;
USART_EnableIt(usart, US_IER_TXRDY | US_IER_TIMEOUT); USART_EnableIt(usart, US_IER_TXRDY);
USART_SetTransmitterEnabled(usart, 1);
break;
case ENABLE_TX_TIMER_ONLY:
/* enable the transmitter without generating TXRDY interrupts
* just so that the timer can run */
USART_DisableIt(usart, ~US_IER_TIMEOUT);
/* as irritating as it is, we actually want to keep the
* receiver enabled during transmit */
USART_SetReceiverEnabled(usart, 1);
usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
USART_EnableIt(usart, US_IER_TIMEOUT);
USART_SetTransmitterEnabled(usart, 1); USART_SetTransmitterEnabled(usart, 1);
break; break;
case ENABLE_RX: case ENABLE_RX:
@@ -214,82 +189,40 @@ int card_emu_uart_tx(uint8_t uart_chan, uint8_t byte)
} }
/*! common handler if interrupt was received. /* FIXME: integrate this with actual irq handler */
* \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));
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;
/* get one atomic snapshot of state/flags before they get changed */
csr = usart->US_CSR & usart->US_IMR; 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) { if (csr & US_CSR_RXRDY) {
/* read the bye from the holding register */
byte = (usart->US_RHR) & 0xFF; byte = (usart->US_RHR) & 0xFF;
/* append it to the buffer */
if (rbuf_write(&ci->rb, byte) < 0) if (rbuf_write(&ci->rb, byte) < 0)
TRACE_ERROR("rbuf overrun\r\n"); TRACE_ERROR("rbuf overrun\r\n");
} }
/* check if the transmitter is ready for the next byte */
if (csr & US_CSR_TXRDY) { if (csr & US_CSR_TXRDY) {
/* transmit next byte and check if more bytes are to be transmitted */ if (card_emu_tx_byte(ci->ch) == 0)
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); USART_DisableIt(usart, US_IER_TXRDY);
}
} }
/* check if any error flags are set */ if (csr & (US_CSR_OVRE|US_CSR_FRAME|US_CSR_PARE|
if (csr & (US_CSR_OVRE|US_CSR_FRAME|US_CSR_PARE|US_CSR_NACK|(1<<10))) { US_CSR_TIMEOUT|US_CSR_NACK|(1<<10))) {
/* clear any error flags */
usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK; 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); TRACE_ERROR("%u e 0x%x st: 0x%lx\n", ci->num, byte, csr);
}
/* check if the timeout has expired. We "abuse" the receive timer for tracking
* how many etu have expired since we last sent a byte. See section
* 33.7.3.11 "Receiver Time-out" of the SAM3S8 Data Sheet */
if (csr & US_CSR_TIMEOUT) {
/* RX has been inactive for some time */
if (ci->wt.remaining <= (usart->US_RTOR & 0xffff)) {
/* waiting time is over; will stop the timer */
ci->wt.remaining = 0;
} else {
/* subtract the actual timeout since the new might not have been set and
* reloaded yet */
ci->wt.remaining -= (usart->US_RTOR & 0xffff);
}
if (ci->wt.remaining == 0) {
/* let the FSM know that WT has expired */
card_emu_wtime_expired(ci->ch);
} else if (ci->wt.remaining <= ci->wt.total / 2 && !ci->wt.half_time_notified) {
/* let the FS know that half of the WT has expired */
card_emu_wtime_half_expired(ci->ch);
ci->wt.half_time_notified = true;
}
/* if value exceeds the USART TO range, use the maximum for now */
usart->US_RTOR = OSMO_MIN(ci->wt.remaining, 0xffff);
/* clear timeout flag (and stop timeout until next character is received) */
usart->US_CR |= US_CR_STTTO;
/* restart the counter (it wt is 0, the timeout is not started) */
usart->US_CR |= US_CR_RETTO;
} }
} }
/*! ISR called for USART0 */
void mode_cardemu_usart0_irq(void) void mode_cardemu_usart0_irq(void)
{ {
/* USART0 == Instance 1 == USIM 2 */ /* USART0 == Instance 1 == USIM 2 */
usart_irq_rx(1); usart_irq_rx(1);
} }
/*! ISR called for USART1 */
void mode_cardemu_usart1_irq(void) void mode_cardemu_usart1_irq(void)
{ {
/* USART1 == Instance 0 == USIM 1 */ /* USART1 == Instance 0 == USIM 1 */
@@ -308,38 +241,6 @@ 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.
* \param[in] usart USART peripheral to configure
* \param[in] wt inactivity Waiting Time before card_emu_wtime_expired is called (0 to disable) */
void card_emu_uart_update_wt(uint8_t uart_chan, uint32_t wt)
{
OSMO_ASSERT(uart_chan < ARRAY_SIZE(cardem_inst));
struct cardem_inst *ci = &cardem_inst[uart_chan];
Usart *usart = get_usart_by_chan(uart_chan);
ci->wt.total = wt;
/* reset and start the 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)
{
OSMO_ASSERT(uart_chan < ARRAY_SIZE(cardem_inst));
struct cardem_inst *ci = &cardem_inst[uart_chan];
Usart *usart = get_usart_by_chan(uart_chan);
/* FIXME: guard against race with interrupt handler */
ci->wt.remaining = ci->wt.total;
ci->wt.half_time_notified = false;
/* if value exceeds the USART TO range, use the maximum for now */
usart->US_RTOR = OSMO_MIN(ci->wt.remaining, 0xffff);
/* restart the counter (if wt is 0, the timeout is not started) */
usart->US_CR |= US_CR_RETTO;
}
/* call-back from card_emu.c to force a USART interrupt */ /* call-back from card_emu.c to force a USART interrupt */
void card_emu_uart_interrupt(uint8_t uart_chan) void card_emu_uart_interrupt(uint8_t uart_chan)
{ {
@@ -360,7 +261,7 @@ void card_emu_uart_interrupt(uint8_t uart_chan)
#ifdef DETECT_VCC_BY_ADC #ifdef DETECT_VCC_BY_ADC
static volatile int adc_triggered = 0; static int adc_triggered = 0;
static int adc_sam3s_reva_errata = 0; static int adc_sam3s_reva_errata = 0;
static int card_vcc_adc_init(void) static int card_vcc_adc_init(void)
@@ -414,10 +315,14 @@ 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 &&
ci->vcc_uv_last < VCC_UV_THRESH_3V) { ci->vcc_uv_last < VCC_UV_THRESH_3V) {
ci->vcc_active = true; card_emu_io_statechg(ci->ch, CARD_IO_VCC, 1);
/* FIXME do this for real */
card_emu_io_statechg(ci->ch, CARD_IO_CLK, 1);
} else if (ci->vcc_uv < VCC_UV_THRESH_3V && } else if (ci->vcc_uv < VCC_UV_THRESH_3V &&
ci->vcc_uv_last >= VCC_UV_THRESH_3V) { ci->vcc_uv_last >= VCC_UV_THRESH_3V) {
ci->vcc_active = false; /* FIXME do this for real */
card_emu_io_statechg(ci->ch, CARD_IO_CLK, 0);
card_emu_io_statechg(ci->ch, CARD_IO_VCC, 0);
} }
ci->vcc_uv_last = ci->vcc_uv; ci->vcc_uv_last = ci->vcc_uv;
} }
@@ -442,54 +347,44 @@ void ADC_IrqHandler(void)
cardem_inst[0].vcc_uv = adc2uv(val); cardem_inst[0].vcc_uv = adc2uv(val);
process_vcc_adc(&cardem_inst[0]); process_vcc_adc(&cardem_inst[0]);
ADC->ADC_CR |= ADC_CR_START; ADC->ADC_CR |= ADC_CR_START;
adc_triggered = 1;
} }
} }
#endif /* DETECT_VCC_BY_ADC */ #endif /* DETECT_VCC_BY_ADC */
/* called from main loop; dispatches card I/O state changes to card_emu from main loop */
static void process_io_statechg(struct cardem_inst *ci)
{
if (ci->vcc_active != ci->vcc_active_last) {
card_emu_io_statechg(ci->ch, CARD_IO_VCC, ci->vcc_active);
/* FIXME do this for real */
card_emu_io_statechg(ci->ch, CARD_IO_CLK, ci->vcc_active);
ci->vcc_active_last = ci->vcc_active;
}
if (ci->rst_active != ci->rst_active_last) {
card_emu_io_statechg(ci->ch, CARD_IO_RST, ci->rst_active);
ci->rst_active_last = ci->rst_active;
}
}
/*********************************************************************** /***********************************************************************
* Core USB / main loop integration * Core USB / main loop integration
***********************************************************************/ ***********************************************************************/
static void usim1_rst_irqhandler(const Pin *pPin) static void usim1_rst_irqhandler(const Pin *pPin)
{ {
cardem_inst[0].rst_active = PIO_Get(&pin_usim1_rst) ? false : true; bool active = PIO_Get(&pin_usim1_rst) ? false : true;
card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_RST, active);
} }
#ifndef DETECT_VCC_BY_ADC #ifndef DETECT_VCC_BY_ADC
static void usim1_vcc_irqhandler(const Pin *pPin) static void usim1_vcc_irqhandler(const Pin *pPin)
{ {
cardem_inst[0].vcc_active = PIO_Get(&pin_usim1_vcc) ? true : false; bool active = PIO_Get(&pin_usim1_vcc) ? true : false;
card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_VCC, active);
/* FIXME do this for real */
card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_CLK, active);
} }
#endif /* !DETECT_VCC_BY_ADC */ #endif /* !DETECT_VCC_BY_ADC */
#ifdef CARDEMU_SECOND_UART #ifdef CARDEMU_SECOND_UART
static void usim2_rst_irqhandler(const Pin *pPin) static void usim2_rst_irqhandler(const Pin *pPin)
{ {
cardem_inst[1].rst_active = PIO_Get(&pin_usim2_rst) ? false : true; bool active = PIO_Get(&pin_usim2_rst) ? false : true;
card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_RST, active);
} }
#ifndef DETECT_VCC_BY_ADC #ifndef DETECT_VCC_BY_ADC
static void usim2_vcc_irqhandler(const Pin *pPin) static void usim2_vcc_irqhandler(const Pin *pPin)
{ {
cardem_inst[1].vcc_active = PIO_Get(&pin_usim2_vcc) ? true : false; bool active = PIO_Get(&pin_usim2_vcc) ? true : false;
card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_VCC, active);
/* FIXME do this for real */
card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_CLK, active);
} }
#endif /* !DETECT_VCC_BY_ADC */ #endif /* !DETECT_VCC_BY_ADC */
#endif /* CARDEMU_SECOND_UART */ #endif /* CARDEMU_SECOND_UART */
@@ -517,41 +412,15 @@ void mode_cardemu_init(void)
INIT_LLIST_HEAD(&cardem_inst[0].usb_out_queue); INIT_LLIST_HEAD(&cardem_inst[0].usb_out_queue);
rbuf_reset(&cardem_inst[0].rb); rbuf_reset(&cardem_inst[0].rb);
PIO_Configure(pins_usim1, PIO_LISTSIZE(pins_usim1)); PIO_Configure(pins_usim1, PIO_LISTSIZE(pins_usim1));
/* 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);
/* obtain current RST state */
usim1_rst_irqhandler(&pin_usim1_rst);
#ifndef DETECT_VCC_BY_ADC #ifndef DETECT_VCC_BY_ADC
PIO_ConfigureIt(&pin_usim1_vcc, usim1_vcc_irqhandler); PIO_ConfigureIt(&pin_usim1_vcc, usim1_vcc_irqhandler);
PIO_EnableIt(&pin_usim1_vcc); PIO_EnableIt(&pin_usim1_vcc);
/* obtain current VCC state */
usim1_vcc_irqhandler(&pin_usim1_vcc);
#else
do {} while (!adc_triggered); /* wait for first ADC reading */
#endif /* DETECT_VCC_BY_ADC */ #endif /* DETECT_VCC_BY_ADC */
cardem_inst[0].ch = card_emu_init(0, 2, 0, SIMTRACE_CARDEM_USB_EP_USIM1_DATAIN, SIMTRACE_CARDEM_USB_EP_USIM1_INT, PIO_Get(&pin_usim1_vcc) ? true : false, PIO_Get(&pin_usim1_rst) ? false : true, PIO_Get(&pin_usim1_vcc) ? true : false);
cardem_inst[0].ch = card_emu_init(0, 2, 0, SIMTRACE_CARDEM_USB_EP_USIM1_DATAIN,
SIMTRACE_CARDEM_USB_EP_USIM1_INT, cardem_inst[0].vcc_active,
cardem_inst[0].rst_active, cardem_inst[0].vcc_active);
sim_switch_use_physical(0, 1); sim_switch_use_physical(0, 1);
#ifdef CARDEMU_SECOND_UART #ifdef CARDEMU_SECOND_UART
@@ -559,24 +428,15 @@ void mode_cardemu_init(void)
rbuf_reset(&cardem_inst[1].rb); rbuf_reset(&cardem_inst[1].rb);
PIO_Configure(pins_usim2, PIO_LISTSIZE(pins_usim2)); PIO_Configure(pins_usim2, PIO_LISTSIZE(pins_usim2));
ISO7816_Init(&cardem_inst[1].usart_info, CLK_SLAVE); ISO7816_Init(&cardem_inst[1].usart_info, CLK_SLAVE);
/* TODO enable timeout */
NVIC_EnableIRQ(USART0_IRQn); NVIC_EnableIRQ(USART0_IRQn);
PIO_ConfigureIt(&pin_usim2_rst, usim2_rst_irqhandler); PIO_ConfigureIt(&pin_usim2_rst, usim2_rst_irqhandler);
PIO_EnableIt(&pin_usim2_rst); PIO_EnableIt(&pin_usim2_rst);
usim2_rst_irqhandler(&pin_usim2_rst); /* obtain current RST state */
#ifndef DETECT_VCC_BY_ADC #ifndef DETECT_VCC_BY_ADC
PIO_ConfigureIt(&pin_usim2_vcc, usim2_vcc_irqhandler); PIO_ConfigureIt(&pin_usim2_vcc, usim2_vcc_irqhandler);
PIO_EnableIt(&pin_usim2_vcc); PIO_EnableIt(&pin_usim2_vcc);
usim2_vcc_irqhandler(&pin_usim2_vcc); /* obtain current VCC state */
#else
do {} while (!adc_triggered); /* wait for first ADC reading */
#endif /* DETECT_VCC_BY_ADC */ #endif /* DETECT_VCC_BY_ADC */
cardem_inst[1].ch = card_emu_init(1, 0, 1, SIMTRACE_CARDEM_USB_EP_USIM2_DATAIN, SIMTRACE_CARDEM_USB_EP_USIM2_INT, PIO_Get(&pin_usim2_vcc) ? true : false, PIO_Get(&pin_usim2_rst) ? false : true, PIO_Get(&pin_usim2_vcc) ? true : false);
cardem_inst[1].ch = card_emu_init(1, 0, 1, SIMTRACE_CARDEM_USB_EP_USIM2_DATAIN,
SIMTRACE_CARDEM_USB_EP_USIM2_INT, cardem_inst[1].vcc_active,
cardem_inst[1].rst_active, cardem_inst[1].vcc_active);
sim_switch_use_physical(1, 1); sim_switch_use_physical(1, 1);
/* TODO check RST and VCC */
#endif /* CARDEMU_SECOND_UART */ #endif /* CARDEMU_SECOND_UART */
} }
@@ -626,7 +486,6 @@ static void dispatch_usb_command_cardem(struct msgb *msg, struct cardem_inst *ci
struct simtrace_msg_hdr *hdr; struct simtrace_msg_hdr *hdr;
struct cardemu_usb_msg_set_atr *atr; struct cardemu_usb_msg_set_atr *atr;
struct cardemu_usb_msg_cardinsert *cardins; struct cardemu_usb_msg_cardinsert *cardins;
struct cardemu_usb_msg_config *cfg;
struct llist_head *queue; struct llist_head *queue;
hdr = (struct simtrace_msg_hdr *) msg->l1h; hdr = (struct simtrace_msg_hdr *) msg->l1h;
@@ -646,7 +505,6 @@ static void dispatch_usb_command_cardem(struct msgb *msg, struct cardem_inst *ci
if (!ci->pin_insert.pio) { if (!ci->pin_insert.pio) {
TRACE_INFO("%u: skipping unsupported card_insert to %s\r\n", TRACE_INFO("%u: skipping unsupported card_insert to %s\r\n",
ci->num, cardins->card_insert ? "INSERTED" : "REMOVED"); ci->num, cardins->card_insert ? "INSERTED" : "REMOVED");
usb_buf_free(msg);
break; break;
} }
TRACE_INFO("%u: set card_insert to %s\r\n", ci->num, TRACE_INFO("%u: set card_insert to %s\r\n", ci->num,
@@ -658,13 +516,9 @@ static void dispatch_usb_command_cardem(struct msgb *msg, struct cardem_inst *ci
usb_buf_free(msg); usb_buf_free(msg);
break; break;
case SIMTRACE_MSGT_BD_CEMU_STATUS: case SIMTRACE_MSGT_BD_CEMU_STATUS:
card_emu_report_status(ci->ch, false); card_emu_report_status(ci->ch);
usb_buf_free(msg); usb_buf_free(msg);
break; break;
case SIMTRACE_MSGT_BD_CEMU_CONFIG:
cfg = (struct cardemu_usb_msg_config *) msg->l2h;
card_emu_set_config(ci->ch, cfg, msgb_l2len(msg));
break;
case SIMTRACE_MSGT_BD_CEMU_STATS: case SIMTRACE_MSGT_BD_CEMU_STATS:
default: default:
/* FIXME: Send Error */ /* FIXME: Send Error */
@@ -798,10 +652,9 @@ static void dispatch_received_msg(struct msgb *msg, struct cardem_inst *ci)
} }
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)\n",
ci->num, mh->msg_len); ci->num, mh->msg_len);
usb_buf_free(segm); usb_buf_free(segm);
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;
@@ -861,8 +714,6 @@ void mode_cardemu_run(void)
//TRACE_ERROR("%uRx%02x\r\n", i, byte); //TRACE_ERROR("%uRx%02x\r\n", i, byte);
} }
process_io_statechg(ci);
/* first try to send any pending messages on IRQ */ /* first try to send any pending messages on IRQ */
usb_refill_to_host(ci->ep_int); usb_refill_to_host(ci->ep_int);

View File

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

View File

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

View File

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

View File

@@ -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");
}

View File

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

View File

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

View File

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

View File

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

Binary file not shown.

5
host/.gitignore vendored
View File

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

View File

@@ -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
View 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/

View File

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

View File

@@ -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
View 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:

View File

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

View File

@@ -1,6 +1,6 @@
/* apdu_dispatch - State machine to determine Rx/Tx phases of APDU /* apdu_dispatch - State machine to determine Rx/Tx phases of APDU
* *
* (C) 2016-2019 by Harald Welte <hwelte@hmw-consulting.de> * (C) 2016 by Harald Welte <hwelte@hmw-consulting.de>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -44,8 +44,6 @@ enum osmo_apdu_action {
APDU_ACT_RX_MORE_CAPDU_FROM_READER = 0x0002, APDU_ACT_RX_MORE_CAPDU_FROM_READER = 0x0002,
}; };
const char *osmo_apdu_dump_context_buf(char *buf, unsigned int buf_len,
const struct osmo_apdu_context *ac);
int osmo_apdu_segment_in(struct osmo_apdu_context *ac, const uint8_t *apdu_buf, int osmo_apdu_segment_in(struct osmo_apdu_context *ac, const uint8_t *apdu_buf,
unsigned int apdu_len, bool new_apdu); unsigned int apdu_len, bool new_apdu);

View File

@@ -0,0 +1,73 @@
/* libisb utilities
*
* (C) 2010-2016 by Harald Welte <hwelte@hmw-consulting.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#pragma once
#include <libusb.h>
#define USB_MAX_PATH_LEN 20
struct dev_id {
uint16_t vendor_id;
uint16_t product_id;
};
/* Find any USB devices in the system matching the given Vendor and
* Product ID */
libusb_device **find_matching_usb_devs(const struct dev_id *dev_ids);
/* structure describing a single matching interface found */
struct usb_interface_match {
/* libusb device E*/
libusb_device *usb_dev;
/* Vendor ID of the device running matching interface */
uint16_t vendor;
/* Product ID of the device running matching interface */
uint16_t product;
/* USB Bus Address */
uint8_t addr;
/* physical path */
char path[USB_MAX_PATH_LEN];
/* configuration of matching interface */
uint8_t configuration;
/* interface number of matching interface */
uint8_t interface;
/* altsetting of matching interface */
uint8_t altsetting;
/* bInterfaceClass of matching interface */
uint8_t class;
/* bInterfaceSubClass of matching interface */
uint8_t sub_class;
/* bInterfaceProtocol of matching interface */
uint8_t protocol;
/* index of string descriptor of matching interface */
uint8_t string_idx;
};
int dev_find_matching_interfaces(libusb_device *dev, int class, int sub_class, int protocol,
struct usb_interface_match *out, unsigned int out_len);
int usb_match_interfaces(libusb_context *ctx, const struct dev_id *dev_ids,
int class, int sub_class, int protocol,
struct usb_interface_match *out, unsigned int out_len);
libusb_device_handle *usb_open_claim_interface(libusb_context *ctx,
const struct usb_interface_match *ifm);
int get_usb_ep_addrs(libusb_device_handle *devh, unsigned int if_num,
uint8_t *out, uint8_t *in, uint8_t *irq);

View File

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

View File

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

View File

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

View File

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

338
host/lib/libusb_util.c Normal file
View File

@@ -0,0 +1,338 @@
/* libusb utilities
*
* (C) 2010-2019 by Harald Welte <hwelte@hmw-consulting.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <libusb.h>
#include <osmocom/simtrace2/libusb_util.h>
static char path_buf[USB_MAX_PATH_LEN];
static char *get_path(libusb_device *dev)
{
#if (defined(LIBUSB_API_VERSION) && LIBUSB_API_VERSION >= 0x01000102) || (defined(LIBUSBX_API_VERSION) && LIBUSBX_API_VERSION >= 0x01000102)
uint8_t path[8];
int r,j;
r = libusb_get_port_numbers(dev, path, sizeof(path));
if (r > 0) {
sprintf(path_buf,"%d-%d",libusb_get_bus_number(dev),path[0]);
for (j = 1; j < r; j++){
sprintf(path_buf+strlen(path_buf),".%d",path[j]);
};
}
return path_buf;
#else
# warning "libusb too old - building without USB path support!"
return NULL;
#endif
}
static int match_dev_id(const struct libusb_device_descriptor *desc, const struct dev_id *id)
{
if ((desc->idVendor == id->vendor_id) && (desc->idProduct == id->product_id))
return 1;
return 0;
}
static int match_dev_ids(const struct libusb_device_descriptor *desc, const struct dev_id *ids)
{
const struct dev_id *id;
for (id = ids; id->vendor_id || id->product_id; id++) {
if (match_dev_id(desc, id))
return 1;
}
return 0;
}
libusb_device **find_matching_usb_devs(const struct dev_id *dev_ids)
{
libusb_device **list;
libusb_device **out = calloc(256, sizeof(libusb_device *));
libusb_device **cur = out;
unsigned int i;
int rc;
if (!out)
return NULL;
rc = libusb_get_device_list(NULL, &list);
if (rc <= 0) {
perror("No USB devices found");
free(out);
return NULL;
}
for (i = 0; list[i] != NULL; i++) {
struct libusb_device_descriptor dev_desc;
libusb_device *dev = list[i];
rc = libusb_get_device_descriptor(dev, &dev_desc);
if (rc < 0) {
perror("Couldn't get device descriptor\n");
libusb_unref_device(dev);
continue;
}
if (match_dev_ids(&dev_desc, dev_ids)) {
*cur = dev;
cur++;
/* FIXME: overflow check */
} else
libusb_unref_device(dev);
}
if (cur == out) {
libusb_free_device_list(list, 1);
free(out);
return NULL;
}
libusb_free_device_list(list, 0);
return out;
}
int dev_find_matching_interfaces(libusb_device *dev, int class, int sub_class, int protocol,
struct usb_interface_match *out, unsigned int out_len)
{
struct libusb_device_descriptor dev_desc;
int rc, i, out_idx = 0;
uint8_t addr;
char *path;
rc = libusb_get_device_descriptor(dev, &dev_desc);
if (rc < 0) {
perror("Couldn't get device descriptor\n");
return -EIO;
}
addr = libusb_get_device_address(dev);
path = get_path(dev);
/* iterate over all configurations */
for (i = 0; i < dev_desc.bNumConfigurations; i++) {
struct libusb_config_descriptor *conf_desc;
int j;
rc = libusb_get_config_descriptor(dev, i, &conf_desc);
if (rc < 0) {
fprintf(stderr, "Couldn't get config descriptor %u\n", i);
continue;
}
/* iterate over all interfaces */
for (j = 0; j < conf_desc->bNumInterfaces; j++) {
const struct libusb_interface *intf = &conf_desc->interface[j];
int k;
/* iterate over all alternate settings */
for (k = 0; k < intf->num_altsetting; k++) {
const struct libusb_interface_descriptor *if_desc;
if_desc = &intf->altsetting[k];
if (class >= 0 && if_desc->bInterfaceClass != class)
continue;
if (sub_class >= 0 && if_desc->bInterfaceSubClass != sub_class)
continue;
if (protocol >= 0 && if_desc->bInterfaceProtocol != protocol)
continue;
/* MATCH! */
out[out_idx].usb_dev = dev;
out[out_idx].vendor = dev_desc.idVendor;
out[out_idx].product = dev_desc.idProduct;
out[out_idx].addr = addr;
strncpy(out[out_idx].path, path, sizeof(out[out_idx].path)-1);
out[out_idx].path[sizeof(out[out_idx].path)-1] = '\0';
out[out_idx].configuration = conf_desc->bConfigurationValue;
out[out_idx].interface = if_desc->bInterfaceNumber;
out[out_idx].altsetting = if_desc->bAlternateSetting;
out[out_idx].class = if_desc->bInterfaceClass;
out[out_idx].sub_class = if_desc->bInterfaceSubClass;
out[out_idx].protocol = if_desc->bInterfaceProtocol;
out[out_idx].string_idx = if_desc->iInterface;
out_idx++;
if (out_idx >= out_len)
return out_idx;
}
}
}
return out_idx;
}
int usb_match_interfaces(libusb_context *ctx, const struct dev_id *dev_ids,
int class, int sub_class, int protocol,
struct usb_interface_match *out, unsigned int out_len)
{
struct usb_interface_match *out_cur = out;
unsigned int out_len_remain = out_len;
libusb_device **list;
libusb_device **dev;
list = find_matching_usb_devs(dev_ids);
if (!list)
return 0;
for (dev = list; *dev; dev++) {
int rc;
#if 0
struct libusb_device_descriptor dev_desc;
uint8_t ports[8];
uint8_t addr;
rc = libusb_get_device_descriptor(*dev, &dev_desc);
if (rc < 0) {
perror("Cannot get device descriptor");
continue;
}
addr = libusb_get_device_address(*dev);
rc = libusb_get_port_numbers(*dev, ports, sizeof(ports));
if (rc < 0) {
perror("Cannot get device path");
continue;
}
printf("Found USB Device %04x:%04x at address %d\n",
dev_desc.idVendor, dev_desc.idProduct, addr);
#endif
rc = dev_find_matching_interfaces(*dev, class, sub_class, protocol, out_cur, out_len_remain);
if (rc < 0)
continue;
out_cur += rc;
out_len_remain -= rc;
}
return out_len - out_len_remain;
}
libusb_device_handle *usb_open_claim_interface(libusb_context *ctx,
const struct usb_interface_match *ifm)
{
int rc, config;
struct dev_id dev_ids[] = { { ifm->vendor, ifm->product }, { 0, 0 } };
libusb_device **list;
libusb_device **dev;
libusb_device_handle *usb_devh = NULL;
list = find_matching_usb_devs(dev_ids);
if (!list) {
perror("No USB device with matching VID/PID");
return NULL;
}
for (dev = list; *dev; dev++) {
int addr;
char *path;
addr = libusb_get_device_address(*dev);
path = get_path(*dev);
if ((ifm->addr && addr == ifm->addr) ||
(strlen(ifm->path) && !strcmp(path, ifm->path))) {
rc = libusb_open(*dev, &usb_devh);
if (rc < 0) {
fprintf(stderr, "Cannot open device: %s\n", libusb_error_name(rc));
usb_devh = NULL;
break;
}
rc = libusb_get_configuration(usb_devh, &config);
if (rc < 0) {
fprintf(stderr, "Cannot get current configuration: %s\n", libusb_error_name(rc));
libusb_close(usb_devh);
usb_devh = NULL;
break;
}
if (config != ifm->configuration) {
rc = libusb_set_configuration(usb_devh, ifm->configuration);
if (rc < 0) {
fprintf(stderr, "Cannot set configuration: %s\n", libusb_error_name(rc));
libusb_close(usb_devh);
usb_devh = NULL;
break;
}
}
rc = libusb_claim_interface(usb_devh, ifm->interface);
if (rc < 0) {
fprintf(stderr, "Cannot claim interface: %s\n", libusb_error_name(rc));
libusb_close(usb_devh);
usb_devh = NULL;
break;
}
rc = libusb_set_interface_alt_setting(usb_devh, ifm->interface, ifm->altsetting);
if (rc < 0) {
fprintf(stderr, "Cannot set interface altsetting: %s\n", libusb_error_name(rc));
libusb_release_interface(usb_devh, ifm->interface);
libusb_close(usb_devh);
usb_devh = NULL;
break;
}
}
}
/* unref / free list */
for (dev = list; *dev; dev++)
libusb_unref_device(*dev);
free(list);
return usb_devh;
}
/*! \brief obtain the endpoint addresses for a given USB interface */
int get_usb_ep_addrs(libusb_device_handle *devh, unsigned int if_num,
uint8_t *out, uint8_t *in, uint8_t *irq)
{
libusb_device *dev = libusb_get_device(devh);
struct libusb_config_descriptor *cdesc;
const struct libusb_interface_descriptor *idesc;
const struct libusb_interface *iface;
int rc, l;
rc = libusb_get_active_config_descriptor(dev, &cdesc);
if (rc < 0)
return rc;
iface = &cdesc->interface[if_num];
/* FIXME: we assume there's no altsetting */
idesc = &iface->altsetting[0];
for (l = 0; l < idesc->bNumEndpoints; l++) {
const struct libusb_endpoint_descriptor *edesc = &idesc->endpoint[l];
switch (edesc->bmAttributes & 3) {
case LIBUSB_TRANSFER_TYPE_BULK:
if (edesc->bEndpointAddress & 0x80) {
if (in)
*in = edesc->bEndpointAddress;
} else {
if (out)
*out = edesc->bEndpointAddress;
}
break;
case LIBUSB_TRANSFER_TYPE_INTERRUPT:
if (irq)
*irq = edesc->bEndpointAddress;
break;
default:
break;
}
}
return 0;
}

View File

@@ -57,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");
} }
/*! \brief Transmit a given command to the SIMtrace2 device */
static void usb_out_xfer_cb(struct libusb_transfer *xfer) int osmo_st2_transp_tx_msg(struct osmo_st2_transport *transp, struct msgb *msg)
{ {
struct msgb *msg = xfer->user_data; int rc;
switch (xfer->status) { printf("<- %s\n", msgb_hexdump(msg));
case LIBUSB_TRANSFER_COMPLETED:
break; if (transp->udp_fd < 0) {
case LIBUSB_TRANSFER_NO_DEVICE: int xfer_len;
fprintf(stderr, "USB device disappeared\n");
exit(1); rc = libusb_bulk_transfer(transp->usb_devh, transp->usb_ep.out,
break; msgb_data(msg), msgb_length(msg),
default: &xfer_len, 100000);
fprintf(stderr, "USB OUT transfer failed, status=%u\n", xfer->status); } else {
exit(1); rc = write(transp->udp_fd, msgb_data(msg), msgb_length(msg));
break;
} }
msgb_free(msg);
libusb_free_transfer(xfer);
}
static int st2_transp_tx_msg_usb_async(struct osmo_st2_transport *transp, struct msgb *msg)
{
struct libusb_transfer *xfer;
int rc;
xfer = libusb_alloc_transfer(0);
OSMO_ASSERT(xfer);
xfer->dev_handle = transp->usb_devh;
xfer->flags = 0;
xfer->type = LIBUSB_TRANSFER_TYPE_BULK;
xfer->endpoint = transp->usb_ep.out;
xfer->timeout = 100000;
xfer->user_data = msg;
xfer->length = msgb_length(msg);
xfer->buffer = msgb_data(msg);
xfer->callback = usb_out_xfer_cb;
rc = libusb_submit_transfer(xfer);
OSMO_ASSERT(rc == 0);
return rc;
}
/*! \brief Transmit a given command to the SIMtrace2 device */
static int st2_transp_tx_msg_usb_sync(struct osmo_st2_transport *transp, struct msgb *msg)
{
int rc;
int xfer_len;
rc = libusb_bulk_transfer(transp->usb_devh, transp->usb_ep.out,
msgb_data(msg), msgb_length(msg),
&xfer_len, 100000);
msgb_free(msg); msgb_free(msg);
return rc; return rc;
} }
@@ -135,24 +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);
printf("SIMtrace <- %s\n", msgb_hexdump(msg));
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;
} }
/*********************************************************************** /***********************************************************************
@@ -256,21 +204,6 @@ int osmo_st2_cardem_request_set_atr(struct osmo_st2_cardem_inst *ci, const uint8
return osmo_st2_slot_tx_msg(ci->slot, msg, SIMTRACE_MSGC_CARDEM, SIMTRACE_MSGT_DT_CEMU_SET_ATR); return osmo_st2_slot_tx_msg(ci->slot, msg, SIMTRACE_MSGC_CARDEM, SIMTRACE_MSGT_DT_CEMU_SET_ATR);
} }
int osmo_st2_cardem_request_config(struct osmo_st2_cardem_inst *ci, uint32_t features)
{
struct msgb *msg = st_msgb_alloc();
struct cardemu_usb_msg_config *cfg;
cfg = (struct cardemu_usb_msg_config *) msgb_put(msg, sizeof(*cfg));
printf("<= %s(%08x)\n", __func__, features);
memset(cfg, 0, sizeof(*cfg));
cfg->features = features;
return osmo_st2_slot_tx_msg(ci->slot, msg, SIMTRACE_MSGC_CARDEM, SIMTRACE_MSGT_BD_CEMU_CONFIG);
}
/*********************************************************************** /***********************************************************************
* Modem Control protocol * Modem Control protocol
***********************************************************************/ ***********************************************************************/

View File

@@ -1,36 +0,0 @@
/* usb_util - USB related utilities for SIMtrace 2 USB devices
*
* (C) 2016-2019 by Harald Welte <hwelte@hmw-consulting.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <errno.h>
#include <getopt.h>
#include <osmocom/core/utils.h>
#include <osmocom/usb/libusb.h>
#include <osmocom/simtrace2/simtrace_usb.h>
/*! list of USB idVendor/idProduct tuples of devices using simtrace2 firmware */
const struct dev_id osmo_st2_compatible_dev_ids[] = {
{ USB_VENDOR_OPENMOKO, USB_PRODUCT_OWHW_SAM3 },
{ USB_VENDOR_OPENMOKO, USB_PRODUCT_QMOD_SAM3 },
{ USB_VENDOR_OPENMOKO, USB_PRODUCT_SIMTRACE2 },
{ 0, 0 }
};

View File

@@ -1,13 +1,15 @@
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include
AM_CFLAGS=-Wall -g $(LIBOSMOCORE_CFLAGS) $(LIBOSMOSIM_CFLAGS) $(LIBOSMOUSB_CFLAGS) $(LIBUSB_CFLAGS) $(COVERAGE_FLAGS) AM_CFLAGS=-Wall -g $(LIBOSMOCORE_CFLAGS) $(LIBOSMOSIM_CFLAGS) $(LIBUSB_CFLAGS) $(COVERAGE_FLAGS)
AM_LDFLAGS=$(COVERAGE_LDFLAGS) 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) $(LIBUSB_LIBS)
bin_PROGRAMS = simtrace2-cardem-pcsc simtrace2-list simtrace2-sniff 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

View File

@@ -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-2020 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
@@ -38,7 +38,7 @@
#include <libusb.h> #include <libusb.h>
#include <osmocom/usb/libusb.h> #include <osmocom/simtrace2/libusb_util.h>
#include <osmocom/simtrace2/simtrace2_api.h> #include <osmocom/simtrace2/simtrace2_api.h>
#include <osmocom/simtrace2/simtrace_prot.h> #include <osmocom/simtrace2/simtrace_prot.h>
#include <osmocom/simtrace2/apdu_dispatch.h> #include <osmocom/simtrace2/apdu_dispatch.h>
@@ -47,33 +47,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/select.h>
#include <osmocom/sim/class_tables.h> #include <osmocom/sim/class_tables.h>
#include <osmocom/sim/sim.h> #include <osmocom/sim/sim.h>
#define ATR_MAX_LEN 33
#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
*/
#define DEFAULT_ATR_STR "3B8080811FC759"
static void atr_update_csum(uint8_t *atr, unsigned int atr_len) static void atr_update_csum(uint8_t *atr, unsigned int atr_len)
{ {
uint8_t csum = 0; uint8_t csum = 0;
@@ -182,9 +158,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;
@@ -194,159 +167,21 @@ 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;
LOGCI(ci, LOGL_INFO, "SIMtrace IRQ STATUS: flags=0x%x, fi=%u, di=%u, wi=%u wtime=%u\n",
status->flags, status->F_index, status->D_index, status->wi,
status->waiting_time);
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-V\t--usb-vendor\tVENDOR_ID\n" "\t-V\t--usb-vendor\tVENDOR_ID\n"
"\t-P\t--usb-product\tPRODUCT_ID\n" "\t-P\t--usb-product\tPRODUCT_ID\n"
"\t-C\t--usb-config\tCONFIG_ID\n" "\t-C\t--usb-config\tCONFIG_ID\n"
@@ -359,12 +194,12 @@ 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' },
{ "usb-vendor", 1, 0, 'V' }, { "usb-vendor", 1, 0, 'V' },
{ "usb-product", 1, 0, 'P' }, { "usb-product", 1, 0, 'P' },
{ "usb-config", 1, 0, 'C' }, { "usb-config", 1, 0, 'C' },
@@ -377,9 +212,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;
}
} }
} }
@@ -415,32 +281,30 @@ 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 = DEFAULT_ATR_STR;
uint8_t real_atr[ATR_MAX_LEN];
int atr_len;
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; 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;
}
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:ak", 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);
@@ -451,15 +315,9 @@ 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;
case 'n':
reader_num = atoi(optarg);
break;
case 'V': case 'V':
vendor_id = strtol(optarg, NULL, 16); vendor_id = strtol(optarg, NULL, 16);
break; break;
@@ -484,24 +342,29 @@ int main(int argc, char **argv)
} }
} }
atr_len = osmo_hexparse(atr,real_atr,ATR_MAX_LEN); if (!remote_udp_host && (vendor_id < 0 || product_id < 0)) {
if (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;
rc = libusb_init(NULL); if (!remote_udp_host) {
if (rc < 0) { rc = libusb_init(NULL);
fprintf(stderr, "libusb initialization failed\n"); if (rc < 0) {
goto do_exit; fprintf(stderr, "libusb initialization failed\n");
goto do_exit;
}
} else {
transp->udp_fd = osmo_sock_init(AF_INET, SOCK_DGRAM, IPPROTO_UDP,
remote_udp_host, remote_udp_port+if_num,
OSMO_SOCK_F_CONNECT);
if (transp->udp_fd < 0) {
fprintf(stderr, "error binding UDP port\n");
goto do_exit;
}
} }
rc = osmo_st2_gsmtap_init(gsmtap_host); rc = osmo_st2_gsmtap_init(gsmtap_host);
@@ -510,7 +373,7 @@ int main(int argc, char **argv)
goto close_exit; goto close_exit;
} }
reader = osim_reader_open(OSIM_READER_DRV_PCSC, reader_num, "", NULL); reader = osim_reader_open(OSIM_READER_DRV_PCSC, 0, "", NULL);
if (!reader) { if (!reader) {
perror("unable to open PC/SC reader"); perror("unable to open PC/SC reader");
goto close_exit; goto close_exit;
@@ -531,43 +394,36 @@ int main(int argc, char **argv)
signal(SIGINT, &signal_handler); signal(SIGINT, &signal_handler);
do { do {
struct usb_interface_match _ifm, *ifm = &_ifm; if (transp->udp_fd < 0) {
ifm->vendor = vendor_id; struct usb_interface_match _ifm, *ifm = &_ifm;
ifm->product = product_id; ifm->vendor = vendor_id;
ifm->configuration = config_id; ifm->product = product_id;
ifm->interface = if_num; ifm->configuration = config_id;
ifm->altsetting = altsetting; ifm->interface = if_num;
ifm->addr = addr; ifm->altsetting = altsetting;
if (path) ifm->addr = addr;
osmo_strlcpy(ifm->path, path, sizeof(ifm->path)); if (path)
transp->udp_fd = -1; osmo_strlcpy(ifm->path, path, sizeof(ifm->path));
transp->usb_async = true; transp->usb_devh = usb_open_claim_interface(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_exit;
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 = get_usb_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;
}
} }
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;
}
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);
@@ -576,8 +432,9 @@ int main(int argc, char **argv)
if (!skip_atr) { if (!skip_atr) {
/* set the ATR */ /* set the ATR */
atr_update_csum(real_atr, atr_len); uint8_t real_atr[] = { 0x3B, 0x00 }; // the simplest ATR
osmo_st2_cardem_request_set_atr(ci, real_atr, atr_len); atr_update_csum(real_atr, sizeof(real_atr));
osmo_st2_cardem_request_set_atr(ci, real_atr, sizeof(real_atr));
} }
/* select remote (forwarded) SIM */ /* select remote (forwarded) SIM */
@@ -586,7 +443,8 @@ int main(int argc, char **argv)
run_mainloop(ci); run_mainloop(ci);
ret = 0; ret = 0;
libusb_release_interface(transp->usb_devh, 0); if (transp->udp_fd < 0)
libusb_release_interface(transp->usb_devh, 0);
close_exit: close_exit:
if (transp->usb_devh) if (transp->usb_devh)
libusb_close(transp->usb_devh); libusb_close(transp->usb_devh);
@@ -594,7 +452,8 @@ close_exit:
sleep(1); sleep(1);
} while (keep_running); } while (keep_running);
libusb_exit(NULL); if (transp->udp_fd < 0)
libusb_exit(NULL);
do_exit: do_exit:
return ret; return ret;
} }

View File

@@ -37,7 +37,7 @@
#include <libusb.h> #include <libusb.h>
#include <osmocom/usb/libusb.h> #include <osmocom/simtrace2/libusb_util.h>
#include <osmocom/simtrace2/simtrace_usb.h> #include <osmocom/simtrace2/simtrace_usb.h>
#include <osmocom/simtrace2/simtrace_prot.h> #include <osmocom/simtrace2/simtrace_prot.h>
@@ -61,19 +61,49 @@ struct st_transport {
}; };
const struct value_string change_flags[] = { const struct value_string change_flags[] = {
{ SNIFF_CHANGE_FLAG_CARD_INSERT, "card inserted" }, {
{ SNIFF_CHANGE_FLAG_CARD_EJECT, "card ejected" }, .value = SNIFF_CHANGE_FLAG_CARD_INSERT,
{ SNIFF_CHANGE_FLAG_RESET_ASSERT, "reset asserted" }, .str = "card inserted",
{ SNIFF_CHANGE_FLAG_RESET_DEASSERT, "reset de-asserted" }, },
{ SNIFF_CHANGE_FLAG_TIMEOUT_WT, "data transfer timeout" }, {
{ 0, NULL } .value = SNIFF_CHANGE_FLAG_CARD_EJECT,
.str = "card ejected",
},
{
.value = SNIFF_CHANGE_FLAG_RESET_ASSERT,
.str = "reset asserted",
},
{
.value = SNIFF_CHANGE_FLAG_RESET_DEASSERT,
.str = "reset de-asserted",
},
{
.value = SNIFF_CHANGE_FLAG_TIMEOUT_WT,
.str = "data transfer timeout",
},
{
.value = 0,
.str = NULL,
},
}; };
const struct value_string data_flags[] = { const struct value_string data_flags[] = {
{ SNIFF_DATA_FLAG_ERROR_INCOMPLETE, "incomplete" }, {
{ SNIFF_DATA_FLAG_ERROR_MALFORMED, "malformed" }, .value = SNIFF_DATA_FLAG_ERROR_INCOMPLETE,
{ SNIFF_DATA_FLAG_ERROR_CHECKSUM, "checksum error" }, .str = "incomplete",
{ 0, NULL } },
{
.value = SNIFF_DATA_FLAG_ERROR_MALFORMED,
.str = "malformed",
},
{
.value = SNIFF_DATA_FLAG_ERROR_CHECKSUM,
.str = "checksum error",
},
{
.value = 0,
.str = NULL,
},
}; };
static void print_flags(const struct value_string* flag_meanings, uint32_t nb_flags, uint32_t flags) { static void print_flags(const struct value_string* flag_meanings, uint32_t nb_flags, uint32_t flags) {
@@ -342,7 +372,7 @@ int main(int argc, char **argv)
while (1) { while (1) {
int option_index = 0; int option_index = 0;
int c = getopt_long(argc, argv, "hi:kV:P:C:I:S:A:", opts, &option_index); char c = getopt_long(argc, argv, "hi:kV:P:C:I:S:A:", opts, &option_index);
if (c == -1) if (c == -1)
break; break;
switch (c) { switch (c) {
@@ -384,7 +414,7 @@ int main(int argc, char **argv)
goto do_exit; goto do_exit;
} }
struct usb_interface_match ifm_scan[16]; struct usb_interface_match ifm_scan[16];
int num_interfaces = osmo_libusb_find_matching_interfaces(NULL, compatible_dev_ids, int num_interfaces = usb_match_interfaces(NULL, compatible_dev_ids,
USB_CLASS_PROPRIETARY, SIMTRACE_SNIFFER_USB_SUBCLASS, -1, ifm_scan, ARRAY_SIZE(ifm_scan)); USB_CLASS_PROPRIETARY, SIMTRACE_SNIFFER_USB_SUBCLASS, -1, ifm_scan, ARRAY_SIZE(ifm_scan));
if (num_interfaces <= 0) { if (num_interfaces <= 0) {
perror("No compatible USB devices found"); perror("No compatible USB devices found");
@@ -473,7 +503,7 @@ int main(int argc, char **argv)
signal(SIGINT, &signal_handler); signal(SIGINT, &signal_handler);
do { do {
_transp.usb_devh = osmo_libusb_open_claim_interface(NULL, NULL, &ifm_selected); _transp.usb_devh = usb_open_claim_interface(NULL, &ifm_selected);
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_exit; goto close_exit;
@@ -485,8 +515,8 @@ int main(int argc, char **argv)
goto close_exit; goto close_exit;
} }
rc = osmo_libusb_get_ep_addrs(_transp.usb_devh, ifm_selected.interface, &_transp.usb_ep.out, rc = get_usb_ep_addrs(_transp.usb_devh, ifm_selected.interface, &_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_exit; goto close_exit;

View File

@@ -23,7 +23,7 @@
#include <osmocom/core/utils.h> #include <osmocom/core/utils.h>
#include <osmocom/usb/libusb.h> #include <osmocom/simtrace2/libusb_util.h>
#include <osmocom/simtrace2/simtrace_usb.h> #include <osmocom/simtrace2/simtrace_usb.h>
static const struct dev_id compatible_dev_ids[] = { static const struct dev_id compatible_dev_ids[] = {
@@ -39,8 +39,8 @@ 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, compatible_dev_ids, rc = usb_match_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)
return rc; return rc;

285
host/src/usb2udp.c Normal file
View 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/simtrace2/simtrace_usb.h>
#include <osmocom/simtrace2/simtrace_prot.h>
#include <osmocom/simtrace2/libusb_util.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 = get_usb_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;
}