Convert to new generalized SIMTRACE2 USB protocol

The current protocol was card-emulation specific.  The new protocol is
generic/flexible enough to accommodate both tracing and card emulation,
as well as modem control and other future extensions.
This commit is contained in:
Harald Welte
2017-05-08 13:30:09 +02:00
parent ed1efc5035
commit 25a9a80ff5
9 changed files with 523 additions and 249 deletions

View File

@@ -31,7 +31,7 @@
#include "iso7816_fidi.h"
#include "tc_etu.h"
#include "card_emu.h"
#include "cardemu_prot.h"
#include "simtrace_prot.h"
#include "usb_buf.h"
#include "osmocom/core/linuxlist.h"
#include "osmocom/core/msgb.h"
@@ -162,6 +162,37 @@ struct llist_head *card_emu_get_uart_tx_queue(struct card_handle *ch)
static void set_tpdu_state(struct card_handle *ch, enum tpdu_state new_ts);
static void set_pts_state(struct card_handle *ch, enum pts_state new_ptss);
/* update simtrace header msg_len and submit USB buffer */
void usb_buf_upd_len_and_submit(struct msgb *msg)
{
struct simtrace_msg_hdr *sh = msg->l1h;
sh->msg_len = msgb_length(msg);
usb_buf_submit(msg);
}
/* Allocate USB buffer and push + initialize simtrace_msg_hdr */
struct msgb *usb_buf_alloc_st(uint8_t ep, uint8_t msg_class, uint8_t msg_type)
{
struct msgb *msg;
struct simtrace_msg_hdr *sh;
msg = usb_buf_alloc(ep);
if (!msg)
return NULL;
msg->l1h = msgb_put(msg, sizeof(*sh));
sh = (struct simtrace_msg_hdr *) msg->l1h;
memset(sh, 0, sizeof(*sh));
sh->msg_class = msg_class;
sh->msg_type = msg_type;
msg->l2h = msg->l1h + sizeof(*sh);
return msg;
}
/* Update cardemu_usb_msg_rx_data length + submit bufffer */
static void flush_rx_buffer(struct card_handle *ch)
{
struct msgb *msg;
@@ -175,12 +206,10 @@ static void flush_rx_buffer(struct card_handle *ch)
ch->uart_rx_msg = NULL;
/* store length of data payload fild in header */
rd = (struct cardemu_usb_msg_rx_data *) msg->l1h;
msg->l2h = &rd->data;
rd->data_len = msgb_l2len(msg);
rd->hdr.msg_len = msgb_length(msg);
rd = (struct cardemu_usb_msg_rx_data *) msg->l2h;
rd->data_len = msgb_l2len(msg) - sizeof(*rd);
usb_buf_submit(msg);
usb_buf_upd_len_and_submit(msg);
}
/* convert a non-contiguous PTS request/responsei into a contiguous
@@ -223,19 +252,15 @@ static void flush_pts(struct card_handle *ch)
struct msgb *msg;
struct cardemu_usb_msg_pts_info *ptsi;
msg = usb_buf_alloc(ch->in_ep);
msg = usb_buf_alloc_st(ch->in_ep, SIMTRACE_MSGC_CARDEM, SIMTRACE_MSGT_DO_CEMU_PTS);
if (!msg)
return;
msg->l1h = msgb_put(msg, sizeof(*ptsi));
msg->l2h = msg->l1h + sizeof(ptsi->hdr);
ptsi = (struct cardemu_usb_msg_pts_info *) msg->l1h;
ptsi->hdr.msg_type = CEMU_USB_MSGT_DO_PTS;
ptsi->hdr.msg_len = sizeof(*ptsi);
ptsi = (struct cardemu_usb_msg_pts_info *) msgb_put(msg, sizeof(*ptsi));
ptsi->pts_len = serialize_pts(ptsi->req, ch->pts.req);
serialize_pts(ptsi->resp, ch->pts.resp);
usb_buf_submit(msg);
usb_buf_upd_len_and_submit(msg);
}
static void emu_update_fidi(struct card_handle *ch)
@@ -504,24 +529,22 @@ static void add_tpdu_byte(struct card_handle *ch, uint8_t byte)
/* ensure we have a buffer */
if (!ch->uart_rx_msg) {
msg = ch->uart_rx_msg = usb_buf_alloc(ch->in_ep);
msg = ch->uart_rx_msg = usb_buf_alloc_st(ch->in_ep, SIMTRACE_MSGC_CARDEM,
SIMTRACE_MSGT_DO_CEMU_RX_DATA);
if (!ch->uart_rx_msg) {
TRACE_ERROR("%u: Received UART byte but ENOMEM\r\n",
ch->num);
return;
}
msg->l1h = msgb_put(msg, sizeof(*rd));
rd = (struct cardemu_usb_msg_rx_data *) msg->l1h;
msg->l2h = msg->l1h + sizeof(rd->hdr);
cardemu_hdr_set(&rd->hdr, CEMU_USB_MSGT_DO_RX_DATA);
msgb_put(msg, sizeof(*rd));
} else
msg = ch->uart_rx_msg;
rd = (struct cardemu_usb_msg_rx_data *) msg->l1h;
rd = (struct cardemu_usb_msg_rx_data *) msg->l2h;
msgb_put_u8(msg, byte);
/* check if the buffer is full. If so, send it */
if (msgb_length(msg) >= sizeof(*rd) + num_data_bytes) {
if (msgb_l2len(msg) >= sizeof(*rd) + num_data_bytes) {
rd->flags |= CEMU_DATA_F_FINAL;
flush_rx_buffer(ch);
/* We need to transmit the SW now, */
@@ -604,18 +627,16 @@ static void send_tpdu_header(struct card_handle *ch)
}
TRACE_DEBUG("%u: allocating new buffer\r\n", ch->num);
/* ensure we have a new buffer */
ch->uart_rx_msg = usb_buf_alloc(ch->in_ep);
ch->uart_rx_msg = usb_buf_alloc_st(ch->in_ep, SIMTRACE_MSGC_CARDEM,
SIMTRACE_MSGT_DO_CEMU_RX_DATA);
if (!ch->uart_rx_msg) {
TRACE_ERROR("%u: %s: ENOMEM\r\n", ch->num, __func__);
return;
}
msg = ch->uart_rx_msg;
msg->l1h = msgb_put(msg, sizeof(*rd));
rd = (struct cardemu_usb_msg_rx_data *) msg->l1h;
rd = (struct cardemu_usb_msg_rx_data *) msgb_put(msg, sizeof(*rd));
/* initialize header */
msg->l2h = msg->l1h + sizeof(rd->hdr);
cardemu_hdr_set(&rd->hdr, CEMU_USB_MSGT_DO_RX_DATA);
rd->flags = CEMU_DATA_F_TPDU_HDR;
/* copy TPDU header to data field */
@@ -683,12 +704,14 @@ static int tx_byte_tpdu(struct card_handle *ch)
/* dequeue first at head */
ch->uart_tx_msg = msgb_dequeue(&ch->uart_tx_queue);
ch->uart_tx_msg->l1h = ch->uart_tx_msg->data;
ch->uart_tx_msg->l1h = ch->uart_tx_msg->head;
ch->uart_tx_msg->l2h = ch->uart_tx_msg->l1h + sizeof(struct simtrace_msg_hdr);
msg = ch->uart_tx_msg;
msgb_pull(msg, sizeof(*td));
/* remove the header */
msgb_pull(msg, sizeof(struct simtrace_msg_hdr) + sizeof(*td));
}
msg = ch->uart_tx_msg;
td = (struct cardemu_usb_msg_tx_data *) msg->l1h;
td = (struct cardemu_usb_msg_tx_data *) msg->l2h;
/* take the next pending byte out of the msgb */
byte = msgb_pull_u8(msg);
@@ -829,15 +852,12 @@ void card_emu_report_status(struct card_handle *ch)
struct msgb *msg;
struct cardemu_usb_msg_status *sts;
msg = usb_buf_alloc(ch->in_ep);
msg = usb_buf_alloc_st(ch->in_ep, SIMTRACE_MSGC_CARDEM,
SIMTRACE_MSGT_BD_CEMU_STATUS);
if (!msg)
return;
msg->l1h = msgb_put(msg, sizeof(*sts));
msg->l2h = msg->l1h + sizeof(sts->hdr);
sts = (struct cardemu_usb_msg_status *) msg->l1h;
sts->hdr.msg_type = CEMU_USB_MSGT_DO_STATUS;
sts->hdr.msg_len = sizeof(*sts);
sts = (struct cardemu_usb_msg_status *) msgb_put(msg, sizeof(*sts));
sts->flags = 0;
if (ch->vcc_active)
sts->flags |= CEMU_STATUS_F_VCC_PRESENT;
@@ -851,7 +871,7 @@ void card_emu_report_status(struct card_handle *ch)
sts->wi = ch->wi;
sts->waiting_time = ch->waiting_time;
usb_buf_submit(msg);
usb_buf_upd_len_and_submit(msg);
}
/* hardware driver informs us that a card I/O signal has changed */

