6 Commits

Author SHA1 Message Date
Harald Welte
575acd9b03 simtrace2_api: Fix transmission of SIMTRACE_CMD_BD_BOARD_INFO
Prior to this commit we didn't pass the pointer to the slot when
requesting board_info.

Change-Id: Ib99e7c0a96f7738480ca68ed2c144c1756a5f11b
2023-10-20 10:09:34 +02:00
Harald Welte
f22a615158 WIP: hack simtrace2-tool for USB testing of rp2040 firmware
Command used for continuous cycles of board_info messages:

./simtrace2-tool -V 1d50 -P aaaa -C 1 -I 0 -S 0 generic board-info

Change-Id: I577a0266b68c8161b9eaec653c3c7d17d320faaf
2023-10-20 10:07:24 +02:00
Harald Welte
4a8ec296fa WIP: generic board-info
Change-Id: I0642269c924a0abe464a64c004681f507f14bc92
2023-09-14 18:36:32 +02:00
Harald Welte
73a8ef31f1 firmware/sniffer: Handle USART BREAK condition
Let's count + report BREAK conditions (all-zero bits + parity + stop
bit)

Change-Id: Idefb552fc9878ca6c88a9bf8bf1c0ced668c5c04
2023-09-14 18:36:32 +02:00
Harald Welte
95c85b6f0c firmware/sniffer: Add performance/error counters
Let's add some counters for number of bytes/tpdu/pps/atr/reset
as well as for all the various error conditions from USART through
ring buffer and TPDU buffer overflows, timeouts, ...

Change-Id: Ic679664191259d321ad1f1829d5568fe0b297f39
2023-09-14 18:36:32 +02:00
Harald Welte
a8d13dea9b HACK: Solve weird problem wih lost OUT transfer on ping-pong endpoint
This adds an unconditional endpoint reset procedure to every SET_FEATURE(UnHalt).

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

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

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

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

Related: OS#5770
Related: https://gerrit.osmocom.org/c/simtrace2/+/26864
Change-Id: I18ed530e617baddf76e8f9829512443ce2a76e0d
2023-09-14 18:36:32 +02:00
6 changed files with 123 additions and 7 deletions

View File

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

View File

@@ -1,6 +1,6 @@
/* SIMtrace2 USB protocol
*
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
* (C) 2015-2022 by Harald Welte <hwelte@hmw-consulting.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
@@ -84,6 +84,8 @@ enum simtrace_msg_type_sniff {
SIMTRACE_MSGT_SNIFF_PPS,
/* TPDU data */
SIMTRACE_MSGT_SNIFF_TPDU,
/* Statistics */
SIMTRACE_MSGT_DO_SNIFF_STATS,
};
/* common message header */
@@ -338,3 +340,24 @@ struct sniff_data {
/* data */
uint8_t data[0];
} __attribute__ ((packed));
/* SIMTRACE_MSGT_DO_SNIFF_STATS */
struct st_sniff_stats {
uint32_t flags; /* RFU */
uint32_t num_bytes; /* total lnumber of bytes received */
uint32_t num_tpdu; /* total number of TPDUs received */
uint32_t num_atr; /* total number of ATRs received */
uint32_t num_pps; /* total number of PPS (req, resp) received */
uint32_t num_reset; /* total number of resets */
struct {
uint32_t overruns;
uint32_t framing_errs;
uint32_t parity_errs;
uint32_t breaks;
} num_usart;
uint32_t num_waiting_time_exp;
uint32_t num_tpdu_overflows; /* TPDU buffer overflows */
uint32_t num_csum_errors; /* ATR + PPS checksum */
uint32_t num_ringbuf_overflows; /* ISR->main ringbuffer overflows */
uint32_t num_tpdu_malformed;
} __attribute__ ((packed));

View File

