Major refactor of USB CCID and USB HID interfaces. All interfaces are rewritten.

With this new scheme we ensure that:
- memcpy's are reduced.
- no race conditions are performed.
- critical areas are protected.
- callbacks are executed immediately.
- write's are executed after the positive report is received.
- no usb middle interface anymore.
- CCID and HID are totally independent.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
This commit is contained in:
Pol Henarejos 2024-08-23 10:02:19 +02:00
parent 0745838e3f
commit fa6292118d
No known key found for this signature in database
GPG key ID: C0095B7870A4CCD3
10 changed files with 420 additions and 576 deletions

View file

@ -118,22 +118,22 @@ uint16_t apdu_process(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size)
if (apdu.rlen <= apdu.ne) {
#ifndef ENABLE_EMULATION
#ifdef USB_ITF_HID
if (itf == ITF_HID) {
driver_exec_finished_cont_hid(itf, apdu.rlen + 2, rdata_gr - (usb_get_tx(itf)));
if (itf == ITF_HID_CTAP) {
driver_exec_finished_cont_hid(itf, apdu.rlen + 2, rdata_gr - apdu.rdata);
}
#endif
#ifdef USB_ITF_CCID
if (itf == ITF_CCID || itf == ITF_WCID) {
driver_exec_finished_cont_ccid(itf, apdu.rlen + 2, rdata_gr - (usb_get_tx(itf) + 34));
if (itf == ITF_SC_CCID || itf == ITF_SC_WCID) {
driver_exec_finished_cont_ccid(itf, apdu.rlen + 2, rdata_gr - apdu.rdata);
}
#endif
#else
driver_exec_finished_cont_emul(itf, apdu.rlen + 2, (uint16_t)(rdata_gr - (usb_get_tx(itf))));
driver_exec_finished_cont_emul(itf, apdu.rlen + 2, (uint16_t)(rdata_gr - apdu.rdata));
#endif
//Prepare next RAPDU
apdu.sw = 0;
apdu.rlen = 0;
usb_prepare_response(itf);
rdata_gr = apdu.rdata;
}
else {
rdata_gr += apdu.ne;
@ -147,17 +147,17 @@ uint16_t apdu_process(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size)
}
#ifndef ENABLE_EMULATION
#ifdef USB_ITF_HID
if (itf == ITF_HID) {
driver_exec_finished_cont_hid(itf, apdu.ne + 2, rdata_gr - apdu.ne - (usb_get_tx(itf)));
if (itf == ITF_HID_CTAP) {
driver_exec_finished_cont_hid(itf, apdu.ne + 2, rdata_gr - apdu.ne - apdu.rdata);
}
#endif
#ifdef USB_ITF_CCID
if (itf == ITF_CCID || itf == ITF_WCID) {
driver_exec_finished_cont_ccid(itf, apdu.ne + 2, rdata_gr - apdu.ne - (usb_get_tx(itf) + 34));
if (itf == ITF_SC_CCID || itf == ITF_SC_WCID) {
driver_exec_finished_cont_ccid(itf, apdu.ne + 2, rdata_gr - apdu.ne - apdu.rdata);
}
#endif
#else
driver_exec_finished_cont_emul(itf, (uint16_t)(apdu.ne + 2), (uint16_t)(rdata_gr - apdu.ne - (usb_get_tx(itf))));
driver_exec_finished_cont_emul(itf, (uint16_t)(apdu.ne + 2), (uint16_t)(rdata_gr - apdu.ne - apdu.rdata));
#endif
apdu.rlen -= (uint16_t)apdu.ne;
}
@ -165,7 +165,6 @@ uint16_t apdu_process(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size)
else {
apdu.sw = 0;
apdu.rlen = 0;
apdu.rdata = usb_prepare_response(itf);
rdata_gr = apdu.rdata;
return 1;
}

View file

@ -29,11 +29,11 @@
typedef struct app {
const uint8_t *aid;
int (*process_apdu)();
int (*select_aid)(struct app *);
int (*select_aid)(struct app *, uint8_t);
int (*unload)();
} app_t;
extern int register_app(int (*)(app_t *), const uint8_t *);
extern int register_app(int (*)(app_t *, uint8_t), const uint8_t *);
extern int select_app(const uint8_t *aid, size_t aid_len);
typedef struct cmd {

View file

@ -30,7 +30,7 @@ typedef QueueHandle_t queue_t;
#define queue_is_empty(a) (uxQueueMessagesWaiting(*(a)) == 0)
#define queue_try_remove(a,b) xQueueReceive(*(a), b, 0)
extern TaskHandle_t hcore0, hcore1;
#define multicore_launch_core1(a) xTaskCreate((void(*)(void *))a, "core1", 4096*ITF_TOTAL, NULL, CONFIG_TINYUSB_TASK_PRIORITY + 2, &hcore1)
#define multicore_launch_core1(a) xTaskCreatePinnedToCore((void(*)(void *))a, "core1", 4096*5, NULL, CONFIG_TINYUSB_TASK_PRIORITY - 2, &hcore1, 1)
#define multicore_reset_core1() do { if (hcore1) { eTaskState e = eTaskGetState(hcore1); if (e <= eSuspended) { vTaskDelete(hcore1); }} }while(0)
#define sleep_ms(a) vTaskDelay(a / portTICK_PERIOD_MS)
static inline uint32_t board_millis(void) {
@ -46,10 +46,8 @@ typedef SemaphoreHandle_t semaphore_t;
#define sem_release(a) xSemaphoreGive(*(a))
#define sem_acquire_blocking(a) xSemaphoreTake(*(a), portMAX_DELAY)
#define multicore_lockout_victim_init() (void)0
static inline bool multicore_lockout_start_timeout_us(int a) {
vTaskSuspend(hcore1); return true; }
static inline bool multicore_lockout_end_timeout_us(int a) {
vTaskResume(hcore1); return true; }
static inline bool multicore_lockout_start_timeout_us(int a) { if (hcore1) { vTaskSuspend(hcore1); } return true; }
static inline bool multicore_lockout_end_timeout_us(int a) { if (hcore1) { vTaskResume(hcore1); } return true; }
#endif

View file

@ -104,7 +104,7 @@ app_t *current_app = NULL;
const uint8_t *ccid_atr = NULL;
int register_app(int (*select_aid)(app_t *), const uint8_t *aid) {
int register_app(int (*select_aid)(app_t *, uint8_t), const uint8_t *aid) {
if (num_apps < sizeof(apps) / sizeof(app_t)) {
apps[num_apps].select_aid = select_aid;
apps[num_apps].aid = aid;
@ -116,13 +116,14 @@ int register_app(int (*select_aid)(app_t *), const uint8_t *aid) {
int select_app(const uint8_t *aid, size_t aid_len) {
if (current_app && current_app->aid && (current_app->aid + 1 == aid || !memcmp(current_app->aid + 1, aid, aid_len))) {
current_app->select_aid(current_app, 0);
return CCID_OK;
}
for (int a = 0; a < num_apps; a++) {
if (!memcmp(apps[a].aid + 1, aid, MIN(aid_len, apps[a].aid[0]))) {
if (current_app) {
if (current_app->aid && !memcmp(current_app->aid + 1, aid, aid_len)) {
current_app->select_aid(current_app);
current_app->select_aid(current_app, 1);
return CCID_OK;
}
if (current_app->unload) {
@ -130,7 +131,7 @@ int select_app(const uint8_t *aid, size_t aid_len) {
}
}
current_app = &apps[a];
if (current_app->select_aid(current_app) == CCID_OK) {
if (current_app->select_aid(current_app, 1) == CCID_OK) {
return CCID_OK;
}
}
@ -146,19 +147,6 @@ void led_set_blink(uint32_t mode) {
blink_interval_ms = mode;
}
uint32_t timeout = 0;
void timeout_stop() {
timeout = 0;
}
void timeout_start() {
timeout = board_millis();
}
bool is_busy() {
return timeout > 0;
}
void execute_tasks();
static bool req_button_pending = false;
@ -344,10 +332,10 @@ extern void neug_task();
extern void usb_task();
void execute_tasks()
{
usb_task();
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
tud_task(); // tinyusb device task
#endif
usb_task();
led_blinking_task();
}
@ -464,7 +452,7 @@ int main(void) {
#endif
#ifdef ESP_PLATFORM
xTaskCreate(core0_loop, "core0", 4096*ITF_TOTAL, NULL, CONFIG_TINYUSB_TASK_PRIORITY + 1, &hcore0);
xTaskCreatePinnedToCore(core0_loop, "core0", 4096*5, NULL, CONFIG_TINYUSB_TASK_PRIORITY - 1, &hcore0, 0);
#else
core0_loop();
#endif

View file

@ -75,9 +75,6 @@ static inline void put_uint16_t(uint16_t n, uint8_t *b) {
extern void low_flash_available();
extern int flash_clear_file(file_t *file);
extern void timeout_stop();
extern void timeout_start();
extern int (*button_pressed_cb)(uint8_t);
enum {

View file

@ -20,6 +20,11 @@
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
#include "hardware/rtc.h"
#endif
#ifndef ESP_PLATFORM
#include "bsp/board.h"
#else
static portMUX_TYPE mutex = portMUX_INITIALIZER_UNLOCKED;
#endif
#include "tusb.h"
#include "ccid.h"
#include "device/usbd_pvt.h"
@ -72,7 +77,7 @@
#define CCID_THREAD_TERMINATED 0xffff
#define CCID_ACK_TIMEOUT 0x6600
struct ccid_header {
typedef struct {
uint8_t bMessageType;
uint32_t dwLength;
uint8_t bSlot;
@ -80,119 +85,159 @@ struct ccid_header {
uint8_t abRFU0;
uint16_t abRFU1;
uint8_t apdu; //Actually it is an array
} __attribute__((__packed__));
} __attribute__((__packed__)) ccid_header_t;
uint8_t ccid_status = 1;
static uint8_t itf_num;
static usb_buffer_t ccid_rx[ITF_SC_TOTAL] = {0}, ccid_tx[ITF_SC_TOTAL] = {0};
static write_status_t last_write_result[ITF_SC_TOTAL] = {0};
int driver_process_usb_packet_ccid(uint8_t itf, uint16_t rx_read);
void ccid_write_offset(uint8_t itf, uint16_t size, uint16_t offset) {
if (*usb_get_tx(itf) + offset != 0x81) {
DEBUG_PAYLOAD(usb_get_tx(itf) + offset, size + 10);
}
usb_write_offset(itf, size + 10, offset);
ccid_tx[itf].w_ptr += size + offset;
ccid_tx[itf].r_ptr += offset;
}
void ccid_write(uint8_t itf, uint16_t size) {
ccid_write_offset(itf, size, 0);
}
struct ccid_header *ccid_response[ITF_TOTAL];
struct ccid_header *ccid_header[ITF_TOTAL];
ccid_header_t *ccid_response[ITF_SC_TOTAL];
ccid_header_t *ccid_resp_fast[ITF_SC_TOTAL];
ccid_header_t *ccid_header[ITF_SC_TOTAL];
ccid_header_t ccid_response_last[ITF_SC_TOTAL];
uint8_t sc_itf_to_usb_itf(uint8_t itf) {
if (itf == ITF_SC_CCID) {
return ITF_CCID;
}
else if (itf == ITF_SC_WCID) {
return ITF_WCID;
}
return itf;
}
int driver_init_ccid(uint8_t itf) {
ccid_header[itf] = (struct ccid_header *) usb_get_rx(itf);
ccid_header[itf] = (ccid_header_t *) (ccid_rx[itf].buffer + ccid_rx[itf].r_ptr);
ccid_resp_fast[itf] = (ccid_header_t *) (ccid_tx[itf].buffer + sizeof(ccid_tx[itf].buffer) - 64);
// apdu.header = &ccid_header->apdu;
ccid_response[itf] = (struct ccid_header *) usb_get_tx(itf);
ccid_response[itf] = (ccid_header_t *) (ccid_tx[itf].buffer + ccid_tx[itf].w_ptr);
usb_set_timeout_counter(itf, 1500);
usb_set_timeout_counter(sc_itf_to_usb_itf(itf), 1500);
//ccid_tx[itf].w_ptr = ccid_tx[itf].r_ptr = 0;
return CCID_OK;
}
void tud_vendor_rx_cb(uint8_t itf) {
uint32_t len = tud_vendor_n_available(itf);
#ifdef USB_ITF_HID
itf += 2;
#endif
usb_rx(itf, NULL, len);
do {
uint16_t tlen = 0;
if (len > 0xFFFF) {
tlen = 0xFFFF;
}
else {
tlen = len;
}
tlen = tud_vendor_n_read(itf, ccid_rx[itf].buffer + ccid_rx[itf].w_ptr, tlen);
ccid_rx[itf].w_ptr += tlen;
driver_process_usb_packet_ccid(itf, tlen);
len -= tlen;
} while (len > 0);
}
void tud_vendor_tx_cb(uint8_t itf, uint32_t sent_bytes) {
#ifdef USB_ITF_HID
itf += 2;
if (sent_bytes) {
#ifdef ESP_PLATFORM
taskENTER_CRITICAL(&mutex);
#endif
usb_write_flush(itf);
if (last_write_result[itf] == WRITE_PENDING) {
last_write_result[itf] = WRITE_SUCCESS;
ccid_header_t *lresp = &ccid_response_last[itf];
if (lresp->bMessageType != CCID_DATA_BLOCK_RET || lresp->dwLength != 0 || lresp->bSlot != 0 || lresp->abRFU0 != CCID_CMD_STATUS_TIMEEXT) {
ccid_tx[itf].r_ptr += sent_bytes;
}
}
if (ccid_tx[itf].r_ptr >= ccid_tx[itf].w_ptr) {
ccid_tx[itf].r_ptr = ccid_tx[itf].w_ptr = 0;
}
#ifdef ESP_PLATFORM
taskEXIT_CRITICAL(&mutex);
#endif
}
}
int driver_write_ccid(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size) {
#ifdef USB_ITF_HID
itf -= 2;
#endif
int r = tud_vendor_n_write(itf, buffer, buffer_size);
if (r > 0) {
return MAX(tud_vendor_n_flush(itf), r);
int driver_write_ccid(uint8_t itf, const uint8_t *tx_buffer, uint16_t buffer_size) {
if (last_write_result[itf] == WRITE_PENDING) {
return 0;
}
memcpy(&ccid_response_last[itf], tx_buffer, 10);
if (*tx_buffer != 0x81) {
DEBUG_PAYLOAD(tx_buffer, buffer_size);
}
int r = tud_vendor_n_write(itf, tx_buffer, buffer_size);
last_write_result[itf] = r == buffer_size ? WRITE_PENDING : WRITE_FAILED;
if (r == buffer_size) {
r = tud_vendor_n_flush(itf);
}
return r;
}
uint16_t driver_read_ccid(uint8_t itf, uint8_t *buffer, uint16_t buffer_size) {
#ifdef USB_ITF_HID
itf -= 2;
#endif
return tud_vendor_n_read(itf, buffer, buffer_size);
}
int driver_process_usb_nopacket_ccid() {
return 0;
}
int driver_process_usb_packet_ccid(uint8_t itf, uint16_t rx_read) {
if (rx_read >= 10) {
if (ccid_rx[itf].w_ptr - ccid_rx[itf].r_ptr >= 10) {
driver_init_ccid(itf);
//printf("%ld %d %x %x\n",ccid_header->dwLength,rx_read-10,ccid_header->bMessageType,ccid_header->bSeq);
if (ccid_header[itf]->dwLength <= rx_read - 10) {
//printf("ccid_process %ld %d %x %x %d\n",ccid_header[itf]->dwLength,rx_read-10,ccid_header[itf]->bMessageType,ccid_header[itf]->bSeq,ccid_rx[itf].w_ptr - ccid_rx[itf].r_ptr - 10);
if (ccid_header[itf]->dwLength <= ccid_rx[itf].w_ptr - ccid_rx[itf].r_ptr - 10){
ccid_rx[itf].r_ptr += ccid_header[itf]->dwLength + 10;
if (ccid_rx[itf].r_ptr >= ccid_rx[itf].w_ptr) {
ccid_rx[itf].r_ptr = ccid_rx[itf].w_ptr = 0;
}
size_t apdu_sent = 0;
if (ccid_header[itf]->bMessageType != CCID_SLOT_STATUS) {
DEBUG_PAYLOAD(usb_get_rx(itf), usb_read_available(itf));
DEBUG_PAYLOAD((uint8_t *)ccid_header[itf], ccid_header[itf]->dwLength + 10);
}
if (ccid_header[itf]->bMessageType == CCID_SLOT_STATUS) {
ccid_response[itf]->bMessageType = CCID_SLOT_STATUS_RET;
ccid_response[itf]->dwLength = 0;
ccid_response[itf]->bSlot = 0;
ccid_response[itf]->bSeq = ccid_header[itf]->bSeq;
ccid_response[itf]->abRFU0 = ccid_status;
ccid_response[itf]->abRFU1 = 0;
ccid_write(itf, 0);
ccid_resp_fast[itf]->bMessageType = CCID_SLOT_STATUS_RET;
ccid_resp_fast[itf]->dwLength = 0;
ccid_resp_fast[itf]->bSlot = 0;
ccid_resp_fast[itf]->bSeq = ccid_header[itf]->bSeq;
ccid_resp_fast[itf]->abRFU0 = ccid_status;
ccid_resp_fast[itf]->abRFU1 = 0;
driver_write_ccid(itf, (const uint8_t *)ccid_resp_fast[itf], 10);
}
else if (ccid_header[itf]->bMessageType == CCID_POWER_ON) {
size_t size_atr = (ccid_atr ? ccid_atr[0] : 0);
ccid_response[itf]->bMessageType = CCID_DATA_BLOCK_RET;
ccid_response[itf]->dwLength = size_atr;
ccid_response[itf]->bSlot = 0;
ccid_response[itf]->bSeq = ccid_header[itf]->bSeq;
ccid_response[itf]->abRFU0 = 0;
ccid_response[itf]->abRFU1 = 0;
//printf("1 %x %x %x || %x %x %x\n",ccid_response->apdu,apdu.rdata,ccid_response,ccid_header,ccid_header->apdu,apdu.data);
memcpy(&ccid_response[itf]->apdu, ccid_atr + 1, size_atr);
ccid_resp_fast[itf]->bMessageType = CCID_DATA_BLOCK_RET;
ccid_resp_fast[itf]->dwLength = size_atr;
ccid_resp_fast[itf]->bSlot = 0;
ccid_resp_fast[itf]->bSeq = ccid_header[itf]->bSeq;
ccid_resp_fast[itf]->abRFU0 = 0;
ccid_resp_fast[itf]->abRFU1 = 0;
//printf("1 %x %x %x || %x %x %x\n",ccid_resp_fast->apdu,apdu.rdata,ccid_resp_fast,ccid_header,ccid_header->apdu,apdu.data);
memcpy(&ccid_resp_fast[itf]->apdu, ccid_atr + 1, size_atr);
if (ccid_status == 1) {
//card_start(apdu_thread);
}
ccid_status = 0;
ccid_write(itf, size_atr);
driver_write_ccid(itf, (const uint8_t *)ccid_resp_fast[itf], size_atr + 10);
}
else if (ccid_header[itf]->bMessageType == CCID_POWER_OFF) {
if (ccid_status == 0) {
//card_exit(0);
}
ccid_status = 1;
ccid_response[itf]->bMessageType = CCID_SLOT_STATUS_RET;
ccid_response[itf]->dwLength = 0;
ccid_response[itf]->bSlot = 0;
ccid_response[itf]->bSeq = ccid_header[itf]->bSeq;
ccid_response[itf]->abRFU0 = ccid_status;
ccid_response[itf]->abRFU1 = 0;
ccid_write(itf, 0);
ccid_resp_fast[itf]->bMessageType = CCID_SLOT_STATUS_RET;
ccid_resp_fast[itf]->dwLength = 0;
ccid_resp_fast[itf]->bSlot = 0;
ccid_resp_fast[itf]->bSeq = ccid_header[itf]->bSeq;
ccid_resp_fast[itf]->abRFU0 = ccid_status;
ccid_resp_fast[itf]->abRFU1 = 0;
driver_write_ccid(itf, (const uint8_t *)ccid_resp_fast[itf], 10);
}
else if (ccid_header[itf]->bMessageType == CCID_SET_PARAMS ||
ccid_header[itf]->bMessageType == CCID_GET_PARAMS ||
@ -207,19 +252,23 @@ int driver_process_usb_packet_ccid(uint8_t itf, uint16_t rx_read) {
0xFE, /* bIFSC */
0 /* bNadValue */
};
ccid_response[itf]->bMessageType = CCID_PARAMS_RET;
ccid_response[itf]->dwLength = sizeof(params);
ccid_response[itf]->bSlot = 0;
ccid_response[itf]->bSeq = ccid_header[itf]->bSeq;
ccid_response[itf]->abRFU0 = ccid_status;
ccid_response[itf]->abRFU1 = 0x0100;
memcpy(&ccid_response[itf]->apdu, params, sizeof(params));
ccid_write(itf, sizeof(params));
ccid_resp_fast[itf]->bMessageType = CCID_PARAMS_RET;
ccid_resp_fast[itf]->dwLength = sizeof(params);
ccid_resp_fast[itf]->bSlot = 0;
ccid_resp_fast[itf]->bSeq = ccid_header[itf]->bSeq;
ccid_resp_fast[itf]->abRFU0 = ccid_status;
ccid_resp_fast[itf]->abRFU1 = 0x0100;
memcpy(&ccid_resp_fast[itf]->apdu, params, sizeof(params));
driver_write_ccid(itf, (const uint8_t *)ccid_resp_fast[itf], sizeof(params) + 10);
}
else if (ccid_header[itf]->bMessageType == CCID_XFR_BLOCK) {
apdu.rdata = &ccid_response[itf]->apdu;
apdu_sent = apdu_process(itf, &ccid_header[itf]->apdu, ccid_header[itf]->dwLength);
if (apdu_sent > 0) {
card_start(sc_itf_to_usb_itf(itf), apdu_thread);
usb_send_event(EV_CMD_AVAILABLE);
}
}
usb_clear_rx(itf);
return apdu_sent;
}
}
@ -227,54 +276,51 @@ int driver_process_usb_packet_ccid(uint8_t itf, uint16_t rx_read) {
}
bool driver_mounted_ccid(uint8_t itf) {
#ifdef USB_ITF_HID
itf -= 2;
#endif
return tud_vendor_n_mounted(itf);
}
void driver_exec_timeout_ccid(uint8_t itf) {
ccid_header[itf] = (struct ccid_header *) usb_get_rx(itf);
ccid_response[itf] = (struct ccid_header *) (usb_get_tx(itf));
ccid_response[itf]->bMessageType = CCID_DATA_BLOCK_RET;
ccid_response[itf]->dwLength = 0;
ccid_response[itf]->bSlot = 0;
ccid_response[itf]->bSeq = ccid_header[itf]->bSeq;
ccid_response[itf]->abRFU0 = CCID_CMD_STATUS_TIMEEXT;
ccid_response[itf]->abRFU1 = 0;
ccid_write(itf, 0);
ccid_resp_fast[itf]->bMessageType = CCID_DATA_BLOCK_RET;
ccid_resp_fast[itf]->dwLength = 0;
ccid_resp_fast[itf]->bSlot = 0;
ccid_resp_fast[itf]->bSeq = ccid_header[itf]->bSeq;
ccid_resp_fast[itf]->abRFU0 = CCID_CMD_STATUS_TIMEEXT;
ccid_resp_fast[itf]->abRFU1 = 0;
driver_write_ccid(itf, (const uint8_t *)ccid_resp_fast[itf], 10);
}
void driver_exec_finished_ccid(uint8_t itf, uint16_t size_next) {
ccid_header[itf] = (struct ccid_header *) usb_get_rx(itf);
ccid_response[itf] = (struct ccid_header *) (usb_get_tx(itf) + 34);
ccid_response[itf]->bMessageType = CCID_DATA_BLOCK_RET;
ccid_response[itf]->dwLength = size_next;
ccid_response[itf]->bSlot = 0;
ccid_response[itf]->bSeq = ccid_header[itf]->bSeq;
ccid_response[itf]->abRFU0 = ccid_status;
ccid_response[itf]->abRFU1 = 0;
ccid_write_offset(itf, size_next, 34);
driver_exec_finished_cont_ccid(itf, size_next, 0);
}
void driver_exec_finished_cont_ccid(uint8_t itf, uint16_t size_next, uint16_t offset) {
ccid_header[itf] = (struct ccid_header *) usb_get_rx(itf);
ccid_response[itf] = (struct ccid_header *) (usb_get_tx(itf) + offset - 10 + 34);
//ccid_response[itf] = (ccid_header_t *) (ccid_tx[itf].buffer + ccid_tx[itf].w_ptr + offset);
ccid_response[itf]->bMessageType = CCID_DATA_BLOCK_RET;
ccid_response[itf]->dwLength = size_next;
ccid_response[itf]->bSlot = 0;
ccid_response[itf]->bSeq = ccid_header[itf]->bSeq;
ccid_response[itf]->abRFU0 = ccid_status;
ccid_response[itf]->abRFU1 = 0;
ccid_write_offset(itf, size_next, offset - 10 + 34);
ccid_write_offset(itf, size_next+10, offset);
}
uint8_t *driver_prepare_response_ccid(uint8_t itf) {
ccid_response[itf] = (struct ccid_header *) (usb_get_tx(itf) + 34);
apdu.rdata = &ccid_response[itf]->apdu;
apdu.rlen = 0;
return &ccid_response[itf]->apdu;
void ccid_task() {
for (int itf = 0; itf < ITF_SC_TOTAL; itf++) {
int status = card_status(sc_itf_to_usb_itf(itf));
if (status == CCID_OK) {
driver_exec_finished_ccid(itf, finished_data_size);
}
else if (status == CCID_ERR_BLOCKED) {
driver_exec_timeout_ccid(itf);
}
if (ccid_tx[itf].w_ptr > ccid_tx[itf].r_ptr && last_write_result[itf] != WRITE_PENDING) {
if (driver_write_ccid(itf, ccid_tx[itf].buffer + ccid_tx[itf].r_ptr, ccid_tx[itf].w_ptr - ccid_tx[itf].r_ptr) > 0) {
}
}
}
}
#define USB_CONFIG_ATT_ONE TU_BIT(7)
#define MAX_USB_POWER 1

View file

@ -33,6 +33,8 @@ typedef unsigned long int uint64_t;
extern "C" {
#endif
#include "usb.h"
// Size of HID reports
#define HID_RPT_SIZE 64 // Default size of raw HID report
@ -145,6 +147,7 @@ typedef struct {
// Low-level error codes. Return as negatives.
#define CTAP_MAX_PACKET_SIZE (64 - 7 + 128 * (64 - 5))
#define CTAP_MAX_CBOR_PAYLOAD (USB_BUFFER_SIZE - 64 - 7 - 1)
#define CTAP1_ERR_NONE 0x00 // No error
#define CTAP1_ERR_INVALID_CMD 0x01 // Invalid command
@ -162,13 +165,6 @@ extern void append_keyboard_buffer(const uint8_t *data, size_t data_len);
extern bool is_nitrokey;
typedef enum {
WRITE_UNKNOWN = 0,
WRITE_PENDING,
WRITE_FAILED,
WRITE_SUCCESS,
} write_status_t;
#ifdef __cplusplus
}
#endif

View file

@ -19,6 +19,8 @@
#include "tusb.h"
#ifndef ESP_PLATFORM
#include "bsp/board.h"
#else
static portMUX_TYPE mutex = portMUX_INITIALIZER_UNLOCKED;
#endif
#endif
#include "ctap_hid.h"
@ -28,11 +30,12 @@
#include "usb.h"
static bool mounted = false;
void (*init_fido_cb)() = NULL;
extern void init_fido();
bool is_nitrokey = false;
uint8_t (*get_version_major)() = NULL;
uint8_t (*get_version_minor)() = NULL;
int (*cbor_process_cb)(uint8_t, const uint8_t *, size_t) = NULL;
static usb_buffer_t hid_rx[ITF_HID_TOTAL] = {0}, hid_tx[ITF_HID_TOTAL] = {0};
typedef struct msg_packet {
uint16_t len;
@ -50,8 +53,15 @@ bool driver_mounted_hid() {
return mounted;
}
static uint16_t send_buffer_size[ITF_HID_TOTAL] = {0};
static write_status_t last_write_result[ITF_HID_TOTAL] = {0};
CTAPHID_FRAME *ctap_req = NULL, *ctap_resp = NULL;
void send_keepalive();
int driver_process_usb_packet_hid(uint16_t read);
int driver_write_hid(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size);
int driver_process_usb_nopacket_hid();
int driver_init_hid() {
#ifndef ENABLE_EMULATION
static bool _init = false;
@ -60,21 +70,22 @@ int driver_init_hid() {
_init = true;
}
#endif
ctap_req = (CTAPHID_FRAME *) (usb_get_rx(ITF_HID) + usb_get_r_offset(ITF_HID));
ctap_req = (CTAPHID_FRAME *) (hid_rx[ITF_HID_CTAP].buffer + hid_rx[ITF_HID_CTAP].r_ptr);
apdu.header = ctap_req->init.data;
ctap_resp = (CTAPHID_FRAME *) usb_get_tx(ITF_HID);
ctap_resp = (CTAPHID_FRAME *) (hid_tx[ITF_HID_CTAP].buffer);
apdu.rdata = ctap_resp->init.data;
//memset(ctap_resp, 0, sizeof(CTAPHID_FRAME));
usb_set_timeout_counter(ITF_HID, 200);
is_nitrokey = false;
hid_tx[ITF_HID_CTAP].w_ptr = hid_tx[ITF_HID_CTAP].r_ptr = 0;
send_buffer_size[ITF_HID_CTAP] = 0;
return 0;
}
uint16_t send_buffer_size[ITF_TOTAL] = {0};
write_status_t last_write_result[ITF_TOTAL] = {0};
uint16_t *get_send_buffer_size(uint8_t itf) {
return &send_buffer_size[itf];
}
@ -111,10 +122,12 @@ uint16_t tud_hid_get_report_cb(uint8_t itf,
#endif
uint32_t hid_write_offset(uint16_t size, uint16_t offset) {
if (*usb_get_tx(ITF_HID) != 0x81) {
DEBUG_PAYLOAD(usb_get_tx(ITF_HID) + offset, size);
if (hid_tx[ITF_HID_CTAP].buffer[offset] != 0x81) {
DEBUG_PAYLOAD(&hid_tx[ITF_HID_CTAP].buffer[offset], size);
}
return usb_write_offset(ITF_HID, size, offset);
hid_tx[ITF_HID_CTAP].w_ptr += size + offset;
hid_tx[ITF_HID_CTAP].r_ptr += offset;
return size;
}
uint32_t hid_write(uint16_t size) {
@ -166,14 +179,12 @@ static void send_hid_report(uint8_t report_id) {
}
keycode[0] = chr & 0x7f;
}
if (tud_hid_n_keyboard_report(ITF_KEYBOARD, REPORT_ID_KEYBOARD, modifier,
keycode) == true) {
if (tud_hid_n_keyboard_report(ITF_HID_KB, REPORT_ID_KEYBOARD, modifier, keycode) == true) {
sent_key = true;
}
}
else {
if (tud_hid_n_keyboard_report(ITF_KEYBOARD, REPORT_ID_KEYBOARD, 0,
NULL) == true) {
if (tud_hid_n_keyboard_report(ITF_HID_KB, REPORT_ID_KEYBOARD, 0, NULL) == true) {
keyboard_w++;
sent_key = false;
@ -190,7 +201,27 @@ static void send_hid_report(uint8_t report_id) {
}
}
void hid_task(void) {
void hid_task() {
int proc_pkt = 0;
if (hid_rx[ITF_HID_CTAP].w_ptr - hid_rx[ITF_HID_CTAP].r_ptr >= 64) {
//proc_pkt = driver_process_usb_packet_hid(64);
}
if (proc_pkt == 0) {
driver_process_usb_nopacket_hid();
}
int status = card_status(ITF_HID);
if (status == CCID_OK) {
driver_exec_finished_hid(finished_data_size);
}
else if (status == CCID_ERR_BLOCKED) {
send_keepalive();
}
if (hid_tx[ITF_HID_CTAP].w_ptr > hid_tx[ITF_HID_CTAP].r_ptr && last_write_result[ITF_HID_CTAP] != WRITE_PENDING) {
if (driver_write_hid(ITF_HID_CTAP, hid_tx[ITF_HID_CTAP].buffer + hid_tx[ITF_HID_CTAP].r_ptr, 64) > 0) {
}
}
/* Keyboard ITF */
// Poll every 10ms
const uint32_t interval_ms = 10;
static uint32_t start_ms = 0;
@ -211,7 +242,11 @@ void hid_task(void) {
#endif
void tud_hid_report_complete_cb(uint8_t instance, uint8_t const *report, uint16_t len) {
if (instance == ITF_HID && len > 0) {
printf("report_complete %d %d %d\n", instance, len, send_buffer_size[instance]);
if (instance == ITF_HID_CTAP && len > 0) {
#ifdef ESP_PLATFORM
taskENTER_CRITICAL(&mutex);
#endif
CTAPHID_FRAME *ctap_req = (CTAPHID_FRAME *) report;
if (last_write_result[instance] == WRITE_PENDING) {
last_write_result[instance] = WRITE_SUCCESS;
@ -224,19 +259,28 @@ void tud_hid_report_complete_cb(uint8_t instance, uint8_t const *report, uint16_
send_buffer_size[instance] -= MIN(64 - 5, send_buffer_size[instance]);
}
}
if (send_buffer_size[instance] > 0) {
if (last_write_result[instance] == WRITE_SUCCESS) {
if (FRAME_TYPE(ctap_req) != TYPE_INIT || ctap_req->init.cmd != CTAPHID_KEEPALIVE) {
if (send_buffer_size[instance] > 0) {
ctap_resp = (CTAPHID_FRAME *) ((uint8_t *) ctap_resp + 64 - 5);
}
uint8_t seq = FRAME_TYPE(ctap_req) == TYPE_INIT ? 0 : FRAME_SEQ(ctap_req) + 1;
ctap_resp->cid = ctap_req->cid;
ctap_resp->cont.seq = seq;
hid_tx[ITF_HID_CTAP].r_ptr += 64 - 5;
}
if (hid_write_offset(64, (uint8_t *) ctap_resp - (usb_get_tx(ITF_HID))) > 0) {
else {
hid_tx[ITF_HID_CTAP].r_ptr += 64;
}
}
}
if (hid_tx[ITF_HID_CTAP].r_ptr >= hid_tx[ITF_HID_CTAP].w_ptr) {
hid_tx[ITF_HID_CTAP].r_ptr = hid_tx[ITF_HID_CTAP].w_ptr = 0;
}
#ifdef ESP_PLATFORM
taskEXIT_CRITICAL(&mutex);
#endif
}
}
#ifndef ENABLE_EMULATION
@ -253,43 +297,38 @@ int driver_write_hid(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size) {
}
#endif
uint16_t driver_read_hid(uint8_t *buffer, uint16_t buffer_size) {
return 0;
}
#ifndef ENABLE_EMULATION
int (*hid_set_report_cb)(uint8_t, uint8_t, hid_report_type_t, uint8_t const *, uint16_t) = NULL;
// Invoked when received SET_REPORT control request or
// received data on OUT endpoint ( Report ID = 0, Type = 0 )
void tud_hid_set_report_cb(uint8_t itf,
uint8_t report_id,
hid_report_type_t report_type,
uint8_t const *buffer,
uint16_t bufsize)
{
void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {
// This example doesn't use multiple report and report ID
(void) itf;
(void) report_id;
(void) report_type;
printf("set_report %d %d %d\n", itf, report_id, report_type);
if (!hid_set_report_cb || hid_set_report_cb(itf, report_id, report_type, buffer, bufsize) == 0) {
usb_rx(itf, buffer, bufsize);
//usb_rx(itf, buffer, bufsize);
memcpy(hid_rx[itf].buffer + hid_rx[itf].w_ptr, buffer, bufsize);
hid_rx[itf].w_ptr += bufsize;
int proc_pkt = driver_process_usb_packet_hid(64);
if (proc_pkt == 0) {
driver_process_usb_nopacket_hid();
}
}
}
#endif
uint32_t last_cmd_time = 0, last_packet_time = 0;
int ctap_error(uint8_t error) {
ctap_resp = (CTAPHID_FRAME *) usb_get_tx(ITF_HID);
memset(ctap_resp, 0, sizeof(CTAPHID_FRAME));
memset((uint8_t *)ctap_resp, 0, sizeof(CTAPHID_FRAME));
ctap_resp->cid = ctap_req->cid;
ctap_resp->init.cmd = CTAPHID_ERROR;
ctap_resp->init.bcntl = 1;
ctap_resp->init.data[0] = error;
hid_write(64);
usb_clear_rx(ITF_HID);
last_packet_time = 0;
return 0;
}
@ -301,6 +340,7 @@ uint32_t lock = 0;
uint8_t thread_type = 0; //1 is APDU, 2 is CBOR
extern bool cancel_button;
extern int cbor_process(uint8_t last_cmd, const uint8_t *data, size_t len);
int driver_process_usb_nopacket_hid() {
if (last_packet_time > 0 && last_packet_time + 500 < board_millis()) {
@ -312,16 +352,21 @@ int driver_process_usb_nopacket_hid() {
}
extern const uint8_t fido_aid[], u2f_aid[];
extern void apdu_thread(), cbor_thread();
int driver_process_usb_packet_hid(uint16_t read) {
int apdu_sent = 0;
if (read >= 5) {
driver_init_hid();
hid_rx[ITF_HID_CTAP].r_ptr += 64;
if (hid_rx[ITF_HID_CTAP].r_ptr >= hid_rx[ITF_HID_CTAP].w_ptr) {
hid_rx[ITF_HID_CTAP].r_ptr = hid_rx[ITF_HID_CTAP].w_ptr = 0;
}
last_packet_time = board_millis();
DEBUG_PAYLOAD(usb_get_rx(ITF_HID) + usb_get_r_offset(ITF_HID), 64);
memset(ctap_resp, 0, sizeof(CTAPHID_FRAME));
DEBUG_PAYLOAD((uint8_t *)ctap_req, 64);
if (ctap_req->cid == 0x0 ||
(ctap_req->cid == CID_BROADCAST && ctap_req->init.cmd != CTAPHID_INIT)) {
(ctap_req->cid == CID_BROADCAST && (FRAME_TYPE(ctap_req) != TYPE_INIT || ctap_req->init.cmd != CTAPHID_INIT))) {
return ctap_error(CTAP1_ERR_INVALID_CHANNEL);
}
if (board_millis() < lock && ctap_req->cid != last_req.cid &&
@ -371,15 +416,11 @@ int driver_process_usb_packet_hid(uint16_t read) {
else if (last_cmd_time + 100 > board_millis()) {
return ctap_error(CTAP1_ERR_CHANNEL_BUSY);
}
}
if (ctap_req->init.cmd == CTAPHID_INIT) {
if (init_fido_cb) {
init_fido_cb();
}
ctap_resp = (CTAPHID_FRAME *) usb_get_tx(ITF_HID);
memset(ctap_resp, 0, 64);
card_exit();
hid_tx[ITF_HID_CTAP].r_ptr = hid_tx[ITF_HID_CTAP].w_ptr = 0;
init_fido();
CTAPHID_INIT_REQ *req = (CTAPHID_INIT_REQ *) ctap_req->init.data;
CTAPHID_INIT_RESP *resp = (CTAPHID_INIT_RESP *) ctap_resp->init.data;
memcpy(resp->nonce, req->nonce, sizeof(resp->nonce));
@ -393,7 +434,7 @@ int driver_process_usb_packet_hid(uint16_t read) {
ctap_resp->init.cmd = CTAPHID_INIT;
ctap_resp->init.bcntl = 17;
ctap_resp->init.bcnth = 0;
hid_write(64);
driver_write_hid(ITF_HID_CTAP, (const uint8_t *)ctap_resp, 64);
msg_packet.len = msg_packet.current_len = 0;
last_packet_time = 0;
}
@ -401,19 +442,17 @@ int driver_process_usb_packet_hid(uint16_t read) {
if (MSG_LEN(ctap_req) != 0) {
return ctap_error(CTAP1_ERR_INVALID_LEN);
}
ctap_resp = (CTAPHID_FRAME *) usb_get_tx(ITF_HID);
last_packet_time = 0;
memcpy(ctap_resp, ctap_req, sizeof(CTAPHID_FRAME));
#ifndef ENABLE_EMULATION
sleep_ms(1000); //For blinking the device during 1 seg
#endif
hid_write(64);
driver_write_hid(ITF_HID_CTAP, (const uint8_t *)ctap_resp, 64);
msg_packet.len = msg_packet.current_len = 0;
last_packet_time = 0;
}
else if ((last_cmd == CTAPHID_PING || last_cmd == CTAPHID_SYNC) &&
(msg_packet.len == 0 ||
(msg_packet.len == msg_packet.current_len && msg_packet.len > 0))) {
ctap_resp = (CTAPHID_FRAME *) usb_get_tx(ITF_HID);
if (msg_packet.current_len == msg_packet.len && msg_packet.len > 0) {
memcpy(ctap_resp->init.data, msg_packet.data, msg_packet.len);
driver_exec_finished_hid(msg_packet.len);
@ -424,7 +463,7 @@ int driver_process_usb_packet_hid(uint16_t read) {
ctap_resp->init.cmd = last_cmd;
ctap_resp->init.bcnth = MSG_LEN(ctap_req) >> 8;
ctap_resp->init.bcntl = MSG_LEN(ctap_req) & 0xff;
hid_write(64);
driver_write_hid(ITF_HID_CTAP, (const uint8_t *)ctap_resp, 64);
}
msg_packet.len = msg_packet.current_len = 0;
last_packet_time = 0;
@ -437,47 +476,39 @@ int driver_process_usb_packet_hid(uint16_t read) {
return ctap_error(CTAP1_ERR_INVALID_PARAMETER);
}
lock = board_millis() + ctap_req->init.data[0] * 1000;
ctap_resp = (CTAPHID_FRAME *) usb_get_tx(ITF_HID);
memset(ctap_resp, 0, 64);
ctap_resp->cid = ctap_req->cid;
ctap_resp->init.cmd = ctap_req->init.cmd;
hid_write(64);
driver_write_hid(ITF_HID_CTAP, (const uint8_t *)ctap_resp, 64);
msg_packet.len = msg_packet.current_len = 0;
last_packet_time = 0;
}
else if (ctap_req->init.cmd == CTAPHID_UUID) {
ctap_resp = (CTAPHID_FRAME *) usb_get_tx(ITF_HID);
memset(ctap_resp, 0, 64);
ctap_resp->cid = ctap_req->cid;
ctap_resp->init.cmd = ctap_req->init.cmd;
memcpy(ctap_resp->init.data, pico_serial.id, sizeof(pico_serial.id));
ctap_resp->init.bcntl = 16;
hid_write(64);
driver_write_hid(ITF_HID_CTAP, (const uint8_t *)ctap_resp, 64);
msg_packet.len = msg_packet.current_len = 0;
last_packet_time = 0;
}
else if (ctap_req->init.cmd == CTAPHID_VERSION) {
ctap_resp = (CTAPHID_FRAME *) usb_get_tx(ITF_HID);
memset(ctap_resp, 0, 64);
ctap_resp->cid = ctap_req->cid;
ctap_resp->init.cmd = ctap_req->init.cmd;
ctap_resp->init.data[0] = PICO_KEYS_SDK_VERSION_MAJOR;
ctap_resp->init.data[1] = PICO_KEYS_SDK_VERSION_MINOR;
ctap_resp->init.bcntl = 4;
hid_write(64);
driver_write_hid(ITF_HID_CTAP, (const uint8_t *)ctap_resp, 64);
msg_packet.len = msg_packet.current_len = 0;
last_packet_time = 0;
}
else if (ctap_req->init.cmd == CTAPHID_ADMIN) {
ctap_resp = (CTAPHID_FRAME *) usb_get_tx(ITF_HID);
memset(ctap_resp, 0, 64);
ctap_resp->cid = ctap_req->cid;
ctap_resp->init.cmd = ctap_req->init.cmd;
if (ctap_req->init.data[0] == 0x80) { // Status
memcpy(ctap_resp->init.data, "\x00\xff\xff\xff\x00", 5);
ctap_resp->init.bcntl = 5;
}
hid_write(64);
driver_write_hid(ITF_HID_CTAP, (const uint8_t *)ctap_resp, 64);
msg_packet.len = msg_packet.current_len = 0;
last_packet_time = 0;
}
@ -497,10 +528,10 @@ int driver_process_usb_packet_hid(uint16_t read) {
thread_type = 1;
if (msg_packet.current_len == msg_packet.len && msg_packet.len > 0) {
apdu_sent = apdu_process(ITF_HID, msg_packet.data, msg_packet.len);
apdu_sent = apdu_process(ITF_HID_CTAP, msg_packet.data, msg_packet.len);
}
else {
apdu_sent = apdu_process(ITF_HID, ctap_req->init.data, MSG_LEN(ctap_req));
apdu_sent = apdu_process(ITF_HID_CTAP, ctap_req->init.data, MSG_LEN(ctap_req));
}
DEBUG_PAYLOAD(apdu.data, (int) apdu.nc);
msg_packet.len = msg_packet.current_len = 0;
@ -512,13 +543,11 @@ int driver_process_usb_packet_hid(uint16_t read) {
(msg_packet.len == msg_packet.current_len && msg_packet.len > 0))) {
thread_type = 2;
select_app(fido_aid + 1, fido_aid[0]);
if (cbor_process_cb) {
if (msg_packet.current_len == msg_packet.len && msg_packet.len > 0) {
apdu_sent = cbor_process_cb(last_cmd, msg_packet.data, msg_packet.len);
apdu_sent = cbor_process(last_cmd, msg_packet.data, msg_packet.len);
}
else {
apdu_sent = cbor_process_cb(last_cmd, ctap_req->init.data, MSG_LEN(ctap_req));
}
apdu_sent = cbor_process(last_cmd, ctap_req->init.data, MSG_LEN(ctap_req));
}
msg_packet.len = msg_packet.current_len = 0;
last_packet_time = 0;
@ -541,34 +570,28 @@ int driver_process_usb_packet_hid(uint16_t read) {
// echo back anything we received from host
//tud_hid_report(0, buffer, bufsize);
//printf("END\n");
usb_more_rx(ITF_HID, 64);
if (apdu_sent > 0) {
if (apdu_sent == 1) {
card_start(ITF_HID, apdu_thread);
}
else if (apdu_sent == 2) {
card_start(ITF_HID, cbor_thread);
}
usb_send_event(EV_CMD_AVAILABLE);
}
}
return apdu_sent;
}
void send_keepalive() {
CTAPHID_FRAME *resp = (CTAPHID_FRAME *) (usb_get_tx(ITF_HID) + 4096);
CTAPHID_FRAME *resp = (CTAPHID_FRAME *) (hid_tx[ITF_HID_CTAP].buffer + sizeof(hid_tx[ITF_HID_CTAP].buffer) - 64);
//memset(ctap_resp, 0, sizeof(CTAPHID_FRAME));
resp->cid = ctap_req->cid;
resp->init.cmd = CTAPHID_KEEPALIVE;
resp->init.bcntl = 1;
resp->init.data[0] = is_req_button_pending() ? 2 : 1;
//send_buffer_size[ITF_HID] = 0;
hid_write_offset(64, 4096);
}
void driver_exec_timeout_hid() {
if (thread_type == 2) {
send_keepalive();
}
}
uint8_t *driver_prepare_response_hid() {
ctap_resp = (CTAPHID_FRAME *) usb_get_tx(ITF_HID);
apdu.rdata = ctap_resp->init.data;
send_buffer_size[ITF_HID] = 0;
memset(usb_get_tx(ITF_HID), 0, 4096);
return ctap_resp->init.data;
//send_buffer_size[ITF_HID_CTAP] = 0;
driver_write_hid(ITF_HID_CTAP, (const uint8_t *)resp, 64);
}
void driver_exec_finished_hid(uint16_t size_next) {
@ -582,7 +605,7 @@ void driver_exec_finished_hid(uint16_t size_next) {
apdu.rdata[0] = apdu.sw >> 8;
apdu.rdata[1] = apdu.sw & 0xff;
}
driver_exec_finished_cont_hid(ITF_HID, size_next, 7);
driver_exec_finished_cont_hid(ITF_HID_CTAP, size_next, 7);
}
}
apdu.sw = 0;
@ -590,14 +613,14 @@ void driver_exec_finished_hid(uint16_t size_next) {
void driver_exec_finished_cont_hid(uint8_t itf, uint16_t size_next, uint16_t offset) {
offset -= 7;
ctap_resp = (CTAPHID_FRAME *) (usb_get_tx(itf) + offset);
ctap_resp = (CTAPHID_FRAME *) (hid_tx[itf].buffer + offset);
ctap_resp->cid = ctap_req->cid;
ctap_resp->init.cmd = last_cmd;
ctap_resp->init.bcnth = size_next >> 8;
ctap_resp->init.bcntl = size_next & 0xff;
send_buffer_size[itf] = size_next;
if (hid_write_offset(64, offset) > 0) {
ctap_resp->init.cmd = last_cmd;
if (hid_write_offset(size_next+7, offset) > 0) {
//ctap_resp = (CTAPHID_FRAME *) ((uint8_t *) ctap_resp + 64 - 5);
//send_buffer_size[ITF_HID] -= MIN(64 - 7, send_buffer_size[ITF_HID]);
//send_buffer_size[ITF_HID_CTAP] -= MIN(64 - 7, send_buffer_size[ITF_HID_CTAP]);
}
}

View file

@ -35,138 +35,13 @@
#include <stdlib.h>
// Device specific functions
static uint8_t rx_buffer[ITF_TOTAL][4096] = { 0 }, tx_buffer[ITF_TOTAL][4096 + 64] = { 0 };
static uint16_t w_offset[ITF_TOTAL] = { 0 }, r_offset[ITF_TOTAL] = { 0 };
static uint16_t w_len[ITF_TOTAL] = { 0 }, tx_r_offset[ITF_TOTAL] = { 0 };
static uint32_t timeout_counter[ITF_TOTAL] = { 0 };
uint8_t card_locked_itf = ITF_TOTAL; // no locked
#ifndef ENABLE_EMULATION
static uint8_t proc_locked = 0;
#endif
void (*cbor_thread_func)() = NULL;
void usb_set_timeout_counter(uint8_t itf, uint32_t v) {
timeout_counter[itf] = v;
}
uint32_t usb_write_offset(uint8_t itf, uint16_t len, uint16_t offset) {
#ifndef ENABLE_EMULATION
uint8_t pkt_max = 64;
#endif
uint16_t w = 0;
if (len > sizeof(tx_buffer[itf])) {
len = sizeof(tx_buffer[itf]);
}
w_len[itf] = len;
tx_r_offset[itf] = offset;
#ifndef ENABLE_EMULATION
#ifdef USB_ITF_HID
if (itf == ITF_HID || itf == ITF_KEYBOARD) {
w = driver_write_hid(itf, tx_buffer[itf] + offset, MIN(len, pkt_max));
}
#endif
#ifdef USB_ITF_CCID
if (itf == ITF_CCID || itf == ITF_WCID) {
w = driver_write_ccid(itf, tx_buffer[itf] + offset, MIN(len, pkt_max));
}
#endif
#else
w = driver_write_emul(itf, tx_buffer[itf] + offset, len);
#endif
w_len[itf] -= w;
tx_r_offset[itf] += w;
return w;
}
#ifndef ENABLE_EMULATION
uint16_t usb_rx(uint8_t itf, const uint8_t *buffer, uint16_t len) {
uint16_t size = MIN((uint16_t)sizeof(rx_buffer[itf]) - w_offset[itf], (uint16_t)len);
if (size > 0) {
if (buffer == NULL) {
#ifdef USB_ITF_HID
if (itf == ITF_HID) {
size = driver_read_hid(rx_buffer[itf] + w_offset[itf], size);
}
#endif
#ifdef USB_ITF_CCID
if (itf == ITF_CCID || itf == ITF_WCID) {
size = (uint16_t)driver_read_ccid(itf, rx_buffer[itf] + w_offset[itf], size);
}
#endif
}
else {
memcpy(rx_buffer[itf] + w_offset[itf], buffer, size);
}
w_offset[itf] += size;
}
return size;
}
#endif
uint32_t usb_write_flush(uint8_t itf) {
uint16_t w = 0;
if (w_len[itf] > 0) {
#ifndef ENABLE_EMULATION
#ifdef USB_ITF_HID
if (itf == ITF_HID || itf == ITF_KEYBOARD) {
w = driver_write_hid(itf, tx_buffer[itf] + tx_r_offset[itf], MIN(w_len[itf], 64));
}
#endif
#ifdef USB_ITF_CCID
if (itf == ITF_CCID || itf == ITF_WCID) {
w = driver_write_ccid(itf, tx_buffer[itf] + tx_r_offset[itf], MIN(w_len[itf], 64));
}
#endif
#else
w = driver_write_emul(itf, tx_buffer[itf] + tx_r_offset[itf], w_len[itf]);
#endif
tx_r_offset[itf] += w;
w_len[itf] -= w;
}
return w;
}
uint32_t usb_write(uint8_t itf, uint16_t len) {
return usb_write_offset(itf, len, 0);
}
uint16_t usb_read_available(uint8_t itf) {
return w_offset[itf] - r_offset[itf];
}
uint16_t usb_write_available(uint8_t itf) {
return w_len[itf] > 0;
}
uint8_t *usb_get_rx(uint8_t itf) {
return rx_buffer[itf];
}
uint8_t *usb_get_tx(uint8_t itf) {
return tx_buffer[itf];
}
void usb_clear_rx(uint8_t itf) {
w_offset[itf] = r_offset[itf] = 0;
}
uint16_t usb_get_r_offset(uint8_t itf) {
return r_offset[itf];
}
uint16_t usb_more_rx(uint8_t itf, uint16_t len) {
if (len > w_offset[itf] - r_offset[itf]) {
len = w_offset[itf] - r_offset[itf];
}
r_offset[itf] += len;
if (r_offset[itf] == w_offset[itf]) {
r_offset[itf] = w_offset[itf] = 0;
return 0;
}
return usb_read_available(itf);
}
#if !defined(ENABLE_EMULATION)
queue_t usb_to_card_q;
queue_t card_to_usb_q;
@ -198,62 +73,24 @@ void usb_init() {
#endif
}
extern int driver_process_usb_nopacket();
extern uint32_t timeout;
uint32_t timeout = 0;
void timeout_stop() {
timeout = 0;
}
static int usb_event_handle(uint8_t itf) {
#ifndef ENABLE_EMULATION
uint16_t rx_read = usb_read_available(itf);
#else
uint16_t rx_read = emul_read(itf);
#endif
int proc_packet = 0;
#ifndef ENABLE_EMULATION
#ifdef USB_ITF_HID
if (itf == ITF_HID) {
proc_packet = driver_process_usb_packet_hid(rx_read);
void timeout_start() {
timeout = board_millis();
}
#endif
#ifdef USB_ITF_CCID
if (itf == ITF_CCID || itf == ITF_WCID) {
proc_packet = driver_process_usb_packet_ccid(itf, rx_read);
bool is_busy() {
return timeout > 0;
}
#endif
#else
proc_packet = driver_process_usb_packet_emul(itf, rx_read);
#endif
if (proc_packet > 0) {
card_locked_itf = itf;
timeout_start();
#ifndef ENABLE_EMULATION
if (proc_locked != proc_packet) {
if (proc_packet == 1) {
card_start(apdu_thread);
}
else if (proc_packet == 2) {
if (cbor_thread_func) {
card_start(cbor_thread_func);
}
}
proc_locked = proc_packet;
}
uint32_t flag = EV_CMD_AVAILABLE;
void usb_send_event(uint32_t flag) {
queue_add_blocking(&usb_to_card_q, &flag);
#endif
if (flag == EV_CMD_AVAILABLE) {
timeout_start();
}
else {
#ifdef USB_ITF_HID
if (itf == ITF_HID) {
driver_process_usb_nopacket_hid();
}
#endif
#ifdef USB_ITF_CCID
//if (itf == ITF_CCID) {
// driver_process_usb_nopacket_ccid();
//}
#endif
}
return 0;
}
extern void low_flash_init();
@ -265,7 +102,9 @@ void card_init_core1() {
uint16_t finished_data_size = 0;
void card_start(void (*func)(void)) {
void card_start(uint8_t itf, void (*func)(void)) {
timeout_start();
if (card_locked_itf != itf) {
#ifndef ENABLE_EMULATION
uint32_t m = 0;
while (queue_is_empty(&usb_to_card_q) == false) {
@ -286,6 +125,8 @@ void card_start(void (*func)(void)) {
#else
(void)func;
#endif
card_locked_itf = itf;
}
}
void card_exit() {
@ -293,35 +134,27 @@ void card_exit() {
uint32_t flag = EV_EXIT;
queue_try_add(&usb_to_card_q, &flag);
led_set_blink(BLINK_SUSPENDED);
multicore_reset_core1();
#ifdef ESP_PLATFORM
hcore1 = NULL;
#endif
card_locked_itf = ITF_TOTAL;
#endif
}
extern void hid_task();
extern void ccid_task();
void usb_task() {
#ifndef ENABLE_EMULATION
bool mounted = false;
#else
bool mounted = true;
#endif
for (uint8_t itf = 0; itf < ITF_TOTAL; itf++) {
#ifndef ENABLE_EMULATION
#ifdef USB_ITF_HID
if (itf == ITF_HID) {
mounted = driver_mounted_hid();
}
hid_task();
#endif
#ifdef USB_ITF_CCID
if (itf == ITF_CCID || itf == ITF_WCID) {
mounted = driver_mounted_ccid(itf);
}
ccid_task();
#endif
#endif
if (mounted == true) {
if (usb_event_handle(itf) != 0) {
}
usb_write_flush(itf);
int card_status(uint8_t itf) {
#ifndef ENABLE_EMULATION
if (card_locked_itf == itf) {
uint32_t m = 0x0;
@ -331,64 +164,32 @@ void usb_task() {
if (has_m) {
if (m == EV_EXEC_FINISHED) {
timeout_stop();
#ifdef USB_ITF_HID
if (itf == ITF_HID) {
driver_exec_finished_hid(finished_data_size);
}
#endif
#ifdef USB_ITF_CCID
if (itf == ITF_CCID || itf == ITF_WCID) {
driver_exec_finished_ccid(itf, finished_data_size);
}
#endif
led_set_blink(BLINK_MOUNTED);
card_locked_itf = ITF_TOTAL;
return CCID_OK;
}
else if (m == EV_PRESS_BUTTON) {
uint32_t flag = wait_button() ? EV_BUTTON_TIMEOUT : EV_BUTTON_PRESSED;
queue_try_add(&usb_to_card_q, &flag);
}
return CCID_ERR_FILE_NOT_FOUND;
}
else {
if (timeout > 0) {
if (timeout + timeout_counter[itf] < board_millis()) {
#ifdef USB_ITF_HID
if (itf == ITF_HID) {
driver_exec_timeout_hid();
}
#endif
#ifdef USB_ITF_CCID
if (itf == ITF_CCID || itf == ITF_WCID) {
driver_exec_timeout_ccid(itf);
}
#endif
timeout = board_millis();
return CCID_ERR_BLOCKED;
}
}
}
}
#endif
return CCID_ERR_FILE_NOT_FOUND;
}
}
#ifndef ENABLE_EMULATION
#ifdef USB_ITF_HID
hid_task();
#endif
#endif
}
uint8_t *usb_prepare_response(uint8_t itf) {
#ifndef ENABLE_EMULATION
#ifdef USB_ITF_HID
if (itf == ITF_HID) {
return driver_prepare_response_hid();
}
#endif
#ifdef USB_ITF_CCID
if (itf == ITF_CCID || itf == ITF_WCID) {
return driver_prepare_response_ccid(itf);
}
#endif
return NULL;
#else

View file

@ -45,17 +45,31 @@
#define EV_BUTTON_TIMEOUT 16
#define EV_BUTTON_PRESSED 32
enum {
#ifdef USB_ITF_HID
ITF_HID_CTAP = 0,
ITF_HID_KB,
#endif
ITF_HID_TOTAL
};
enum {
#ifdef USB_ITF_CCID
ITF_SC_CCID = 0,
ITF_SC_WCID,
#endif
ITF_SC_TOTAL
};
enum {
#ifdef USB_ITF_HID
ITF_HID = 0,
ITF_KEYBOARD,
ITF_HID = ITF_HID_CTAP,
ITF_KEYBOARD = ITF_HID_KB,
#endif
#ifdef USB_ITF_CCID
ITF_CCID,
ITF_WCID,
ITF_CCID = ITF_SC_CCID + ITF_HID_TOTAL,
ITF_WCID = ITF_SC_WCID + ITF_HID_TOTAL,
#endif
ITF_TOTAL
ITF_TOTAL = ITF_HID_TOTAL + ITF_SC_TOTAL
};
enum {
@ -70,60 +84,42 @@ extern queue_t card_to_usb_q;
#endif
extern uint8_t card_locked_itf;
#ifdef USB_ITF_HID
extern int driver_process_usb_packet_hid(uint16_t rx_read);
extern void driver_exec_finished_hid(uint16_t size_next);
extern void driver_exec_finished_cont_hid(uint8_t itf, uint16_t size_next, uint16_t offset);
extern void driver_exec_timeout_hid();
extern bool driver_mounted_hid();
extern uint8_t *driver_prepare_response_hid();
extern int driver_write_hid(uint8_t, const uint8_t *, uint16_t);
extern uint16_t driver_read_hid(uint8_t *, uint16_t);
extern int driver_process_usb_nopacket_hid();
#endif
#ifdef USB_ITF_CCID
extern int driver_process_usb_packet_ccid(uint8_t itf, uint16_t rx_read);
extern void driver_exec_finished_ccid(uint8_t itf, uint16_t size_next);
extern void driver_exec_finished_cont_ccid(uint8_t itf, uint16_t size_next, uint16_t offset);
extern void driver_exec_timeout_ccid(uint8_t itf);
extern bool driver_mounted_ccid(uint8_t itf);
extern uint8_t *driver_prepare_response_ccid(uint8_t itf);
extern int driver_write_ccid(uint8_t, const uint8_t *, uint16_t);
extern uint16_t driver_read_ccid(uint8_t, uint8_t *, uint16_t);
extern int driver_process_usb_nopacket_ccid();
#endif
#ifdef ENABLE_EMULATION
extern int driver_process_usb_packet_emul(uint8_t, uint16_t rx_read);
extern void driver_exec_finished_emul(uint8_t, uint16_t size_next);
extern void driver_exec_finished_cont_emul(uint8_t, uint16_t size_next, uint16_t offset);
extern void driver_exec_timeout_emul(uint8_t);
extern bool driver_mounted_emul(uint8_t);
extern uint8_t *driver_prepare_response_emul(uint8_t);
extern uint16_t driver_write_emul(uint8_t, const uint8_t *, uint16_t);
extern uint16_t driver_read_emul(uint8_t, uint8_t *, uint16_t);
extern int driver_process_usb_nopacket_emul(uint8_t);
extern uint16_t emul_read(uint8_t);
#else
extern uint16_t usb_rx(uint8_t itf, const uint8_t *buffer, uint16_t len);
#endif
extern void card_start(void (*func)(void));
extern void card_start(uint8_t, void (*func)(void));
extern void card_exit();
extern int card_status(uint8_t itf);
extern void usb_init();
extern uint8_t *usb_prepare_response(uint8_t itf);
extern uint8_t *usb_get_rx(uint8_t itf);
extern uint8_t *usb_get_tx(uint8_t itf);
extern uint32_t usb_write_offset(uint8_t itf, uint16_t len, uint16_t offset);
extern void usb_clear_rx(uint8_t itf);
extern uint16_t usb_more_rx(uint8_t itf, uint16_t len);
extern uint16_t usb_get_r_offset(uint8_t itf);
extern uint16_t finished_data_size;
extern void usb_set_timeout_counter(uint8_t itf, uint32_t v);
extern void card_init_core1();
extern uint32_t usb_write_flush(uint8_t itf);
extern uint16_t usb_read_available(uint8_t itf);
extern uint16_t usb_write_available(uint8_t itf);
extern void usb_send_event(uint32_t flag);
extern void timeout_stop();
extern void timeout_start();
extern bool is_busy();
#ifdef USB_ITF_HID
extern void driver_exec_finished_hid(uint16_t size_next);
extern void driver_exec_finished_cont_hid(uint8_t itf, uint16_t size_next, uint16_t offset);
#endif
#ifdef USB_ITF_CCID
extern void driver_exec_finished_ccid(uint8_t itf, uint16_t size_next);
extern void driver_exec_finished_cont_ccid(uint8_t itf, uint16_t size_next, uint16_t offset);
#endif
#define USB_BUFFER_SIZE 2048 // Size of USB buffer
typedef struct {
uint8_t buffer[USB_BUFFER_SIZE];
uint16_t r_ptr, w_ptr;
} __attribute__((__packed__)) usb_buffer_t;
typedef enum {
WRITE_UNKNOWN = 0,
WRITE_PENDING,
WRITE_FAILED,
WRITE_SUCCESS,
} write_status_t;
#endif