View File

@@ -10,7 +10,7 @@
#include "osmocom/core/msgb.h"
#include "llist_irqsafe.h"
#include "usb_buf.h"
#include "cardemu_prot.h"
#include "simtrace_prot.h"
#define TRACE_ENTRY() TRACE_DEBUG("%s entering\r\n", __func__)
@@ -440,27 +440,42 @@ void mode_cardemu_exit(void)
}
/* handle a single USB command as received from the USB host */
static void dispatch_usb_command(struct msgb *msg, struct cardem_inst *ci)
static void dispatch_usb_command_generic(struct msgb *msg, struct cardem_inst *ci)
{
struct cardemu_usb_msg_hdr *hdr;
struct simtrace_msg_hdr *hdr;
hdr = (struct simtrace_msg_hdr *) msg->l1h;
switch (hdr->msg_type) {
case SIMTRACE_CMD_BD_BOARD_INFO:
break;
default:
break;
}
usb_buf_free(msg);
}
/* handle a single USB command as received from the USB host */
static void dispatch_usb_command_cardem(struct msgb *msg, struct cardem_inst *ci)
{
struct simtrace_msg_hdr *hdr;
struct cardemu_usb_msg_set_atr *atr;
struct cardemu_usb_msg_cardinsert *cardins;
struct llist_head *queue;
hdr = (struct cardemu_usb_msg_hdr *) msg->l1h;
hdr = (struct simtrace_msg_hdr *) msg->l1h;
switch (hdr->msg_type) {
case CEMU_USB_MSGT_DT_TX_DATA:
case SIMTRACE_MSGT_DT_CEMU_TX_DATA:
queue = card_emu_get_uart_tx_queue(ci->ch);
llist_add_tail(&msg->list, queue);
card_emu_have_new_uart_tx(ci->ch);
break;
case CEMU_USB_MSGT_DT_SET_ATR:
atr = (struct cardemu_usb_msg_set_atr *) hdr;
case SIMTRACE_MSGT_DT_CEMU_SET_ATR:
atr = (struct cardemu_usb_msg_set_atr *) msg->l2h;
card_emu_set_atr(ci->ch, atr->atr, atr->atr_len);
usb_buf_free(msg);
break;
case CEMU_USB_MSGT_DT_CARDINSERT:
cardins = (struct cardemu_usb_msg_cardinsert *) hdr;
case SIMTRACE_MSGT_DT_CEMU_CARDINSERT:
cardins = (struct cardemu_usb_msg_cardinsert *) msg->l2h;
TRACE_INFO("%u: set card_insert to %s\r\n", ci->num,
cardins->card_insert ? "INSERTED" : "REMOVED");
if (cardins->card_insert)
@@ -469,12 +484,60 @@ static void dispatch_usb_command(struct msgb *msg, struct cardem_inst *ci)
PIO_Clear(&ci->pin_insert);
usb_buf_free(msg);
break;
case CEMU_USB_MSGT_DT_GET_STATUS:
case SIMTRACE_MSGT_BD_CEMU_STATUS:
card_emu_report_status(ci->ch);
usb_buf_free(msg);
break;
case CEMU_USB_MSGT_DT_GET_STATS:
case SIMTRACE_MSGT_BD_CEMU_STATS:
default:
/* FIXME */
/* FIXME: Send Error */
usb_buf_free(msg);
break;
}
}
/* handle a single USB command as received from the USB host */
static void dispatch_usb_command_modem(struct msgb *msg, struct cardem_inst *ci)
{
struct simtrace_msg_hdr *hdr;
hdr = (struct simtrace_msg_hdr *) msg->l1h;
switch (hdr->msg_type) {
case SIMTRACE_MSGT_DT_MODEM_RESET:
break;
case SIMTRACE_MSGT_DT_MODEM_SIM_SELECT:
break;
case SIMTRACE_MSGT_BD_MODEM_STATUS:
break;
default:
break;
}
usb_buf_free(msg);
}
/* handle a single USB command as received from the USB host */
static void dispatch_usb_command(struct msgb *msg, struct cardem_inst *ci)
{
struct simtrace_msg_hdr *sh = msg->l1h;
if (msgb_length(msg) < sizeof(*sh)) {
/* FIXME: Error */
usb_buf_free(msg);
return;
}
switch (sh->msg_class) {
case SIMTRACE_MSGC_GENERIC:
dispatch_usb_command_generic(msg, ci);
break;
case SIMTRACE_MSGC_CARDEM:
dispatch_usb_command_cardem(msg, ci);
break;
case SIMTRACE_MSGC_MODEM:
dispatch_usb_command_modem(msg, ci);
break;
default:
/* FIXME: Send Error */
usb_buf_free(msg);
break;
}
@@ -483,12 +546,12 @@ static void dispatch_usb_command(struct msgb *msg, struct cardem_inst *ci)
static void dispatch_received_msg(struct msgb *msg, struct cardem_inst *ci)
{
struct msgb *segm;
struct cardemu_usb_msg_hdr *mh;
struct simtrace_msg_hdr *mh;
/* check if we have multiple concatenated commands in
* one message. USB endpoints are streams that don't
* preserve the message boundaries */
mh = (struct cardemu_usb_msg_hdr *) msg->data;
mh = (struct simtrace_msg_hdr *) msg->data;
if (mh->msg_len == msgb_length(msg)) {
/* fast path: only one message in buffer */
dispatch_usb_command(msg, ci);
@@ -498,7 +561,7 @@ static void dispatch_received_msg(struct msgb *msg, struct cardem_inst *ci)
/* slow path: iterate over list of messages, allocating one new
* reqe_ctx per segment */
while (1) {
mh = (struct cardemu_usb_msg_hdr *) msg->head;
mh = (struct simtrace_msg_hdr *) msg->data;
segm = usb_buf_alloc(ci->ep_out);
if (!segm) {