@@ -116,6 +116,7 @@ enum tpdu_sniff_state {
#define RBUF16_F_FRAMING 0x0200
#define RBUF16_F_PARITY 0x0400
#define RBUF16_F_TIMEOUT_WT 0x0800
#define RBUF16_F_BREAK 0x1000
#define RBUF16_F_DATA_BYTE 0x8000
/*------------------------------------------------------------------------------
@@ -150,6 +151,9 @@ static struct ringbuf16 sniff_buffer;
/* Flags to know is the card status changed (see SIMTRACE_MSGT_DT_SNIFF_CHANGE flags) */
static volatile uint32_t change_flags = 0;
/* statistics for SIMTRACE_MSGT_DO_SNIFF_STATS */
static struct st_sniff_stats g_stats;
/* ISO 7816 variables */
/*! ISO 7816-3 state */
static enum iso7816_3_sniff_state iso_state = ISO7816_S_RESET;
@@ -453,6 +457,7 @@ static void process_byte_atr(uint8_t byte)
default:
TRACE_WARNING("Invalid TS received\n\r");
led_blink(LED_RED, BLINK_2F_O); /* indicate error to user */
g_stats.num_tpdu_malformed++;
usb_send_atr(SNIFF_DATA_FLAG_ERROR_MALFORMED); /* send ATR to host software using USB */
change_state(ISO7816_S_WAIT_ATR); /* reset state */
break;
@@ -523,9 +528,11 @@ static void process_byte_atr(uint8_t byte)
/* We still consider the data as valid (e.g. for WT) even is the checksum is wrong.
* It is up to the reader to handle this error (e.g. by resetting)
*/
g_stats.num_csum_errors++;
}
}
usb_send_atr(flags); /* send ATR to host software using USB */
g_stats.num_atr++;
change_state(ISO7816_S_WAIT_TPDU); /* go to next state */
break;
default:
@@ -617,6 +624,7 @@ static void process_byte_pps(uint8_t byte)
} else {
TRACE_INFO("Invalid PPSS received\n\r");
led_blink(LED_RED, BLINK_2F_O); /* indicate error to user */
g_stats.num_tpdu_malformed++;
usb_send_pps(SNIFF_DATA_FLAG_ERROR_MALFORMED); /* send ATR to host software using USB */
change_state(ISO7816_S_WAIT_TPDU); /* go back to TPDU state */
}
@@ -668,6 +676,7 @@ static void process_byte_pps(uint8_t byte)
if (0 == check) { /* checksum is valid */
change_state(ISO7816_S_WAIT_PPS_RSP); /* go to next state */
} else { /* checksum is invalid */
g_stats.num_csum_errors++;
change_state(ISO7816_S_WAIT_TPDU); /* go to next state */
}
} else if (ISO7816_S_IN_PPS_RSP == iso_state) {
@@ -687,7 +696,9 @@ static void process_byte_pps(uint8_t byte)
usb_send_fidi(pps_cur[2]); /* send Fi/Di change notification to host software over USB */
} else { /* checksum is invalid */
TRACE_INFO("PPS negotiation failed\n\r");
g_stats.num_csum_errors++;
}
g_stats.num_pps++;
change_state(ISO7816_S_WAIT_TPDU); /* go to next state */
}
break;
@@ -724,6 +735,7 @@ static void process_byte_tpdu(uint8_t byte)
return;
}
if (g_tpdu.packet_i >= ARRAY_SIZE(g_tpdu.packet)) {
g_stats.num_tpdu_overflows++;
TRACE_ERROR("TPDU data overflow\n\r");
return;
}
@@ -734,6 +746,7 @@ static void process_byte_tpdu(uint8_t byte)
if (0xff == byte) {
TRACE_WARNING("0xff is not a valid class byte\n\r");
led_blink(LED_RED, BLINK_2F_O); /* indicate error to user */
g_stats.num_tpdu_malformed++;
usb_send_tpdu(SNIFF_DATA_FLAG_ERROR_MALFORMED); /* send ATR to host software using USB */
change_state(ISO7816_S_WAIT_TPDU); /* go back to TPDU state */
return;
@@ -746,6 +759,7 @@ static void process_byte_tpdu(uint8_t byte)
if ((0x60 == (byte & 0xf0)) || (0x90 == (byte & 0xf0))) {
TRACE_WARNING("invalid INS 0x%02x\n\r", byte);
led_blink(LED_RED, BLINK_2F_O); /* indicate error to user */
g_stats.num_tpdu_malformed++;
usb_send_tpdu(SNIFF_DATA_FLAG_ERROR_MALFORMED); /* send ATR to host software using USB */
change_state(ISO7816_S_WAIT_TPDU); /* go back to TPDU state */
return;
@@ -786,6 +800,7 @@ static void process_byte_tpdu(uint8_t byte)
} else {
TRACE_WARNING("invalid SW1 0x%02x\n\r", byte);
led_blink(LED_RED, BLINK_2F_O); /* indicate error to user */
g_stats.num_tpdu_malformed++;
usb_send_tpdu(SNIFF_DATA_FLAG_ERROR_MALFORMED); /* send ATR to host software using USB */
change_state(ISO7816_S_WAIT_TPDU); /* go back to TPDU state */
return;
@@ -794,6 +809,7 @@ static void process_byte_tpdu(uint8_t byte)
case TPDU_S_SW2:
g_tpdu.packet[g_tpdu.packet_i++] = byte;
usb_send_tpdu(0); /* send TPDU to host software using USB */
g_stats.num_tpdu++;
change_state(ISO7816_S_WAIT_TPDU); /* this is the end of the TPDU */
break;
case TPDU_S_DATA_SINGLE:
@@ -832,17 +848,28 @@ void Sniffer_usart_isr(void)
if (csr & US_CSR_RXRDY) {
/* Read communication data byte between phone and SIM */
byte = RBUF16_F_DATA_BYTE | (sniff_usart.base->US_RHR & 0xff);
g_stats.num_bytes++;
/* Reset WT timer */
wt_remaining = g_wt;
}
/* Verify if there was an error */
if (csr & US_CSR_OVRE)
if (csr & US_CSR_OVRE) {
g_stats.num_usart.overruns++;
byte |= RBUF16_F_OVERRUN;
if (csr & US_CSR_FRAME)
}
if (csr & US_CSR_FRAME) {
g_stats.num_usart.framing_errs++;
byte |= RBUF16_F_FRAMING;
if (csr & US_CSR_PARE)
}
if (csr & US_CSR_PARE) {
g_stats.num_usart.parity_errs++;
byte |= RBUF16_F_PARITY;
}
if (csr & US_CSR_RXBRK) {
g_stats.num_usart.breaks++;
byte |= RBUF16_F_BREAK;
};
if (csr & (US_CSR_OVRE|US_CSR_FRAME|US_CSR_PARE))
sniff_usart.base->US_CR |= US_CR_RSTSTA;
@@ -856,6 +883,7 @@ void Sniffer_usart_isr(void)
change_flags |= SNIFF_CHANGE_FLAG_TIMEOUT_WT;
/* Reset timeout value */
wt_remaining = g_wt;
g_stats.num_waiting_time_exp++;
} else {
wt_remaining -= (sniff_usart.base->US_RTOR & 0xffff); /* be sure to subtract the actual timeout since the new might not have been set and reloaded yet */
}
@@ -874,8 +902,10 @@ void Sniffer_usart_isr(void)
/* Store sniffed data (or error flags, or both) into buffer */
if (byte) {
if (rbuf16_write(&sniff_buffer, byte) != 0)
if (rbuf16_write(&sniff_buffer, byte) != 0) {
g_stats.num_ringbuf_overflows++;
TRACE_ERROR("USART buffer full\n\r");
}
}
}
@@ -891,6 +921,7 @@ static void Sniffer_reset_isr(const Pin* pPin)
/* Update the ISO state according to the reset change (reset is active low) */
if (PIO_Get(&pin_rst)) {
change_flags |= SNIFF_CHANGE_FLAG_RESET_DEASSERT; /* set flag and let main loop send it */
g_stats.num_reset++;
} else {
change_flags |= SNIFF_CHANGE_FLAG_RESET_ASSERT; /* set flag and let main loop send it */
}
@@ -918,7 +949,8 @@ void Sniffer_usart0_irq(void)
* Initialization routine
*-----------------------------------------------------------------------------*/
#define SNIFFER_IER (US_IER_RXRDY | US_IER_TIMEOUT | US_IER_OVRE | US_IER_FRAME | US_IER_PARE)
#define SNIFFER_IER (US_IER_RXRDY | US_IER_TIMEOUT | US_IER_OVRE | US_IER_FRAME | US_IER_PARE | \
US_CSR_RXBRK)
/* Called during USB enumeration after device is enumerated by host */
void Sniffer_configure(void)
@@ -945,6 +977,8 @@ void Sniffer_init(void)
{
TRACE_INFO("Sniffer Init\n\r");
memset(&g_stats, 0, sizeof(g_stats));
/* Configure pins to sniff communication between phone and card */
PIO_Configure(pins_sniff, PIO_LISTSIZE(pins_sniff));
/* Configure pins to connect phone to card */
@@ -1101,6 +1135,8 @@ void Sniffer_run(void)
TRACE_ERROR("USART FRAMING Error\r\n");
if (entry & RBUF16_F_OVERRUN)
TRACE_ERROR("USART OVERRUN Error\r\n");
if (entry & RBUF16_F_BREAK)
TRACE_ERROR("USART BREAK Error\r\n");
}
/* Handle flags */

