mirror of
https://gitea.osmocom.org/sim-card/simtrace2.git
synced 2026-03-17 13:48:32 +03:00
Compare commits
22 Commits
osmith/wip
...
kevin/card
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b149ea3039 | ||
|
|
6b0afb3761 | ||
|
|
90abc09cf3 | ||
|
|
76c2eebae2 | ||
|
|
e3d516745d | ||
|
|
0cbe9a4fb6 | ||
|
|
1a88fd8066 | ||
|
|
73d4d49b83 | ||
|
|
558f25237e | ||
|
|
7fd7674577 | ||
|
|
7a060da30f | ||
|
|
5b2ade08dd | ||
|
|
6470d999b7 | ||
|
|
46a1f167f7 | ||
|
|
0954e3b283 | ||
|
|
c2a3836777 | ||
|
|
a2b2df235a | ||
|
|
af7544aa9d | ||
|
|
f6f507ab3c | ||
|
|
844c6608cf | ||
|
|
8ed780ec35 | ||
|
|
ad3414fdf7 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -21,3 +21,4 @@ host/simtrace2-list
|
||||
host/simtrace2-remsim
|
||||
host/simtrace2-remsim-usb2udp
|
||||
usb_strings_generated.h
|
||||
firmware/usbstring/usbstring
|
||||
|
||||
@@ -25,7 +25,7 @@ export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH"
|
||||
export LD_LIBRARY_PATH="$inst/lib"
|
||||
|
||||
BUILDS=""
|
||||
BUILDS+="simtrace/dfu simtrace/cardem simtrace/trace " # simtrace/triple_play
|
||||
BUILDS+="simtrace/dfu simtrace/trace simtrace/cardem "
|
||||
BUILDS+="qmod/dfu qmod/cardem "
|
||||
BUILDS+="owhw/dfu owhw/cardem "
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ C_LIBUSB_DFU = dfu.c dfu_desc.c dfu_driver.c
|
||||
C_LIBCOMMON = string.c stdio.c fputs.c usb_buf.c ringbuffer.c pseudo_talloc.c host_communication.c
|
||||
|
||||
C_BOARD = $(notdir $(wildcard libboard/common/source/*.c))
|
||||
C_BOARD += $(notdir $(wildcard libboard/$(BOARD)/source/*.c))
|
||||
C_BOARD += $(notdir $(wildcard libboard/$(BOARD)/source/*.c))
|
||||
|
||||
C_APPLEVEL = $(notdir $(wildcard apps/$(APP)/*.c))
|
||||
|
||||
@@ -228,7 +228,7 @@ program:
|
||||
|
||||
SERIAL ?= /dev/ttyUSB0
|
||||
log:
|
||||
stty -F $(SERIAL) 115200
|
||||
stty -F $(SERIAL) 921600
|
||||
lsof $(SERIAL) && echo "log is already opened" || ( sed -u "s/\r//" $(SERIAL) | ts )
|
||||
|
||||
clean:
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
C_FILES += $(C_LIBUSB_RT)
|
||||
|
||||
C_FILES += card_emu.c cciddriver.c iso7816_4.c iso7816_fidi.c mitm.c mode_cardemu.c mode_ccid.c simtrace_iso7816.c sniffer.c tc_etu.c usb.c
|
||||
C_FILES += card_emu.c iso7816_3.c iso7816_4.c mode_cardemu.c simtrace_iso7816.c usb.c
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* SIMtrace 2 firmware card emulation application
|
||||
*
|
||||
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
|
||||
* (C) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
|
||||
* (C) 2018-2019, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -146,7 +146,8 @@ extern int main(void)
|
||||
unsigned int i = 0;
|
||||
|
||||
led_init();
|
||||
led_blink(LED_RED, BLINK_3O_5F);
|
||||
led_blink(LED_RED, BLINK_ALWAYS_ON);
|
||||
led_blink(LED_GREEN, BLINK_ALWAYS_ON);
|
||||
|
||||
/* Enable watchdog for 2000ms, with no window */
|
||||
WDT_Enable(WDT, WDT_MR_WDRSTEN | WDT_MR_WDDBGHLT | WDT_MR_WDIDLEHLT |
|
||||
@@ -158,7 +159,8 @@ extern int main(void)
|
||||
|
||||
printf("\n\r\n\r"
|
||||
"=============================================================================\n\r"
|
||||
"SIMtrace2 firmware " GIT_VERSION " (C) 2010-2016 by Harald Welte\n\r"
|
||||
"SIMtrace2 firmware " GIT_VERSION "\n\r"
|
||||
"(C) 2010-2017 by Harald Welte, 2018-2019 by Kevin Redon\n\r"
|
||||
"=============================================================================\n\r");
|
||||
|
||||
#if (TRACE_LEVEL >= TRACE_LEVEL_INFO)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* SIMtrace 2 firmware USB DFU bootloader
|
||||
*
|
||||
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
|
||||
* (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
|
||||
* (C) 2018-2019 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -66,7 +66,11 @@ int USBDFU_handle_dnload(uint8_t altif, unsigned int offset,
|
||||
WDT_Restart(WDT);
|
||||
}
|
||||
|
||||
printf("dnload(altif=%u, offset=%u, len=%u)\n\r", altif, offset, len);
|
||||
#if TRACE_LEVEL >= TRACE_LEVEL_INFO
|
||||
TRACE_INFO("dnload(altif=%u, offset=%u, len=%u)\n\r", altif, offset, len);
|
||||
#else
|
||||
printf("DL off=%u\n\r", offset);
|
||||
#endif
|
||||
|
||||
#ifdef PINS_LEDS
|
||||
PIO_Clear(&pinsLeds[LED_NUM_RED]);
|
||||
@@ -248,7 +252,8 @@ extern int main(void)
|
||||
|
||||
printf("\n\r\n\r"
|
||||
"=============================================================================\n\r"
|
||||
"DFU bootloader %s for board %s (C) 2010-2017 by Harald Welte\n\r"
|
||||
"DFU bootloader %s for board %s\n\r"
|
||||
"(C) 2010-2017 by Harald Welte, 2018-2019 by Kevin Redon\n\r"
|
||||
"=============================================================================\n\r",
|
||||
manifest_revision, manifest_board);
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
C_FILES += $(C_LIBUSB_RT)
|
||||
|
||||
C_FILES += card_emu.c cciddriver.c iso7816_4.c iso7816_fidi.c mitm.c mode_cardemu.c mode_ccid.c simtrace_iso7816.c sniffer.c tc_etu.c usb.c
|
||||
C_FILES += iso7816_4.c iso7816_fidi.c simtrace_iso7816.c sniffer.c usb.c
|
||||
|
||||
@@ -251,7 +251,7 @@ static void GetDescriptor(
|
||||
switch (type) {
|
||||
|
||||
case USBGenericDescriptor_DEVICE:
|
||||
TRACE_INFO_WP("Dev ");
|
||||
TRACE_DEBUG_WP("Dev ");
|
||||
|
||||
/* Adjust length and send descriptor */
|
||||
|
||||
@@ -263,7 +263,7 @@ static void GetDescriptor(
|
||||
break;
|
||||
|
||||
case USBGenericDescriptor_CONFIGURATION:
|
||||
TRACE_INFO_WP("Cfg ");
|
||||
TRACE_DEBUG_WP("Cfg ");
|
||||
|
||||
/* Adjust length and send descriptor */
|
||||
|
||||
@@ -280,7 +280,7 @@ static void GetDescriptor(
|
||||
break;
|
||||
|
||||
case USBGenericDescriptor_DEVICEQUALIFIER:
|
||||
TRACE_INFO_WP("Qua ");
|
||||
TRACE_DEBUG_WP("Qua ");
|
||||
|
||||
/* Check if descriptor exists */
|
||||
|
||||
@@ -301,7 +301,7 @@ static void GetDescriptor(
|
||||
break;
|
||||
|
||||
case USBGenericDescriptor_OTHERSPEEDCONFIGURATION:
|
||||
TRACE_INFO_WP("OSC ");
|
||||
TRACE_DEBUG_WP("OSC ");
|
||||
|
||||
/* Check if descriptor exists */
|
||||
|
||||
@@ -327,7 +327,7 @@ static void GetDescriptor(
|
||||
break;
|
||||
|
||||
case USBGenericDescriptor_STRING:
|
||||
TRACE_INFO_WP("Str%d ", indexRDesc);
|
||||
TRACE_DEBUG_WP("Str%d ", indexRDesc);
|
||||
|
||||
/* Check if descriptor exists */
|
||||
|
||||
@@ -504,13 +504,13 @@ void USBDDriver_RequestHandler(
|
||||
uint32_t length;
|
||||
uint32_t address;
|
||||
|
||||
TRACE_INFO_WP("Std ");
|
||||
TRACE_DEBUG_WP("Std ");
|
||||
|
||||
/* Check request code */
|
||||
switch (USBGenericRequest_GetRequest(pRequest)) {
|
||||
|
||||
case USBGenericRequest_GETDESCRIPTOR:
|
||||
TRACE_INFO_WP("gDesc ");
|
||||
TRACE_DEBUG_WP("gDesc ");
|
||||
|
||||
/* Send the requested descriptor */
|
||||
type = USBGetDescriptorRequest_GetDescriptorType(pRequest);
|
||||
@@ -520,7 +520,7 @@ void USBDDriver_RequestHandler(
|
||||
break;
|
||||
|
||||
case USBGenericRequest_SETADDRESS:
|
||||
TRACE_INFO_WP("sAddr ");
|
||||
TRACE_DEBUG_WP("sAddr ");
|
||||
|
||||
/* Sends a zero-length packet and then set the device address */
|
||||
address = USBSetAddressRequest_GetAddress(pRequest);
|
||||
@@ -528,7 +528,7 @@ void USBDDriver_RequestHandler(
|
||||
break;
|
||||
|
||||
case USBGenericRequest_SETCONFIGURATION:
|
||||
TRACE_INFO_WP("sCfg ");
|
||||
TRACE_DEBUG_WP("sCfg ");
|
||||
|
||||
/* Set the requested configuration */
|
||||
cfgnum = USBSetConfigurationRequest_GetConfiguration(pRequest);
|
||||
@@ -536,27 +536,27 @@ void USBDDriver_RequestHandler(
|
||||
break;
|
||||
|
||||
case USBGenericRequest_GETCONFIGURATION:
|
||||
TRACE_INFO_WP("gCfg ");
|
||||
TRACE_DEBUG_WP("gCfg ");
|
||||
|
||||
/* Send the current configuration number */
|
||||
GetConfiguration(pDriver);
|
||||
break;
|
||||
|
||||
case USBGenericRequest_GETSTATUS:
|
||||
TRACE_INFO_WP("gSta ");
|
||||
TRACE_DEBUG_WP("gSta ");
|
||||
|
||||
/* Check who is the recipient */
|
||||
switch (USBGenericRequest_GetRecipient(pRequest)) {
|
||||
|
||||
case USBGenericRequest_DEVICE:
|
||||
TRACE_INFO_WP("Dev ");
|
||||
TRACE_DEBUG_WP("Dev ");
|
||||
|
||||
/* Send the device status */
|
||||
GetDeviceStatus(pDriver);
|
||||
break;
|
||||
|
||||
case USBGenericRequest_ENDPOINT:
|
||||
TRACE_INFO_WP("Ept ");
|
||||
TRACE_DEBUG_WP("Ept ");
|
||||
|
||||
/* Send the endpoint status */
|
||||
eptnum = USBGenericRequest_GetEndpointNumber(pRequest);
|
||||
@@ -572,13 +572,13 @@ void USBDDriver_RequestHandler(
|
||||
break;
|
||||
|
||||
case USBGenericRequest_CLEARFEATURE:
|
||||
TRACE_INFO_WP("cFeat ");
|
||||
TRACE_DEBUG_WP("cFeat ");
|
||||
|
||||
/* Check which is the requested feature */
|
||||
switch (USBFeatureRequest_GetFeatureSelector(pRequest)) {
|
||||
|
||||
case USBFeatureRequest_ENDPOINTHALT:
|
||||
TRACE_INFO_WP("Hlt ");
|
||||
TRACE_DEBUG_WP("Hlt ");
|
||||
|
||||
/* Unhalt endpoint and send a zero-length packet */
|
||||
USBD_Unhalt(USBGenericRequest_GetEndpointNumber(pRequest));
|
||||
@@ -586,7 +586,7 @@ void USBDDriver_RequestHandler(
|
||||
break;
|
||||
|
||||
case USBFeatureRequest_DEVICEREMOTEWAKEUP:
|
||||
TRACE_INFO_WP("RmWU ");
|
||||
TRACE_DEBUG_WP("RmWU ");
|
||||
|
||||
/* Disable remote wake-up and send a zero-length packet */
|
||||
pDriver->isRemoteWakeUpEnabled = 0;
|
||||
@@ -602,13 +602,13 @@ void USBDDriver_RequestHandler(
|
||||
break;
|
||||
|
||||
case USBGenericRequest_SETFEATURE:
|
||||
TRACE_INFO_WP("sFeat ");
|
||||
TRACE_DEBUG_WP("sFeat ");
|
||||
|
||||
/* Check which is the selected feature */
|
||||
switch (USBFeatureRequest_GetFeatureSelector(pRequest)) {
|
||||
|
||||
case USBFeatureRequest_DEVICEREMOTEWAKEUP:
|
||||
TRACE_INFO_WP("RmWU ");
|
||||
TRACE_DEBUG_WP("RmWU ");
|
||||
|
||||
/* Enable remote wake-up and send a ZLP */
|
||||
pDriver->isRemoteWakeUpEnabled = 1;
|
||||
@@ -616,25 +616,25 @@ void USBDDriver_RequestHandler(
|
||||
break;
|
||||
|
||||
case USBFeatureRequest_ENDPOINTHALT:
|
||||
TRACE_INFO_WP("Halt ");
|
||||
TRACE_DEBUG_WP("Halt ");
|
||||
/* Halt endpoint */
|
||||
USBD_Halt(USBGenericRequest_GetEndpointNumber(pRequest));
|
||||
USBD_Write(0, 0, 0, 0, 0);
|
||||
break;
|
||||
case USBFeatureRequest_OTG_B_HNP_ENABLE:
|
||||
TRACE_INFO_WP("OTG_B_HNP_ENABLE ");
|
||||
TRACE_DEBUG_WP("OTG_B_HNP_ENABLE ");
|
||||
pDriver->otg_features_supported |=
|
||||
1<<USBFeatureRequest_OTG_B_HNP_ENABLE;
|
||||
USBD_Write(0, 0, 0, 0, 0);
|
||||
break;
|
||||
case USBFeatureRequest_OTG_A_HNP_SUPPORT:
|
||||
TRACE_INFO_WP("OTG_A_HNP_SUPPORT ");
|
||||
TRACE_DEBUG_WP("OTG_A_HNP_SUPPORT ");
|
||||
pDriver->otg_features_supported |=
|
||||
1<<USBFeatureRequest_OTG_A_HNP_SUPPORT;
|
||||
USBD_Write(0, 0, 0, 0, 0);
|
||||
break;
|
||||
case USBFeatureRequest_OTG_A_ALT_HNP_SUPPORT:
|
||||
TRACE_INFO_WP("OTG_A_ALT_HNP_SUPPORT ");
|
||||
TRACE_DEBUG_WP("OTG_A_ALT_HNP_SUPPORT ");
|
||||
pDriver->otg_features_supported |=
|
||||
1<<USBFeatureRequest_OTG_A_ALT_HNP_SUPPORT;
|
||||
USBD_Write(0, 0, 0, 0, 0);
|
||||
@@ -649,7 +649,7 @@ void USBDDriver_RequestHandler(
|
||||
break;
|
||||
|
||||
case USBGenericRequest_SETINTERFACE:
|
||||
TRACE_INFO_WP("sInterface ");
|
||||
TRACE_DEBUG_WP("sInterface ");
|
||||
|
||||
infnum = USBInterfaceRequest_GetInterface(pRequest);
|
||||
setting = USBInterfaceRequest_GetAlternateSetting(pRequest);
|
||||
@@ -657,7 +657,7 @@ void USBDDriver_RequestHandler(
|
||||
break;
|
||||
|
||||
case USBGenericRequest_GETINTERFACE:
|
||||
TRACE_INFO_WP("gInterface ");
|
||||
TRACE_DEBUG_WP("gInterface ");
|
||||
|
||||
infnum = USBInterfaceRequest_GetInterface(pRequest);
|
||||
GetInterface(pDriver, infnum);
|
||||
|
||||
@@ -14,5 +14,13 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
/** switch card lines to use physical or emulated card
|
||||
* @param[in] nr card interface number (i.e. slot)
|
||||
* @param[in] physical which physical interface to switch to (e.g. 0: physical, 1: virtual)
|
||||
* @return 0 on success, negative else
|
||||
*/
|
||||
int sim_switch_use_physical(unsigned int nr, int physical);
|
||||
/** initialise card switching capabilities
|
||||
* @return number of switchable card interfaces
|
||||
*/
|
||||
int sim_switch_init(void);
|
||||
|
||||
@@ -95,4 +95,7 @@
|
||||
#define CARDEMU_SECOND_UART
|
||||
#define DETECT_VCC_BY_ADC
|
||||
|
||||
/** sysmoQMOD only supports card emulation */
|
||||
#ifdef APPLICATION_cardem
|
||||
#define HAVE_CARDEM
|
||||
#endif
|
||||
|
||||
90
firmware/libboard/qmod/source/sim_switch.c
Normal file
90
firmware/libboard/qmod/source/sim_switch.c
Normal file
@@ -0,0 +1,90 @@
|
||||
/* Code to switch between local (physical) and remote (emulated) SIM
|
||||
*
|
||||
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#include "board.h"
|
||||
#include "trace.h"
|
||||
#include "led.h"
|
||||
#include "sim_switch.h"
|
||||
|
||||
#ifdef PIN_SIM_SWITCH1
|
||||
static const Pin pin_conn_usim1 = {PIO_PA20, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT};
|
||||
#endif
|
||||
#ifdef PIN_SIM_SWITCH2
|
||||
static const Pin pin_conn_usim2 = {PIO_PA28, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT};
|
||||
#endif
|
||||
|
||||
static int initialized = 0;
|
||||
|
||||
int sim_switch_use_physical(unsigned int nr, int physical)
|
||||
{
|
||||
const Pin *pin;
|
||||
enum led led;
|
||||
|
||||
if (!initialized) {
|
||||
TRACE_ERROR("Somebody forgot to call sim_switch_init()\r\n");
|
||||
sim_switch_init();
|
||||
}
|
||||
|
||||
TRACE_INFO("Modem %d: %s SIM\n\r", nr,
|
||||
physical ? "physical" : "virtual");
|
||||
|
||||
switch (nr) {
|
||||
#ifdef PIN_SIM_SWITCH1
|
||||
case 0:
|
||||
pin = &pin_conn_usim1;
|
||||
led = LED_USIM1;
|
||||
break;
|
||||
#endif
|
||||
#ifdef PIN_SIM_SWITCH2
|
||||
case 1:
|
||||
pin = &pin_conn_usim2;
|
||||
led = LED_USIM2;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
TRACE_ERROR("Invalid SIM%u\n\r", nr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (physical) {
|
||||
TRACE_INFO("%u: Use local/physical SIM\r\n", nr);
|
||||
PIO_Clear(pin);
|
||||
led_blink(led, BLINK_ALWAYS_ON);
|
||||
} else {
|
||||
TRACE_INFO("%u: Use remote/emulated SIM\r\n", nr);
|
||||
PIO_Set(pin);
|
||||
led_blink(led, BLINK_ALWAYS_OFF);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sim_switch_init(void)
|
||||
{
|
||||
int num_switch = 0;
|
||||
#ifdef PIN_SIM_SWITCH1
|
||||
PIO_Configure(&pin_conn_usim1, 1);
|
||||
num_switch++;
|
||||
#endif
|
||||
#ifdef PIN_SIM_SWITCH2
|
||||
PIO_Configure(&pin_conn_usim2, 1);
|
||||
num_switch++;
|
||||
#endif
|
||||
initialized = 1;
|
||||
return num_switch;
|
||||
}
|
||||
@@ -59,15 +59,15 @@
|
||||
|
||||
/** Phone connection **/
|
||||
/* Phone USIM slot 1 VCC pin (VCC_PHONE in schematic) */
|
||||
#define PIN_USIM1_VCC {PIO_PA25, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT}
|
||||
#define PIN_USIM1_VCC {PIO_PA25, PIOA, ID_PIOA, PIO_INPUT, PIO_IT_EDGE | PIO_DEGLITCH }
|
||||
/* Phone USIM slot 1 RST pin (active low; RST_PHONE in schematic) */
|
||||
#define PIN_USIM1_nRST {PIO_PA24, PIOA, ID_PIOA, PIO_INPUT, PIO_IT_RISE_EDGE | PIO_DEGLITCH }
|
||||
#define PIN_USIM1_nRST {PIO_PA24, PIOA, ID_PIOA, PIO_INPUT, PIO_IT_EDGE | PIO_DEGLITCH }
|
||||
/* Phone I/O data signal input/output (I/O_PHONE in schematic) */
|
||||
#define PIN_PHONE_IO {PIO_PA22A_TXD1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
|
||||
#define PIN_USIM1_IO {PIO_PA22A_TXD1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
|
||||
/* Phone CLK clock input (CLK_PHONE in schematic) */
|
||||
#define PIN_PHONE_CLK {PIO_PA23A_SCK1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
|
||||
/* Pin used for phone USIM slot 1 communication */
|
||||
#define PINS_USIM1 PIN_PHONE_IO, PIN_PHONE_CLK, PIN_PHONE_CLK_INPUT, PIN_USIM1_VCC, PIN_PHONE_IO_INPUT, PIN_USIM1_nRST
|
||||
#define PINS_USIM1 PIN_USIM1_IO, PIN_PHONE_CLK, PIN_PHONE_CLK_INPUT, PIN_USIM1_VCC, PIN_PHONE_IO_INPUT, PIN_USIM1_nRST
|
||||
/* Phone I/O data signal input/output (unused USART RX input; connected to I/O_PHONE in schematic) */
|
||||
#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) */
|
||||
@@ -105,6 +105,14 @@
|
||||
/* ISO7816-communication related pins */
|
||||
#define PINS_ISO7816 PIN_SIM_IO, PIN_SIM_CLK, PIN_ISO7816_RSTMC // SIM_PWEN_PIN, PIN_SIM_IO2, PIN_SIM_CLK2
|
||||
|
||||
/** card emulation configuration */
|
||||
/* Disable power converter 4.5-6V to 3.3V (active high) */
|
||||
#define PIN_SIM_PWEN_CARDEMU {SIM_PWEN, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
|
||||
/* Disable power switch to forward VCC_PHONE to VCC_SIM (active high) */
|
||||
#define PIN_VCC_FWD_CARDEMU {VCC_FWD, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
|
||||
/* Disable power to SIM */
|
||||
#define PINS_PWR_CARDEMU PIN_SIM_PWEN_CARDEMU, PIN_VCC_FWD_CARDEMU
|
||||
|
||||
/** External SPI flash interface **/
|
||||
/* SPI MISO pin definition */
|
||||
#define PIN_SPI_MISO {PIO_PA12A_MISO, PIOA, PIOA, PIO_PERIPH_A, PIO_PULLUP}
|
||||
@@ -138,10 +146,18 @@
|
||||
|
||||
/** Supported modes */
|
||||
/* SIMtrace board supports sniffer mode */
|
||||
#ifdef APPLICATION_trace
|
||||
#define HAVE_SNIFFER
|
||||
#endif
|
||||
/* SIMtrace board supports CCID mode */
|
||||
#ifdef APPLICATION_ccid
|
||||
//#define HAVE_CCID
|
||||
#endif
|
||||
/* SIMtrace board supports card emulation mode */
|
||||
//#define HAVE_CARDEM
|
||||
#ifdef APPLICATION_cardem
|
||||
#define HAVE_CARDEM
|
||||
#endif
|
||||
/* SIMtrace board supports man-in-the-middle mode */
|
||||
#ifdef APPLICATION_mitm
|
||||
//#define HAVE_MITM
|
||||
#endif
|
||||
|
||||
63
firmware/libboard/simtrace/source/sim_switch.c
Normal file
63
firmware/libboard/simtrace/source/sim_switch.c
Normal file
@@ -0,0 +1,63 @@
|
||||
/* Code to switch between local (physical) and remote (emulated) SIM
|
||||
*
|
||||
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
|
||||
* (C) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#include "board.h"
|
||||
#include "trace.h"
|
||||
#include "led.h"
|
||||
#include "sim_switch.h"
|
||||
|
||||
#ifdef PIN_SIM_SWITCH1
|
||||
static const Pin pin_conn_usim1 = {PIO_PA20, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT};
|
||||
#endif
|
||||
#ifdef PIN_SIM_SWITCH2
|
||||
static const Pin pin_conn_usim2 = {PIO_PA28, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT};
|
||||
#endif
|
||||
|
||||
static int initialized = 0;
|
||||
|
||||
int sim_switch_use_physical(unsigned int nr, int physical)
|
||||
{
|
||||
const Pin pin_sc = PIN_SC_SW_DEFAULT; // pin to control bus switch for VCC/RST/CLK signals
|
||||
const Pin pin_io = PIN_IO_SW_DEFAULT; // pin to control bus switch for I/O signal
|
||||
|
||||
if (nr > 0) {
|
||||
TRACE_ERROR("SIM interface for Modem %d can't be switched\r\n", nr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
TRACE_INFO("Modem %u: %s SIM\n\r", nr, physical ? "physical" : "virtual");
|
||||
|
||||
if (physical) {
|
||||
TRACE_INFO("%u: Use local/physical SIM\r\n", nr);
|
||||
PIO_Set(&pin_sc);
|
||||
PIO_Set(&pin_io);
|
||||
} else {
|
||||
TRACE_INFO("%u: Use remote/emulated SIM\r\n", nr);
|
||||
PIO_Clear(&pin_sc);
|
||||
PIO_Clear(&pin_io);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sim_switch_init(void)
|
||||
{
|
||||
// the bus switch is already initialised
|
||||
return 1; // SIMtrace hardware has only one switchable interface
|
||||
}
|
||||
@@ -48,10 +48,41 @@ struct llist_head *card_emu_get_uart_tx_queue(struct card_handle *ch);
|
||||
void card_emu_have_new_uart_tx(struct card_handle *ch);
|
||||
void card_emu_report_status(struct card_handle *ch);
|
||||
|
||||
/*! call when the waiting time has half-expired
|
||||
* param[in] ch card for which the waiting time half expired
|
||||
*/
|
||||
void card_emu_wt_halfed(struct card_handle *ch);
|
||||
/*! call when the waiting time has expired
|
||||
* param[in] ch card for which the waiting time expired
|
||||
*/
|
||||
void card_emu_wt_expired(struct card_handle *ch);
|
||||
|
||||
#define ENABLE_TX 0x01
|
||||
#define ENABLE_RX 0x02
|
||||
|
||||
int card_emu_uart_update_fidi(uint8_t uart_chan, unsigned int fidi);
|
||||
// the following functions are callbacks implement in mode_cardemu.c
|
||||
|
||||
/*! update F and D on USART peripheral
|
||||
* @param[in] usart USART peripheral to configure
|
||||
* @param[in] f clock rate conversion integer F value
|
||||
* @param[in] d baud rate adjustment factor D value
|
||||
* @note this should happen after reset and protocol select (through PPS or implicit)
|
||||
*/
|
||||
void card_emu_uart_update_fd(uint8_t uart_chan, uint16_t f, uint8_t d);
|
||||
/*! update WT on USART peripheral
|
||||
* @param[in] usart USART peripheral to configure
|
||||
* @param[in] wt inactivity Waiting Time before card_emu_wt_expired is called (0 to disable)
|
||||
*/
|
||||
void card_emu_uart_update_wt(uint8_t uart_chan, uint32_t wt);
|
||||
/*! reset waiting timeout count down on USART peripheral
|
||||
* @param[in] usart USART peripheral to configure
|
||||
*/
|
||||
void card_emu_uart_reset_wt(uint8_t uart_chan);
|
||||
/*! set I/O line high
|
||||
* @param[in] usart USART peripheral to configure
|
||||
* @param[in] set if I/O line should be set high (true), or cleared low (false)
|
||||
*/
|
||||
void card_emu_uart_io_set(uint8_t uart_chan, bool set);
|
||||
int card_emu_uart_tx(uint8_t uart_chan, uint8_t byte);
|
||||
void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx);
|
||||
void card_emu_uart_wait_tx_idle(uint8_t uart_chan);
|
||||
|
||||
98
firmware/libcommon/include/iso7816_3.h
Normal file
98
firmware/libcommon/include/iso7816_3.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (C) 2019 sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
/* this library provides utilities to handle the ISO-7816 part 3 communication aspects (e.g. related to F and D) */
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/** default clock rate conversion integer Fd
|
||||
* @implements ISO/IEC 7816-3:2006(E) section 8.1
|
||||
*/
|
||||
#define ISO7816_3_DEFAULT_FD 372
|
||||
/** default baud rate adjustment factor Dd
|
||||
* @implements ISO/IEC 7816-3:2006(E) section 8.1
|
||||
*/
|
||||
#define ISO7816_3_DEFAULT_DD 1
|
||||
/** default clock rate conversion integer Fi
|
||||
* @implements ISO/IEC 7816-3:2006(E) section 8.3
|
||||
* @note non-default value is optionally specified in TA1
|
||||
*/
|
||||
#define ISO7816_3_DEFAULT_FI 372
|
||||
/** default baud rate adjustment factor Di
|
||||
* @implements ISO/IEC 7816-3:2006(E) section 8.3
|
||||
* @note non-default value is optionally specified in TA1
|
||||
*/
|
||||
#define ISO7816_3_DEFAULT_DI 1
|
||||
/** default maximum clock frequency, in Hz
|
||||
* @implements ISO/IEC 7816-3:2006(E) section 8.3
|
||||
* @note non-default value is optionally specified in TA1
|
||||
*/
|
||||
#define ISO7816_3_DEFAULT_FMAX 5000000UL
|
||||
/** default Waiting Integer (WI) value for T=0
|
||||
* @implements ISO/IEC 7816-3:2006(E) section 10.2
|
||||
* @note non-default value is optionally specified in TC2
|
||||
*/
|
||||
#define ISO7816_3_DEFAULT_WI 10
|
||||
/** default Waiting Time (WT) value, in ETU
|
||||
* @implements ISO/IEC 7816-3:2006(E) section 8.1
|
||||
* @note depends on Fi, Di, and WI if protocol T=0 is selected
|
||||
*/
|
||||
#define ISO7816_3_DEFAULT_WT 9600
|
||||
|
||||
/** Table encoding the clock rate conversion integer Fi
|
||||
* @note Fi is indicated in TA1, but the same table is used for F and Fn during PPS
|
||||
* @implements ISO/IEC 7816-3:2006(E) table 7
|
||||
*/
|
||||
extern const uint16_t iso7816_3_fi_table[];
|
||||
|
||||
/** Table encoding the maximum clock frequency f_max in Hz
|
||||
* @implements ISO/IEC 7816-3:2006(E) table 7
|
||||
* @note f_max is indicated in TA1, but the same table is used for F and Fn during PPS
|
||||
*/
|
||||
extern const uint32_t iso7816_3_fmax_table[];
|
||||
|
||||
/** Table encoding the baud rate adjust integer Di
|
||||
* @implements ISO/IEC 7816-3:2006(E) table 8
|
||||
* @note Di is indicated in TA1, but the same table is used for D and Dn during PPS
|
||||
*/
|
||||
extern const uint8_t iso7816_3_di_table[];
|
||||
|
||||
/* verify if the clock rate conversion integer F value is valid
|
||||
* @param[in] f F value to be validated
|
||||
* @return if F value is valid
|
||||
* @note only values in ISO/IEC 7816-3:2006(E) table 7 are valid
|
||||
*/
|
||||
bool iso7816_3_valid_f(uint16_t f);
|
||||
/* verify if the baud rate adjustment factor D value is valid
|
||||
* @param[in] d D value to be validated
|
||||
* @return if D value is valid
|
||||
* @note only values in ISO/IEC 7816-3:2006(E) table 8 are valid
|
||||
*/
|
||||
bool iso7816_3_valid_d(uint8_t d);
|
||||
/** calculate Waiting Time (WT)
|
||||
* @param[in] wi Waiting Integer
|
||||
* @param[in] fi clock rate conversion integer Fi value
|
||||
* @param[in] di baud rate adjustment factor Di value
|
||||
* @param[in] f clock rate conversion integer F value
|
||||
* @param[in] d baud rate adjustment factor D value
|
||||
* @return Waiting Time WT, in ETU, or < 0 on error (see code for return codes)
|
||||
* @note this should happen after reset and T=0 protocol select (through PPS or implicit)
|
||||
* @implements ISO/IEC 7816-3:2006(E) section 8.1 and 10.2
|
||||
*/
|
||||
int32_t iso7816_3_calculate_wt(uint8_t wi, uint16_t fi, uint8_t di, uint16_t f, uint8_t d);
|
||||
@@ -228,11 +228,10 @@ struct cardemu_usb_msg_status {
|
||||
uint32_t flags;
|
||||
/* phone-applied target voltage in mV */
|
||||
uint16_t voltage_mv;
|
||||
/* Fi/Di related information */
|
||||
uint8_t fi;
|
||||
uint8_t di;
|
||||
uint8_t wi;
|
||||
uint32_t waiting_time;
|
||||
uint8_t f; /*!< index of F and f_max values as encoded in ISO/IEC 7816-3:2006(E) Table 7 */
|
||||
uint8_t d; /*!< index of D value as encoded in ISO/IEC 7816-3:2006(E) Table 8 */
|
||||
uint8_t wi; /*!< Waiting Integer as defined in ISO/IEC 7816-3:2006(E) Section 10.2 */
|
||||
uint32_t wt; /*!< Waiting Time in ETU as defined in ISO/IEC 7816-3:2006(E) Section 8.1 */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* CEMU_USB_MSGT_DO_PTS */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* ISO7816-3 state machine for the card side
|
||||
*
|
||||
* (C) 2010-2017 by Harald Welte <laforge@gnumonks.org>
|
||||
* (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
|
||||
* (C) 2018-2019 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -26,15 +26,13 @@
|
||||
|
||||
#include "utils.h"
|
||||
#include "trace.h"
|
||||
#include "iso7816_fidi.h"
|
||||
#include "tc_etu.h"
|
||||
#include "iso7816_3.h"
|
||||
#include "card_emu.h"
|
||||
#include "simtrace_prot.h"
|
||||
#include "usb_buf.h"
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/core/msgb.h>
|
||||
|
||||
|
||||
#define NUM_SLOTS 2
|
||||
|
||||
#define ISO7816_3_INIT_WTIME 9600
|
||||
@@ -186,18 +184,53 @@ struct card_handle {
|
||||
uint8_t in_reset; /* 1 = RST low, 0 = RST high */
|
||||
uint8_t clocked; /* 1 = active, 0 = inactive */
|
||||
|
||||
/* timing parameters, from PTS */
|
||||
uint8_t fi;
|
||||
uint8_t di;
|
||||
uint8_t wi;
|
||||
|
||||
uint8_t tc_chan; /* TC channel number */
|
||||
uint8_t uart_chan; /* UART channel */
|
||||
|
||||
uint8_t in_ep; /* USB IN EP */
|
||||
uint8_t irq_ep; /* USB IN EP */
|
||||
|
||||
uint32_t waiting_time; /* in clocks */
|
||||
/*! clock rate conversion integer F
|
||||
* @implements ISO/IEC 7816-3:2006(E) section 7.1
|
||||
* @note this represents the current value used
|
||||
*/
|
||||
uint16_t f;
|
||||
/*! baud rate adjustment factor D
|
||||
* @implements ISO/IEC 7816-3:2006(E) section 7.1
|
||||
* @note this represents the current value used
|
||||
*/
|
||||
uint8_t d;
|
||||
/*! clock frequency in Hz
|
||||
* @implements ISO/IEC 7816-3:2006(E) section 7.1
|
||||
* @note the USART peripheral in slave mode does not provide the current value. we could measure it but this is not really useful. instead we remember the maximum possible value corresponding to the selected F value
|
||||
*/
|
||||
uint32_t f_cur;
|
||||
/*! clock rate conversion integer Fi
|
||||
* @implements ISO/IEC 7816-3:2006(E) Table 7
|
||||
* @note this represents the maximum value supported by the card, and can be indicated in TA1
|
||||
* @note this value can be set in TA1
|
||||
*/
|
||||
uint16_t fi;
|
||||
/*! baud rate adjustment factor Di
|
||||
* @implements ISO/IEC 7816-3:2006(E) Table 8
|
||||
* @note this represents the maximum value supported by the card, and can be indicated in TA1
|
||||
*/
|
||||
uint8_t di;
|
||||
/*! clock frequency, in Hz
|
||||
* @implements ISO/IEC 7816-3:2006(E) Table 7
|
||||
* @note this represents the maximum value supported by the card, and can be indicated in TA1
|
||||
*/
|
||||
uint32_t f_max;
|
||||
/*! Waiting Integer
|
||||
* @implements ISO/IEC 7816-3:2006(E) Section 10.2
|
||||
* @note this value can be set in TA2
|
||||
*/
|
||||
uint8_t wi;
|
||||
/*! Waiting Time, in ETU
|
||||
* @implements ISO/IEC 7816-3:2006(E) Section 8.1
|
||||
* @note this depends on Fi, Di, and WI if T=0 is used
|
||||
*/
|
||||
uint32_t wt;
|
||||
|
||||
/* ATR state machine */
|
||||
struct {
|
||||
@@ -345,23 +378,6 @@ static void flush_pts(struct card_handle *ch)
|
||||
usb_buf_upd_len_and_submit(msg);
|
||||
}
|
||||
|
||||
static void emu_update_fidi(struct card_handle *ch)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = compute_fidi_ratio(ch->fi, ch->di);
|
||||
if (rc > 0 && rc < 0x400) {
|
||||
TRACE_INFO("%u: computed Fi(%u) Di(%u) ratio: %d\r\n",
|
||||
ch->num, ch->fi, ch->di, rc);
|
||||
/* make sure UART uses new F/D ratio */
|
||||
card_emu_uart_update_fidi(ch->uart_chan, rc);
|
||||
/* notify ETU timer about this */
|
||||
tc_etu_set_etu(ch->tc_chan, rc);
|
||||
} else
|
||||
TRACE_INFO("%u: computed FiDi ration %d unsupported\r\n",
|
||||
ch->num, rc);
|
||||
}
|
||||
|
||||
/* Update the ISO 7816-3 TPDU receiver state */
|
||||
static void card_set_state(struct card_handle *ch,
|
||||
enum iso7816_3_card_state new_state)
|
||||
@@ -378,31 +394,38 @@ static void card_set_state(struct card_handle *ch,
|
||||
case ISO_S_WAIT_POWER:
|
||||
case ISO_S_WAIT_CLK:
|
||||
case ISO_S_WAIT_RST:
|
||||
/* disable Rx and Tx of UART */
|
||||
card_emu_uart_enable(ch->uart_chan, 0);
|
||||
card_emu_uart_enable(ch->uart_chan, 0); // disable Rx and Tx of UART
|
||||
card_emu_uart_update_wt(ch->uart_chan, 0); // disable timeout
|
||||
if (ISO_S_WAIT_POWER == new_state) {
|
||||
card_emu_uart_io_set(ch->uart_chan, false); // pull I/O line low
|
||||
} else {
|
||||
card_emu_uart_io_set(ch->uart_chan, true); // pull I/O line high
|
||||
}
|
||||
break;
|
||||
case ISO_S_WAIT_ATR:
|
||||
/* Reset to initial Fi / Di ratio */
|
||||
ch->fi = 1;
|
||||
ch->di = 1;
|
||||
emu_update_fidi(ch);
|
||||
// reset the ETU-related values
|
||||
ch->f = ISO7816_3_DEFAULT_FD;
|
||||
ch->d = ISO7816_3_DEFAULT_DD;
|
||||
card_emu_uart_update_fd(ch->uart_chan, ch->f, ch->d); // set baud rate
|
||||
|
||||
// reset values optionally specified in the ATR
|
||||
ch->fi = ISO7816_3_DEFAULT_FI;
|
||||
ch->di = ISO7816_3_DEFAULT_DI;
|
||||
ch->wi = ISO7816_3_DEFAULT_WI;
|
||||
int32_t wt = iso7816_3_calculate_wt(ch->wi, ch->fi, ch->di, ch->f, ch->d); // get default waiting time
|
||||
if (wt <= 0) {
|
||||
TRACE_FATAL("%u: invalid WT %ld\r\n", ch->num, wt);
|
||||
}
|
||||
ch->wt = wt;
|
||||
card_emu_uart_enable(ch->uart_chan, ENABLE_TX); // enable TX to be able to use the timeout
|
||||
/* the ATR should only be sent 400 to 40k clock cycles after the RESET.
|
||||
* we use the tc_etu mechanism to wait this time.
|
||||
* since the initial ETU is Fd=372/Dd=1 clock cycles long, we have to wait 2-107 ETU.
|
||||
*/
|
||||
tc_etu_set_wtime(ch->tc_chan, 2);
|
||||
/* ensure the TC_ETU timer is enabled */
|
||||
tc_etu_enable(ch->tc_chan);
|
||||
card_emu_uart_update_wt(ch->uart_chan, 2);
|
||||
break;
|
||||
case ISO_S_IN_ATR:
|
||||
/* initialize to default WI, this will be overwritten if we
|
||||
* send TC2, and it will be programmed into hardware after
|
||||
* ATR is finished */
|
||||
ch->wi = ISO7816_3_DEFAULT_WI;
|
||||
/* update waiting time to initial waiting time */
|
||||
ch->waiting_time = ISO7816_3_INIT_WTIME;
|
||||
/* set initial waiting time */
|
||||
tc_etu_set_wtime(ch->tc_chan, ch->waiting_time);
|
||||
// FIXME disable timeout while sending ATR
|
||||
/* Set ATR sub-state to initial state */
|
||||
ch->atr.idx = 0;
|
||||
/* enable USART transmission to reader */
|
||||
@@ -448,7 +471,6 @@ static int tx_byte_atr(struct card_handle *ch)
|
||||
return 1;
|
||||
} else { /* The ATR has been completely transmitted */
|
||||
/* search for TC2 to updated WI */
|
||||
ch->wi = ISO7816_3_DEFAULT_WI;
|
||||
if (ch->atr.len >= 2 && ch->atr.atr[1] & 0xf0) { /* Y1 has some data */
|
||||
uint8_t atr_td1 = 2;
|
||||
if (ch->atr.atr[1] & 0x10) { /* TA1 is present */
|
||||
@@ -477,9 +499,7 @@ static int tx_byte_atr(struct card_handle *ch)
|
||||
}
|
||||
}
|
||||
}
|
||||
/* update waiting time (see ISO 7816-3 10.2) */
|
||||
ch->waiting_time = ch->wi * 960 * ch->fi;
|
||||
tc_etu_set_wtime(ch->tc_chan, ch->waiting_time);
|
||||
/* FIXME update waiting time in case of card is specific mode */
|
||||
/* reset PTS to initial state */
|
||||
set_pts_state(ch, PTS_S_WAIT_REQ_PTSS);
|
||||
/* go to next state */
|
||||
@@ -546,9 +566,12 @@ from_pts3:
|
||||
return PTS_S_WAIT_REQ_PCK | is_resp;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
process_byte_pts(struct card_handle *ch, uint8_t byte)
|
||||
/*! process incoming PTS byte
|
||||
* @param[in] ch card handle on which the byte has been received
|
||||
* @param[in] byte received PTS byte
|
||||
* @return new iso7816_3_card_state or -1 at the end of PTS request
|
||||
*/
|
||||
static int process_byte_pts(struct card_handle *ch, uint8_t byte)
|
||||
{
|
||||
switch (ch->pts.state) {
|
||||
case PTS_S_WAIT_REQ_PTSS:
|
||||
@@ -575,7 +598,7 @@ process_byte_pts(struct card_handle *ch, uint8_t byte)
|
||||
set_pts_state(ch, PTS_S_WAIT_REQ_PTSS);
|
||||
return ISO_S_WAIT_TPDU;
|
||||
}
|
||||
/* FIXME: check if proposal matches capabilities in ATR */
|
||||
/* FIXME check if proposal matches capabilities in TA1 */
|
||||
memcpy(ch->pts.resp, ch->pts.req, sizeof(ch->pts.resp));
|
||||
break;
|
||||
default:
|
||||
@@ -614,11 +637,17 @@ static int tx_byte_pts(struct card_handle *ch)
|
||||
break;
|
||||
case PTS_S_WAIT_RESP_PTS1:
|
||||
byte = ch->pts.resp[_PTS1];
|
||||
/* This must be TA1 */
|
||||
ch->fi = byte >> 4;
|
||||
ch->di = byte & 0xf;
|
||||
TRACE_DEBUG("%u: found Fi=%u Di=%u\r\n", ch->num,
|
||||
ch->fi, ch->di);
|
||||
// TODO the value should have been validated when receiving the request
|
||||
ch->f = iso7816_3_fi_table[byte >> 4]; // save selected Fn
|
||||
if (0 == ch->f) {
|
||||
TRACE_ERROR("%u: invalid F index in PPS response: %u\r\n", ch->num, byte >> 4);
|
||||
// TODO become unresponsive to signal error condition
|
||||
}
|
||||
ch->d = iso7816_3_di_table[byte & 0xf]; // save selected Dn
|
||||
if (0 == ch->d) {
|
||||
TRACE_ERROR("%u: invalid D index in PPS response: %u\r\n", ch->num, byte & 0xf);
|
||||
// TODO become unresponsive to signal error condition
|
||||
}
|
||||
break;
|
||||
case PTS_S_WAIT_RESP_PTS2:
|
||||
byte = ch->pts.resp[_PTS2];
|
||||
@@ -643,8 +672,15 @@ static int tx_byte_pts(struct card_handle *ch)
|
||||
switch (ch->pts.state) {
|
||||
case PTS_S_WAIT_RESP_PCK:
|
||||
card_emu_uart_wait_tx_idle(ch->uart_chan);
|
||||
/* update baud rate generator with Fi/Di */
|
||||
emu_update_fidi(ch);
|
||||
card_emu_uart_update_fd(ch->uart_chan, ch->f, ch->d); // set selected baud rate
|
||||
int32_t wt = iso7816_3_calculate_wt(ch->wi, ch->fi, ch->di, ch->f, ch->d); // get new waiting time
|
||||
if (wt <= 0) {
|
||||
TRACE_ERROR("%u: invalid WT calculated: %ld\r\n", ch->num, wt);
|
||||
// TODO become unresponsive to signal error condition
|
||||
} else {
|
||||
ch->wt = wt;
|
||||
}
|
||||
// FIXME disable WT
|
||||
/* Wait for the next TPDU */
|
||||
card_set_state(ch, ISO_S_WAIT_TPDU);
|
||||
set_pts_state(ch, PTS_S_WAIT_REQ_PTSS);
|
||||
@@ -715,6 +751,10 @@ static void set_tpdu_state(struct card_handle *ch, enum tpdu_state new_ts)
|
||||
{
|
||||
if (ch->tpdu.state == new_ts)
|
||||
return;
|
||||
if (ISO_S_IN_TPDU != ch->state && ISO_S_WAIT_TPDU != ch->state) {
|
||||
TRACE_ERROR("%u: setting TPDU state in %s state\r\n", ch->num,
|
||||
get_value_string(iso7816_3_card_state_names, ch->state));
|
||||
}
|
||||
|
||||
TRACE_DEBUG("%u: 7816 TPDU state %s -> %s\r\n", ch->num,
|
||||
get_value_string(tpdu_state_names, ch->tpdu.state),
|
||||
@@ -722,15 +762,20 @@ static void set_tpdu_state(struct card_handle *ch, enum tpdu_state new_ts)
|
||||
ch->tpdu.state = new_ts;
|
||||
|
||||
switch (new_ts) {
|
||||
case TPDU_S_WAIT_CLA:
|
||||
case TPDU_S_WAIT_RX:
|
||||
card_emu_uart_enable(ch->uart_chan, ENABLE_RX);
|
||||
case TPDU_S_WAIT_CLA: // we will be waiting for the next incoming TDPU
|
||||
card_emu_uart_enable(ch->uart_chan, ENABLE_RX); // switch back to receiving mode
|
||||
card_emu_uart_update_wt(ch->uart_chan, 0); // disable waiting time since we don't expect any data
|
||||
break;
|
||||
case TPDU_S_WAIT_INS: // the reader started sending the TPDU header
|
||||
card_emu_uart_update_wt(ch->uart_chan, ch->wt); // start waiting for the rest of the header/body
|
||||
break;
|
||||
case TPDU_S_WAIT_RX: // the reader should send us the TPDU body data
|
||||
card_emu_uart_enable(ch->uart_chan, ENABLE_RX); // switch to receive mode to receive the body
|
||||
card_emu_uart_update_wt(ch->uart_chan, ch->wt); // start waiting for the rest body
|
||||
break;
|
||||
case TPDU_S_WAIT_PB:
|
||||
/* we just completed the TPDU header from reader to card
|
||||
* and now need to disable the receiver, enable the
|
||||
* transmitter and transmit the procedure byte */
|
||||
card_emu_uart_enable(ch->uart_chan, ENABLE_TX);
|
||||
card_emu_uart_enable(ch->uart_chan, ENABLE_TX); // header is completely received, now we need to transmit the procedure byte
|
||||
card_emu_uart_update_wt(ch->uart_chan, ch->wt); // prepare to extend the waiting time once half of it is reached
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -1009,11 +1054,11 @@ void card_emu_report_status(struct card_handle *ch)
|
||||
sts->flags |= CEMU_STATUS_F_CLK_ACTIVE;
|
||||
if (ch->in_reset)
|
||||
sts->flags |= CEMU_STATUS_F_RESET_ACTIVE;
|
||||
/* FIXME: voltage + card insert */
|
||||
sts->fi = ch->fi;
|
||||
sts->di = ch->di;
|
||||
/* FIXME set voltage and card insert values */
|
||||
sts->f = ch->f;
|
||||
sts->d = ch->d;
|
||||
sts->wi = ch->wi;
|
||||
sts->waiting_time = ch->waiting_time;
|
||||
sts->wt = ch->wt;
|
||||
|
||||
usb_buf_upd_len_and_submit(msg);
|
||||
}
|
||||
@@ -1025,7 +1070,6 @@ void card_emu_io_statechg(struct card_handle *ch, enum card_io io, int active)
|
||||
case CARD_IO_VCC:
|
||||
if (active == 0 && ch->vcc_active == 1) {
|
||||
TRACE_INFO("%u: VCC deactivated\r\n", ch->num);
|
||||
tc_etu_disable(ch->tc_chan);
|
||||
card_set_state(ch, ISO_S_WAIT_POWER);
|
||||
} else if (active == 1 && ch->vcc_active == 0) {
|
||||
TRACE_INFO("%u: VCC activated\r\n", ch->num);
|
||||
@@ -1046,18 +1090,18 @@ void card_emu_io_statechg(struct card_handle *ch, enum card_io io, int active)
|
||||
case CARD_IO_RST:
|
||||
if (active == 0 && ch->in_reset) {
|
||||
TRACE_INFO("%u: RST released\r\n", ch->num);
|
||||
if (ch->vcc_active && ch->clocked) {
|
||||
/* enable the TC/ETU counter once reset has been released */
|
||||
tc_etu_enable(ch->tc_chan);
|
||||
if (ch->vcc_active && ch->clocked && ISO_S_WAIT_RST == ch->state) {
|
||||
/* prepare to send the ATR */
|
||||
card_set_state(ch, ISO_S_WAIT_ATR);
|
||||
}
|
||||
} else if (active && !ch->in_reset) {
|
||||
TRACE_INFO("%u: RST asserted\r\n", ch->num);
|
||||
tc_etu_disable(ch->tc_chan);
|
||||
card_set_state(ch, ISO_S_WAIT_RST);
|
||||
}
|
||||
ch->in_reset = active;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1067,62 +1111,61 @@ int card_emu_set_atr(struct card_handle *ch, const uint8_t *atr, uint8_t len)
|
||||
if (len > sizeof(ch->atr.atr))
|
||||
return -1;
|
||||
|
||||
/* ignore new ATR for now since we PPS has not been tested
|
||||
memcpy(ch->atr.atr, atr, len);
|
||||
ch->atr.len = len;
|
||||
ch->atr.idx = 0;
|
||||
*/
|
||||
|
||||
#if TRACE_LEVEL >= TRACE_LEVEL_INFO
|
||||
uint8_t i;
|
||||
TRACE_INFO("%u: ATR set: ", ch->num);
|
||||
for (i = 0; i < ch->atr.len; i++) {
|
||||
for (i = 0; i < len; i++) {
|
||||
TRACE_INFO_WP("%02x ", atr[i]);
|
||||
}
|
||||
TRACE_INFO_WP("\n\r");
|
||||
TRACE_INFO("%u: ATR set currently ignored\n\r", ch->num);
|
||||
#endif
|
||||
/* FIXME: race condition with transmitting ATR to reader? */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* hardware driver informs us that one (more) ETU has expired */
|
||||
void tc_etu_wtime_half_expired(void *handle)
|
||||
void card_emu_wt_halfed(struct card_handle *ch)
|
||||
{
|
||||
struct card_handle *ch = handle;
|
||||
/* transmit NULL procedure byte well before waiting time expires */
|
||||
switch (ch->state) {
|
||||
case ISO_S_IN_TPDU:
|
||||
switch (ch->tpdu.state) {
|
||||
case TPDU_S_WAIT_PB:
|
||||
case TPDU_S_WAIT_TX:
|
||||
case TPDU_S_WAIT_PB:
|
||||
putchar('N');
|
||||
card_emu_uart_tx(ch->uart_chan, ISO7816_3_PB_NULL);
|
||||
card_emu_uart_tx(ch->uart_chan, ISO7816_3_PB_NULL); // we are waiting for data from the user. send a procedure byte to ask the reader to wait more time
|
||||
card_emu_uart_reset_wt(ch->uart_chan); // reset WT
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* hardware driver informs us that one (more) ETU has expired */
|
||||
void tc_etu_wtime_expired(void *handle)
|
||||
void card_emu_wt_expired(struct card_handle *ch)
|
||||
{
|
||||
struct card_handle *ch = handle;
|
||||
switch (ch->state) {
|
||||
case ISO_S_WAIT_ATR:
|
||||
/* ISO 7816-3 6.2.1 time tc has passed, we can now send the ATR */
|
||||
card_set_state(ch, ISO_S_IN_ATR);
|
||||
break;
|
||||
default:
|
||||
// TODO become unresponsive
|
||||
TRACE_ERROR("%u: wtime_exp\r\n", ch->num);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* shortest ATR found in smartcard_list.txt */
|
||||
static const uint8_t default_atr[] = { 0x3B, 0x02, 0x14, 0x50 };
|
||||
/* shortest ATR possible (uses default speed and no options) */
|
||||
static const uint8_t default_atr[] = { 0x3B, 0x00 };
|
||||
|
||||
static struct card_handle card_handles[NUM_SLOTS];
|
||||
|
||||
@@ -1149,13 +1192,13 @@ struct card_handle *card_emu_init(uint8_t slot_num, uint8_t tc_chan, uint8_t uar
|
||||
ch->in_reset = 1;
|
||||
ch->clocked = 0;
|
||||
|
||||
ch->fi = 0;
|
||||
ch->di = 1;
|
||||
ch->fi = ISO7816_3_DEFAULT_FI;
|
||||
ch->di = ISO7816_3_DEFAULT_DI;
|
||||
ch->wi = ISO7816_3_DEFAULT_WI;
|
||||
ch->wt = ISO7816_3_DEFAULT_WT;;
|
||||
|
||||
ch->tc_chan = tc_chan;
|
||||
ch->uart_chan = uart_chan;
|
||||
ch->waiting_time = ISO7816_3_INIT_WTIME;
|
||||
|
||||
ch->atr.idx = 0;
|
||||
ch->atr.len = sizeof(default_atr);
|
||||
@@ -1164,7 +1207,5 @@ struct card_handle *card_emu_init(uint8_t slot_num, uint8_t tc_chan, uint8_t uar
|
||||
ch->pts.state = PTS_S_WAIT_REQ_PTSS;
|
||||
ch->tpdu.state = TPDU_S_WAIT_CLA;
|
||||
|
||||
tc_etu_init(ch->tc_chan, ch);
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
123
firmware/libcommon/source/iso7816_3.c
Normal file
123
firmware/libcommon/source/iso7816_3.c
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (C) 2019 sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "iso7816_3.h"
|
||||
|
||||
const uint16_t iso7816_3_fi_table[16] = {
|
||||
372, 372, 558, 744, 1116, 1488, 1860, 0,
|
||||
0, 512, 768, 1024, 1536, 2048, 0, 0
|
||||
};
|
||||
|
||||
const uint32_t iso7816_3_fmax_table[16] = {
|
||||
4000000, 5000000, 6000000, 8000000, 12000000, 16000000, 20000000, 0,
|
||||
0, 5000000, 7500000, 10000000, 15000000, 20000000, 0, 0
|
||||
};
|
||||
|
||||
const uint8_t iso7816_3_di_table[16] = {
|
||||
0, 1, 2, 4, 8, 16, 32, 64,
|
||||
12, 20, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
/* all values are based on the Elementary Time Unit (ETU), defined in ISO/IEC 7816-3 section 7.1
|
||||
* this is the time required to transmit a bit, and is calculated as follows: 1 ETU = (F / D) x (1 / f) where:
|
||||
* - F is the clock rate conversion integer
|
||||
* - D is the baud rate adjustment factor
|
||||
* - f is the clock frequency
|
||||
* the possible F, f(max), and D values are defined in ISO/IEC 7816-3 table 7 and 8
|
||||
* - the initial value for F (after reset) is Fd = 372
|
||||
* - the initial value for D (after reset) is Dd = 1
|
||||
* - the initial maximum frequency f(max) is 5 MHz
|
||||
* the card must measure the ETU based on the clock signal provided by the reader
|
||||
* one ETU (e.g. 1 bit) takes F/D clock cycles, which the card must count
|
||||
*
|
||||
* the card can indicate an alternative set of supported values Fi (with corresponding f(max)) and Di for higher baud rate in TA1 in the ATR (see ISO/IEC 7816-3 section 8.3)
|
||||
* these values are selected according to ISO/IEC 7816-3 section 6.3.1:
|
||||
* - card in specific mode: they are enforced if TA2 is present (the reader can deactivate the card if it does not support these values)
|
||||
* - card in negotiable mode:
|
||||
* -- they can be selected by the reader using the Protocol and Parameters Selection (PPS) procedure
|
||||
* -- the first offered protocol and default values are used when no PPS is started
|
||||
*
|
||||
* PPS is done with Fd and Dd (see ISO/IEC 7816-3 section 9)
|
||||
* the reader can propose any F and D values between from Fd to Fi, and from Dd to Di (Fi and Di are indicated in TA1)
|
||||
* the in PPS agreed values F and D are called Fn and Dn and are applied after a successful exchange, corresponding to PPS1_Response bit 5
|
||||
*
|
||||
* the F and D values must be provided to the SAM3S USART peripheral (after reset and PPS)
|
||||
*/
|
||||
|
||||
bool iso7816_3_valid_f(uint16_t f)
|
||||
{
|
||||
if (0 == f) {
|
||||
return false;
|
||||
}
|
||||
uint8_t i = 0;
|
||||
for (i = 0; i < ARRAY_SIZE(iso7816_3_fi_table) && iso7816_3_fi_table[i] != f; i++);
|
||||
return (i < ARRAY_SIZE(iso7816_3_fi_table) && iso7816_3_fi_table[i] == f);
|
||||
}
|
||||
|
||||
bool iso7816_3_valid_d(uint8_t d)
|
||||
{
|
||||
if (0 == d) {
|
||||
return false;
|
||||
}
|
||||
uint8_t i = 0;
|
||||
for (i = 0; i < ARRAY_SIZE(iso7816_3_di_table) && iso7816_3_di_table[i] != d; i++);
|
||||
return (i < ARRAY_SIZE(iso7816_3_di_table) && iso7816_3_di_table[i] == d);
|
||||
}
|
||||
|
||||
/*
|
||||
* the ETU is not only used to define the baud rate, but also the Waiting Time (WT) (see ISO/IEC 7816-3 section 8.1)
|
||||
* when exceeding WT without card response, the reader flags the card as unresponsive, and resets it
|
||||
* this can be used by the card to indicate errors or unsupported operations
|
||||
* if the card requires more time to respond, it shall send a procedure byte to restart WT
|
||||
* WT is calculated as follows (for T=0, see ISO/IEC 7816-3 section 10.2): WT = WI x 960 x (Fi / f(max)) where
|
||||
* - WI is encoded in TC2 in the ATR (10 if absent)
|
||||
* - WI does not depend on D/Di (used for the ETU)
|
||||
* - after reset WT is 9600 ETU
|
||||
* - WI (e.g. the new WT) is applied when T=0 is used (after 6.3.1), even if Fi is not Fn (this WT extension is important to know for the reader so to have the right timeout)
|
||||
*/
|
||||
|
||||
int32_t iso7816_3_calculate_wt(uint8_t wi, uint16_t fi, uint8_t di, uint16_t f, uint8_t d)
|
||||
{
|
||||
// sanity checks
|
||||
if (0 == wi) {
|
||||
return -1;
|
||||
}
|
||||
if (!iso7816_3_valid_f(fi)) {
|
||||
return -2;
|
||||
}
|
||||
if (!iso7816_3_valid_d(di)) {
|
||||
return -3;
|
||||
}
|
||||
if (!iso7816_3_valid_f(f)) {
|
||||
return -4;
|
||||
}
|
||||
if (!iso7816_3_valid_d(d)) {
|
||||
return -5;
|
||||
}
|
||||
if (f > fi) {
|
||||
return -6;
|
||||
}
|
||||
if (d > di) {
|
||||
return -7;
|
||||
}
|
||||
|
||||
return wi * 960UL * (fi/f) * (di/d); // calculate timeout value in ETU
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/* card emulation mode
|
||||
*
|
||||
* (C) 2015-2017 by Harald Welte <laforge@gnumonks.org>
|
||||
* (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
|
||||
* (C) 2018-2019 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "simtrace.h"
|
||||
#include "ringbuffer.h"
|
||||
#include "card_emu.h"
|
||||
#include "iso7816_fidi.h"
|
||||
#include "iso7816_3.h"
|
||||
#include "utils.h"
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/core/msgb.h>
|
||||
@@ -54,11 +54,15 @@ struct cardem_inst {
|
||||
struct card_handle *ch;
|
||||
struct llist_head usb_out_queue;
|
||||
struct ringbuf rb;
|
||||
uint32_t wt; /*!< receiver waiting time to trigger timeout (0 to deactivate it) */
|
||||
uint32_t wt_remaining; /*!< remaining waiting time */
|
||||
bool wt_halfed; /*!< if at least half of the waiting time passed */
|
||||
struct Usart_info usart_info;
|
||||
int usb_pending_old;
|
||||
uint8_t ep_out;
|
||||
uint8_t ep_in;
|
||||
uint8_t ep_int;
|
||||
const Pin pin_io;
|
||||
const Pin pin_insert;
|
||||
uint32_t vcc_uv;
|
||||
uint32_t vcc_uv_last;
|
||||
@@ -75,6 +79,7 @@ struct cardem_inst cardem_inst[] = {
|
||||
.ep_out = SIMTRACE_CARDEM_USB_EP_USIM1_DATAOUT,
|
||||
.ep_in = SIMTRACE_CARDEM_USB_EP_USIM1_DATAIN,
|
||||
.ep_int = SIMTRACE_CARDEM_USB_EP_USIM1_INT,
|
||||
.pin_io = PIN_USIM1_IO,
|
||||
#ifdef PIN_SET_USIM1_PRES
|
||||
.pin_insert = PIN_SET_USIM1_PRES,
|
||||
#endif
|
||||
@@ -90,6 +95,7 @@ struct cardem_inst cardem_inst[] = {
|
||||
.ep_out = SIMTRACE_CARDEM_USB_EP_USIM2_DATAOUT,
|
||||
.ep_in = SIMTRACE_CARDEM_USB_EP_USIM2_DATAIN,
|
||||
.ep_int = SIMTRACE_CARDEM_USB_EP_USIM2_INT,
|
||||
.pin_io = PIN_USIM2_IO,
|
||||
#ifdef PIN_SET_USIM2_PRES
|
||||
.pin_insert = PIN_SET_USIM2_PRES,
|
||||
#endif
|
||||
@@ -140,7 +146,7 @@ void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx)
|
||||
* receiver enabled during transmit */
|
||||
USART_SetReceiverEnabled(usart, 1);
|
||||
usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
|
||||
USART_EnableIt(usart, US_IER_TXRDY);
|
||||
USART_EnableIt(usart, US_IER_TXRDY | US_IER_TIMEOUT);
|
||||
USART_SetTransmitterEnabled(usart, 1);
|
||||
break;
|
||||
case ENABLE_RX:
|
||||
@@ -150,7 +156,7 @@ void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx)
|
||||
USART_SetTransmitterEnabled(usart, 1);
|
||||
wait_tx_idle(usart);
|
||||
usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
|
||||
USART_EnableIt(usart, US_IER_RXRDY);
|
||||
USART_EnableIt(usart, US_IER_RXRDY | US_IER_TIMEOUT);
|
||||
USART_SetReceiverEnabled(usart, 1);
|
||||
break;
|
||||
case 0:
|
||||
@@ -188,57 +194,157 @@ int card_emu_uart_tx(uint8_t uart_chan, uint8_t byte)
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* FIXME: integrate this with actual irq handler */
|
||||
static void usart_irq_rx(uint8_t inst_num)
|
||||
{
|
||||
if (inst_num >= ARRAY_SIZE(cardem_inst)) {
|
||||
TRACE_ERROR("%u: UART channel out of bounds\r\n", inst_num);
|
||||
return;
|
||||
}
|
||||
Usart *usart = get_usart_by_chan(inst_num);
|
||||
struct cardem_inst *ci = &cardem_inst[inst_num];
|
||||
uint32_t csr;
|
||||
uint8_t byte = 0;
|
||||
|
||||
csr = usart->US_CSR & usart->US_IMR;
|
||||
csr = usart->US_CSR & usart->US_IMR; // save state/flags before they get changed
|
||||
|
||||
if (csr & US_CSR_RXRDY) {
|
||||
byte = (usart->US_RHR) & 0xFF;
|
||||
if (rbuf_write(&ci->rb, byte) < 0)
|
||||
TRACE_ERROR("rbuf overrun\r\n");
|
||||
if (csr & US_CSR_RXRDY) { // bytes has been received
|
||||
byte = (usart->US_RHR) & 0xFF; // ready out byte
|
||||
if (rbuf_write(&ci->rb, byte) < 0) // store byte in buffer
|
||||
TRACE_ERROR("rbuf overrun\r\n"); // error if could not store in buffer
|
||||
}
|
||||
|
||||
if (csr & US_CSR_TXRDY) {
|
||||
if (card_emu_tx_byte(ci->ch) == 0)
|
||||
USART_DisableIt(usart, US_IER_TXRDY);
|
||||
if (csr & US_CSR_TXRDY) { // ready to transmit the next byte
|
||||
if (card_emu_tx_byte(ci->ch) == 0) // transmit next byte, and check if a byte is being transmitted
|
||||
USART_DisableIt(usart, US_IER_TXRDY); // stop the TX ready signal if not byte has been transmitted
|
||||
}
|
||||
|
||||
if (csr & (US_CSR_OVRE|US_CSR_FRAME|US_CSR_PARE|
|
||||
US_CSR_TIMEOUT|US_CSR_NACK|(1<<10))) {
|
||||
usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
|
||||
TRACE_ERROR("%u e 0x%x st: 0x%lx\n", ci->num, byte, csr);
|
||||
if (csr & (US_CSR_OVRE | US_CSR_FRAME | US_CSR_PARE | US_CSR_NACK | (1 << 10))) { // error flag set
|
||||
usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK; // reset UART state to clear flag
|
||||
TRACE_ERROR("%u USART error on 0x%x status: 0x%lx\n", ci->num, byte, csr); // warn user about error
|
||||
}
|
||||
|
||||
// handle timeout
|
||||
if (csr & US_CSR_TIMEOUT) { // RX has been inactive for some time
|
||||
if (ci->wt_remaining <= (usart->US_RTOR & 0xffff)) { // waiting time has passed
|
||||
ci->wt_remaining = 0; // timeout reached (will stop the timer)
|
||||
} else {
|
||||
ci->wt_remaining -= (usart->US_RTOR & 0xffff); // be sure to subtract the actual timeout since the new might not have been set and reloaded yet
|
||||
}
|
||||
if (0 == ci->wt_remaining) {
|
||||
card_emu_wt_expired(ci->ch); // let the state know WT has expired
|
||||
} else if (ci->wt_remaining <= ci->wt / 2 && !ci->wt_halfed) {
|
||||
ci->wt_halfed = true;
|
||||
card_emu_wt_halfed(ci->ch); // let the state know WT has half expired
|
||||
}
|
||||
if (ci->wt_remaining > 0xffff) { // value exceeds the USART TO range
|
||||
usart->US_RTOR = 0xffff; // use the MAX
|
||||
} else {
|
||||
usart->US_RTOR = ci->wt_remaining;
|
||||
}
|
||||
usart->US_CR |= US_CR_STTTO; // clear timeout flag (and stop timeout until next character is received)
|
||||
usart->US_CR |= US_CR_RETTO; // restart the counter (it wt is 0, the timeout is not started)
|
||||
}
|
||||
}
|
||||
|
||||
/*! ISR called for USART0 */
|
||||
void mode_cardemu_usart0_irq(void)
|
||||
{
|
||||
/* USART0 == Instance 1 == USIM 2 */
|
||||
usart_irq_rx(1);
|
||||
}
|
||||
|
||||
/*! ISR called for USART1 */
|
||||
void mode_cardemu_usart1_irq(void)
|
||||
{
|
||||
/* USART1 == Instance 0 == USIM 1 */
|
||||
usart_irq_rx(0);
|
||||
}
|
||||
|
||||
/* call-back from card_emu.c to change UART baud rate */
|
||||
int card_emu_uart_update_fidi(uint8_t uart_chan, unsigned int fidi)
|
||||
{
|
||||
int rc;
|
||||
Usart *usart = get_usart_by_chan(uart_chan);
|
||||
// call-back from card_emu.c to change UART baud rate
|
||||
|
||||
usart->US_CR |= US_CR_RXDIS | US_CR_RSTRX;
|
||||
usart->US_FIDI = fidi & 0x3ff;
|
||||
usart->US_CR |= US_CR_RXEN | US_CR_STTTO;
|
||||
return 0;
|
||||
void card_emu_uart_update_fd(uint8_t uart_chan, uint16_t f, uint8_t d)
|
||||
{
|
||||
Usart *usart = get_usart_by_chan(uart_chan); // get the USART based on the card handle
|
||||
if (NULL == usart) {
|
||||
TRACE_ERROR("%u: USART not found by chan\r\n", uart_chan);
|
||||
return;
|
||||
}
|
||||
if (!iso7816_3_valid_f(f)) {
|
||||
TRACE_ERROR("%u: invalid F: %u\r\n", uart_chan, f);
|
||||
return;
|
||||
}
|
||||
if (!iso7816_3_valid_d(d)) {
|
||||
TRACE_ERROR("%u: invalid D: %u\r\n", uart_chan, d);
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t ratio = f / d;
|
||||
if (ratio > 0 && ratio < 2048) {
|
||||
/* make sure USART uses new F/D ratio */
|
||||
usart->US_CR |= US_CR_RXDIS | US_CR_RSTRX; // disable USART before changing baud rate
|
||||
usart->US_FIDI = (ratio & 0x7ff); // change baud rate (ratio)
|
||||
usart->US_CR |= US_CR_RXEN | US_CR_STTTO; // re-enable USART (and stop timeout)
|
||||
TRACE_INFO("%u: USART F/D set to %u/%u\r\n", uart_chan, f, d);
|
||||
} else {
|
||||
TRACE_ERROR("%u: USART could not set F/D to %u/%u\r\n", uart_chan, f, d);
|
||||
// TODO become unresponsive
|
||||
}
|
||||
}
|
||||
|
||||
void card_emu_uart_update_wt(uint8_t uart_chan, uint32_t wt)
|
||||
{
|
||||
if (uart_chan >= ARRAY_SIZE(cardem_inst)) {
|
||||
TRACE_ERROR("%u: UART channel out of bounds\r\n", uart_chan);
|
||||
return;
|
||||
}
|
||||
struct cardem_inst *ci = &cardem_inst[uart_chan];
|
||||
Usart *usart = get_usart_by_chan(uart_chan); // get the USART based on the card handle
|
||||
if (NULL == usart) {
|
||||
TRACE_ERROR("%u: USART not found by chan\r\n", uart_chan);
|
||||
return;
|
||||
}
|
||||
|
||||
ci->wt = wt; // save value
|
||||
card_emu_uart_reset_wt(uart_chan); // reset and start timer
|
||||
TRACE_INFO("%u: USART WT set to %lu ETU\r\n", uart_chan, wt);
|
||||
}
|
||||
|
||||
void card_emu_uart_reset_wt(uint8_t uart_chan)
|
||||
{
|
||||
if (uart_chan >= ARRAY_SIZE(cardem_inst)) {
|
||||
TRACE_ERROR("%u: UART channel out of bounds\r\n", uart_chan);
|
||||
return;
|
||||
}
|
||||
struct cardem_inst *ci = &cardem_inst[uart_chan];
|
||||
Usart *usart = get_usart_by_chan(uart_chan); // get the USART based on the card handle
|
||||
if (NULL == usart) {
|
||||
TRACE_ERROR("%u: USART not found by chan\r\n", uart_chan);
|
||||
return;
|
||||
}
|
||||
|
||||
ci->wt_remaining = ci->wt; // reload WT value
|
||||
ci->wt_halfed = false; // reset half expired
|
||||
if (ci->wt_remaining > 0xffff) { // value exceeds the USART TO range
|
||||
usart->US_RTOR = 0xffff; // use the MAX
|
||||
} else {
|
||||
usart->US_RTOR = ci->wt_remaining;
|
||||
}
|
||||
usart->US_CR |= US_CR_RETTO; // restart the counter (if wt is 0, the timeout is not started)
|
||||
}
|
||||
|
||||
void card_emu_uart_io_set(uint8_t uart_chan, bool set)
|
||||
{
|
||||
if (uart_chan >= ARRAY_SIZE(cardem_inst)) {
|
||||
TRACE_ERROR("%u: UART channel out of bounds\r\n", uart_chan);
|
||||
return;
|
||||
}
|
||||
struct cardem_inst *ci = &cardem_inst[uart_chan];
|
||||
if (set) {
|
||||
PIO_Set(&ci->pin_io);
|
||||
} else {
|
||||
PIO_Clear(&ci->pin_io);
|
||||
}
|
||||
}
|
||||
|
||||
/* call-back from card_emu.c to force a USART interrupt */
|
||||
@@ -366,7 +472,7 @@ static void usim1_vcc_irqhandler(const Pin *pPin)
|
||||
{
|
||||
int active = PIO_Get(&pin_usim1_vcc) ? 1 : 0;
|
||||
card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_VCC, active);
|
||||
/* FIXME do this for real */
|
||||
/* FIXME readers enable clock after providing power and before releasing reset, but we should check it */
|
||||
card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_CLK, active);
|
||||
}
|
||||
#endif /* !DETECT_VCC_BY_ADC */
|
||||
@@ -383,7 +489,7 @@ static void usim2_vcc_irqhandler(const Pin *pPin)
|
||||
{
|
||||
int active = PIO_Get(&pin_usim2_vcc) ? 1 : 0;
|
||||
card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_VCC, active);
|
||||
/* FIXME do this for real */
|
||||
/* FIXME readers enable clock after providing power and before releasing reset, but we should check it */
|
||||
card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_CLK, active);
|
||||
}
|
||||
#endif /* !DETECT_VCC_BY_ADC */
|
||||
@@ -402,32 +508,47 @@ void mode_cardemu_init(void)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
#ifdef PINS_PWR_CARDEMU
|
||||
// enable power on required peripherals, else disable
|
||||
Pin pins_pwr_cardemu[] = { PINS_PWR_CARDEMU };
|
||||
PIO_Configure(pins_pwr_cardemu, PIO_LISTSIZE(pins_pwr_cardemu));
|
||||
#endif /* PINS_PWR_CARDEMU */
|
||||
#ifdef PINS_CARDSIM
|
||||
PIO_Configure(pins_cardsim, PIO_LISTSIZE(pins_cardsim));
|
||||
#endif
|
||||
// ADC channel 6 and 7 are used to measure VCC (else they are grounded)
|
||||
ADC->ADC_CHER |= ADC_CHER_CH6 | ADC_CHER_CH7; // enable the ADC channels to put them in high impedance (else they leak current)
|
||||
#ifdef DETECT_VCC_BY_ADC
|
||||
card_vcc_adc_init();
|
||||
card_vcc_adc_init(); // configure the ADC to measure VCC
|
||||
#endif /* DETECT_VCC_BY_ADC */
|
||||
// TODO pull SIMtrace board SIM lines low, else they can leak current back to VCC
|
||||
|
||||
INIT_LLIST_HEAD(&cardem_inst[0].usb_out_queue);
|
||||
rbuf_reset(&cardem_inst[0].rb);
|
||||
PIO_Configure(pins_usim1, PIO_LISTSIZE(pins_usim1));
|
||||
ISO7816_Init(&cardem_inst[0].usart_info, CLK_SLAVE);
|
||||
NVIC_EnableIRQ(USART1_IRQn);
|
||||
PIO_ConfigureIt(&pin_usim1_rst, usim1_rst_irqhandler);
|
||||
PIO_EnableIt(&pin_usim1_rst);
|
||||
ISO7816_Init(&cardem_inst[0].usart_info, CLK_SLAVE); // configure USART as ISO-7816 slave (e.g. card)
|
||||
cardem_inst[0].usart_info.base->US_RTOR = 0; // don't use receive timeout timer for now
|
||||
USART_EnableIt(cardem_inst[0].usart_info.base, US_IER_RXRDY | US_IER_TIMEOUT); // enable interrupts to indicate when data has been received or timeout occurred
|
||||
NVIC_EnableIRQ(USART1_IRQn); // enable interrupt requests for the USART peripheral
|
||||
PIO_ConfigureIt(&pin_usim1_rst, usim1_rst_irqhandler); // register ISR to handle reset signal change
|
||||
PIO_EnableIt(&pin_usim1_rst); // enable interrupt for reset pin change
|
||||
#ifndef DETECT_VCC_BY_ADC
|
||||
PIO_ConfigureIt(&pin_usim1_vcc, usim1_vcc_irqhandler);
|
||||
PIO_EnableIt(&pin_usim1_vcc);
|
||||
PIO_ConfigureIt(&pin_usim1_vcc, usim1_vcc_irqhandler); // register ISR to handle VCC signal change
|
||||
PIO_EnableIt(&pin_usim1_vcc); // enable interrupt for VCC pin change
|
||||
#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);
|
||||
sim_switch_use_physical(0, 1);
|
||||
#ifndef DETECT_VCC_BY_ADC
|
||||
usim1_vcc_irqhandler(NULL); // check VCC/CLK state
|
||||
#endif
|
||||
usim1_rst_irqhandler(NULL); // force RST state
|
||||
|
||||
#ifdef CARDEMU_SECOND_UART
|
||||
INIT_LLIST_HEAD(&cardem_inst[1].usb_out_queue);
|
||||
rbuf_reset(&cardem_inst[1].rb);
|
||||
PIO_Configure(pins_usim2, PIO_LISTSIZE(pins_usim2));
|
||||
ISO7816_Init(&cardem_inst[1].usart_info, CLK_SLAVE);
|
||||
// TODO enable timeout
|
||||
NVIC_EnableIRQ(USART0_IRQn);
|
||||
PIO_ConfigureIt(&pin_usim2_rst, usim2_rst_irqhandler);
|
||||
PIO_EnableIt(&pin_usim2_rst);
|
||||
@@ -437,6 +558,7 @@ void mode_cardemu_init(void)
|
||||
#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);
|
||||
sim_switch_use_physical(1, 1);
|
||||
// TODO check rst and vcc
|
||||
#endif /* CARDEMU_SECOND_UART */
|
||||
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ void ISR_PhoneRST(const Pin * pPin)
|
||||
}
|
||||
|
||||
/*
|
||||
* char_stat is zero if no error occured.
|
||||
* char_stat is zero if no error occurred.
|
||||
* Otherwise it is filled with the content of the status register.
|
||||
*/
|
||||
void mode_trace_usart1_irq(void)
|
||||
@@ -110,7 +110,7 @@ void mode_trace_usart1_irq(void)
|
||||
rbuf_write(&sim_rcv_buf, c);
|
||||
} else {
|
||||
TRACE_DEBUG("e %x st: %x\n", c, stat);
|
||||
} /* else: error occured */
|
||||
} /* else: error occurred */
|
||||
|
||||
char_stat = stat;
|
||||
}
|
||||
|
||||
@@ -214,8 +214,8 @@ static void update_wt(uint8_t wi, uint8_t d)
|
||||
if (0 != d) {
|
||||
wt_d = d;
|
||||
}
|
||||
wt = wt_wi*960UL*wt_d;
|
||||
TRACE_INFO("WT updated to %lu\n\r", wt);
|
||||
wt = wt_wi * 960UL * wt_d;
|
||||
TRACE_INFO("WT updated to %lu ETU\n\r", wt);
|
||||
}
|
||||
|
||||
/*! Allocate USB buffer and push + initialize simtrace_msg_hdr
|
||||
|
||||
@@ -36,7 +36,7 @@ const char *get_value_string_or_null(const struct value_string *vs,
|
||||
int get_string_value(const struct value_string *vs, const char *str);
|
||||
|
||||
char osmo_bcd2char(uint8_t bcd);
|
||||
/* only works for numbers in ascci */
|
||||
/* only works for numbers in ASCII */
|
||||
uint8_t osmo_char2bcd(char c);
|
||||
|
||||
int osmo_hexparse(const char *str, uint8_t *b, int max_len);
|
||||
@@ -60,7 +60,7 @@ do { \
|
||||
rem -= ret; \
|
||||
} while (0)
|
||||
|
||||
/*! Helper macro to terminate when an assertion failes
|
||||
/*! Helper macro to terminate when an assertion fails
|
||||
* \param[in] exp Predicate to verify
|
||||
* This function will generate a backtrace and terminate the program if
|
||||
* the predicate evaluates to false (0).
|
||||
@@ -75,7 +75,7 @@ do { \
|
||||
/*! duplicate a string using talloc and release its prior content (if any)
|
||||
* \param[in] ctx Talloc context to use for allocation
|
||||
* \param[out] dst pointer to string, will be updated with ptr to new string
|
||||
* \param[in] newstr String that will be copieed to newly allocated string */
|
||||
* \param[in] newstr String that will be copied to newly allocated string */
|
||||
static inline void osmo_talloc_replace_string(void *ctx, char **dst, const char *newstr)
|
||||
{
|
||||
if (*dst)
|
||||
|
||||
@@ -367,9 +367,9 @@ static int process_do_status(struct cardem_inst *ci, uint8_t *buf, int len)
|
||||
struct cardemu_usb_msg_status *status;
|
||||
status = (struct cardemu_usb_msg_status *) buf;
|
||||
|
||||
printf("=> STATUS: flags=0x%x, fi=%u, di=%u, wi=%u wtime=%u\n",
|
||||
status->flags, status->fi, status->di, status->wi,
|
||||
status->waiting_time);
|
||||
printf("=> STATUS: flags=0x%x, F=%u, D=%u, WI=%u WT=%u\n",
|
||||
status->flags, status->f, status->d, status->wi,
|
||||
status->wt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -747,9 +747,7 @@ int main(int argc, char **argv)
|
||||
st_modem_sim_select_remote(ci->slot);
|
||||
|
||||
/* set the ATR */
|
||||
uint8_t real_atr[] = { 0x3B, 0x9F, 0x96, 0x80, 0x1F, 0xC7, 0x80, 0x31,
|
||||
0xA0, 0x73, 0xBE, 0x21, 0x13, 0x67, 0x43, 0x20,
|
||||
0x07, 0x18, 0x00, 0x00, 0x01, 0xA5 };
|
||||
uint8_t real_atr[] = { 0x3B, 0x00 }; // the simplest ATR
|
||||
atr_update_csum(real_atr, sizeof(real_atr));
|
||||
cardem_request_set_atr(ci, real_atr, sizeof(real_atr));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user