View File

@@ -44,6 +44,7 @@ struct osmo_st2_cardem_inst {
int osmo_st2_slot_tx_msg(struct osmo_st2_slot *slot, struct msgb *msg,
uint8_t msg_class, uint8_t msg_type);
int osmo_st2_generic_request_board_info(struct osmo_st2_slot *slot);
int osmo_st2_cardem_request_card_insert(struct osmo_st2_cardem_inst *ci, bool inserted);
int osmo_st2_cardem_request_pb_and_rx(struct osmo_st2_cardem_inst *ci, uint8_t pb, uint8_t le);

View File

@@ -154,6 +154,19 @@ int osmo_st2_slot_tx_msg(struct osmo_st2_slot *slot, struct msgb *msg,
return rc;
}
/***********************************************************************
* Generic protocol
***********************************************************************/
/*! \brief Requeset the SIMtrace2 board information structure from the device */
int osmo_st2_generic_request_board_info(struct osmo_st2_slot *slot)
{
struct msgb *msg = st_msgb_alloc();
return osmo_st2_slot_tx_msg(slot, msg, SIMTRACE_MSGC_GENERIC, SIMTRACE_CMD_BD_BOARD_INFO);
}
/***********************************************************************
* Card Emulation protocol
***********************************************************************/

View File

@@ -63,6 +63,7 @@ static void print_help(void)
"\n"
);
printf( "Commands:\n"
"\tgeneric board-info\n"
"\tmodem reset (enable|disable|cycle)\n"
"\tmodem sim-switch (local|remote)\n"
"\tmodem sim-card (insert|remove)\n"
@@ -98,9 +99,15 @@ static void run_mainloop(struct osmo_st2_cardem_inst *ci)
fprintf(stderr, "BULK IN transfer error; rc=%d\n", rc);
return;
}
if (rc >= 0) {
printf("Rx(%u): %s\n", xfer_len, osmo_hexdump(buf, xfer_len));
osmo_st2_generic_request_board_info(ci->slot);
}
#if 0
/* break the loop if no new messages arrive within 100ms */
if (rc == LIBUSB_ERROR_TIMEOUT)
return;
#endif
}
}
@@ -216,6 +223,36 @@ static int do_subsys_modem(int argc, char **argv)
return rc;
}
static int do_generic_board_info(int argc, char **argv)
{
printf("ci: %p\n", ci);
printf("ci->slot: %p\n", ci->slot);
printf("ci->slot->transp: %p\n", ci->slot->transp);
return osmo_st2_generic_request_board_info(ci->slot);
}
static int do_subsys_generic(int argc, char **argv)
{
char *command;
int rc;
if (argc < 1)
return -EINVAL;
command = argv[0];
argc--;
argv++;
if (!strcmp(command, "board-info")) {
rc = do_generic_board_info(argc, argv);
} else {
fprintf(stderr, "Unsupported command for subsystem generic: '%s'\n", command);
return -EINVAL;
}
return rc;
}
static int do_command(int argc, char **argv)
{
char *subsys;
@@ -227,7 +264,9 @@ static int do_command(int argc, char **argv)
argc--;
argv++;
if (!strcmp(subsys, "modem"))
if (!strcmp(subsys, "generic")) {
rc= do_subsys_generic(argc, argv);
} else if (!strcmp(subsys, "modem"))
rc = do_subsys_modem(argc, argv);
else {
fprintf(stderr, "Unsupported subsystem '%s'\n", subsys);