feat(core/bootloader): dynamically decide to listen either USB or BLE

[no changelog]
tychovrahe/bluetooth/unification2
tychovrahe 1 year ago
parent 4ce0df6fc4
commit 9305ef7b25

@ -82,7 +82,8 @@ typedef enum {
CONTINUE = 0, CONTINUE = 0,
RETURN = 1, RETURN = 1,
SHUTDOWN = 2, SHUTDOWN = 2,
} usb_result_t; NO_RESULT = -1,
} comm_result_t;
static void usb_init_all(secbool usb21_landing) { static void usb_init_all(secbool usb21_landing) {
usb_dev_info_t dev_info = { usb_dev_info_t dev_info = {
@ -124,15 +125,6 @@ static void usb_init_all(secbool usb21_landing) {
usb_start(); usb_start();
} }
void start_comm(secbool usb21_landing) {
// if both are NULL, we don't have a firmware installed
// let's show a webusb landing page in this case
usb_init_all(usb21_landing);
#ifdef USE_BLE
start_advertising();
#endif
}
void stop_comm(void) { void stop_comm(void) {
hal_delay(100); hal_delay(100);
usb_stop(); usb_stop();
@ -142,64 +134,138 @@ void stop_comm(void) {
#endif #endif
} }
static usb_result_t bootloader_comm_loop(const vendor_header *const vhdr, static comm_result_t process_common_messages(uint8_t iface, uint8_t *buf,
const vendor_header *const vhdr,
const image_header *const hdr) {
uint16_t msg_id;
uint32_t msg_size;
uint32_t response;
int32_t upload_response;
if (sectrue != msg_parse_header(buf, &msg_id, &msg_size)) {
// invalid header -> discard
return NO_RESULT;
}
switch (msg_id) {
case 0: // Initialize
process_msg_Initialize(iface, msg_size, buf, vhdr, hdr);
break;
case 1: // Ping
process_msg_Ping(iface, msg_size, buf);
break;
case 5: // WipeDevice
response = ui_screen_wipe_confirm();
if (INPUT_CANCEL == response) {
send_user_abort(iface, "Wipe cancelled");
stop_comm();
return RETURN;
}
ui_screen_wipe();
upload_response = process_msg_WipeDevice(iface, msg_size, buf);
if (upload_response < 0) { // error
screen_wipe_fail();
stop_comm();
return SHUTDOWN;
} else { // success
screen_wipe_success();
stop_comm();
return SHUTDOWN;
}
break;
case 6: // FirmwareErase
process_msg_FirmwareErase(iface, msg_size, buf);
break;
case 7: // FirmwareUpload
upload_response = process_msg_FirmwareUpload(iface, msg_size, buf);
if (upload_response < 0 &&
upload_response !=
UPLOAD_ERR_USER_ABORT) { // error, but not user abort
ui_screen_fail();
stop_comm();
return SHUTDOWN;
} else if (upload_response == UPLOAD_ERR_USER_ABORT) {
stop_comm();
return RETURN;
} else if (upload_response == 0) { // last chunk received
ui_screen_install_progress_upload(1000);
ui_screen_done(4, sectrue);
ui_screen_done(3, secfalse);
hal_delay(1000);
ui_screen_done(2, secfalse);
hal_delay(1000);
ui_screen_done(1, secfalse);
hal_delay(1000);
stop_comm();
ui_screen_boot_empty(true);
return CONTINUE;
}
break;
case 55: // GetFeatures
process_msg_GetFeatures(iface, msg_size, buf, vhdr, hdr);
break;
default:
process_msg_unknown(iface, msg_size, buf);
break;
}
return NO_RESULT;
}
static comm_result_t bootloader_usb_loop(const vendor_header *const vhdr,
const image_header *const hdr) { const image_header *const hdr) {
start_comm((vhdr == NULL && hdr == NULL) ? sectrue : secfalse); uint8_t buf[USB_PACKET_SIZE];
uint8_t buf_usb[USB_PACKET_SIZE]; for (;;) {
#ifdef USE_BLE #ifdef TREZOR_EMULATOR
uint8_t ble_buf[BLE_PACKET_SIZE]; emulator_poll_events();
#endif #endif
uint8_t *buf = NULL; int r = usb_webusb_read_blocking(USB_IFACE_NUM, buf, USB_PACKET_SIZE,
USB_TIMEOUT);
if (r != USB_PACKET_SIZE) {
continue;
}
comm_result_t res = process_common_messages(USB_IFACE_NUM, buf, vhdr, hdr);
if (res != NO_RESULT) {
return res;
}
}
}
#ifdef USE_BLE
static comm_result_t bootloader_ble_loop(const vendor_header *const vhdr,
const image_header *const hdr) {
start_advertising();
uint8_t buf[BLE_PACKET_SIZE];
uint8_t active_iface = 0; uint8_t active_iface = 0;
int r = 0; int r = 0;
for (;;) { for (;;) {
for (;;) { for (;;) {
#ifdef TREZOR_EMULATOR r = ble_ext_comm_receive(buf, sizeof(buf));
emulator_poll_events();
#endif
r = usb_webusb_read_blocking(USB_IFACE_NUM, buf_usb, USB_PACKET_SIZE, 20);
if (r == USB_PACKET_SIZE) {
active_iface = USB_IFACE_NUM;
buf = buf_usb;
break;
}
#ifdef USE_BLE
r = ble_ext_comm_receive(ble_buf, sizeof(ble_buf));
if (r == BLE_PACKET_SIZE) { if (r == BLE_PACKET_SIZE) {
active_iface = BLE_EXT_IFACE_NUM; active_iface = BLE_EXT_IFACE_NUM;
buf = ble_buf;
break; break;
} }
r = ble_int_comm_receive(ble_buf, sizeof(ble_buf)); r = ble_int_comm_receive(buf, sizeof(buf));
if (r != 0) { if (r != 0) {
active_iface = BLE_INT_IFACE_NUM; active_iface = BLE_INT_IFACE_NUM;
buf = ble_buf;
break; break;
} }
ble_event_poll();
#endif
} }
#ifdef USE_BLE
if (active_iface == BLE_INT_IFACE_NUM) { if (active_iface == BLE_INT_IFACE_NUM) {
for (;;) { for (;;) {
bool next = false; bool next = false;
if (r == 0) { if (r == 0) {
if (active_iface == BLE_INT_IFACE_NUM) { r = ble_int_comm_receive(buf, sizeof(buf));
r = ble_int_comm_receive(ble_buf, sizeof(ble_buf));
if (r == 0) { if (r == 0) {
continue; continue;
}
} else {
// unknown interface
return CONTINUE;
} }
} }
@ -214,7 +280,7 @@ static usb_result_t bootloader_comm_loop(const vendor_header *const vhdr,
} }
switch (msg_id) { switch (msg_id) {
case MessageType_MessageType_PairingRequest: // pairing request case MessageType_MessageType_PairingRequest: // pairing request
response = process_msg_Pairing(active_iface, msg_size, ble_buf); response = process_msg_Pairing(active_iface, msg_size, buf);
if (response != INPUT_CONFIRM) { if (response != INPUT_CONFIRM) {
stop_comm(); stop_comm();
return RETURN; return RETURN;
@ -224,7 +290,7 @@ static usb_result_t bootloader_comm_loop(const vendor_header *const vhdr,
break; break;
case MessageType_MessageType_RepairRequest: // repairing request case MessageType_MessageType_RepairRequest: // repairing request
response = process_msg_Repair(active_iface, msg_size, ble_buf); response = process_msg_Repair(active_iface, msg_size, buf);
if (response != INPUT_CONFIRM) { if (response != INPUT_CONFIRM) {
stop_comm(); stop_comm();
return RETURN; return RETURN;
@ -233,7 +299,7 @@ static usb_result_t bootloader_comm_loop(const vendor_header *const vhdr,
// todo - screen connect or timeout? // todo - screen connect or timeout?
break; break;
default: default:
process_msg_unknown(active_iface, msg_size, ble_buf); process_msg_unknown(active_iface, msg_size, buf);
break; break;
} }
if (next) { if (next) {
@ -241,113 +307,58 @@ static usb_result_t bootloader_comm_loop(const vendor_header *const vhdr,
} }
} }
} }
#endif
if (active_iface == USB_IFACE_NUM || active_iface == BLE_EXT_IFACE_NUM) { if (active_iface == BLE_EXT_IFACE_NUM) {
for (;;) { for (;;) {
#ifdef TREZOR_EMULATOR
emulator_poll_events();
#endif
if (r == 0) { if (r == 0) {
if (active_iface == USB_IFACE_NUM) { r = ble_ext_comm_receive(buf, sizeof(buf));
r = usb_webusb_read_blocking(active_iface, buf_usb, USB_PACKET_SIZE,
USB_TIMEOUT);
if (r != USB_PACKET_SIZE) {
continue;
}
}
#ifdef USE_BLE
else if (active_iface == BLE_EXT_IFACE_NUM) {
r = ble_ext_comm_receive(ble_buf, sizeof(ble_buf));
if (r != BLE_PACKET_SIZE) { if (r != BLE_PACKET_SIZE) {
continue; continue;
}
}
#endif
else {
// unknown interface
return CONTINUE;
} }
} }
r = 0; r = 0;
uint16_t msg_id; comm_result_t res =
uint32_t msg_size; process_common_messages(active_iface, buf, vhdr, hdr);
uint32_t response;
int32_t upload_response; if (res != NO_RESULT) {
if (sectrue != msg_parse_header(buf, &msg_id, &msg_size)) { return res;
// invalid header -> discard
continue;
}
switch (msg_id) {
case 0: // Initialize
process_msg_Initialize(active_iface, msg_size, buf, vhdr, hdr);
break;
case 1: // Ping
process_msg_Ping(active_iface, msg_size, buf);
break;
case 5: // WipeDevice
response = ui_screen_wipe_confirm();
if (INPUT_CANCEL == response) {
send_user_abort(active_iface, "Wipe cancelled");
stop_comm();
return RETURN;
}
ui_screen_wipe();
upload_response =
process_msg_WipeDevice(active_iface, msg_size, buf);
if (upload_response < 0) { // error
screen_wipe_fail();
stop_comm();
return SHUTDOWN;
} else { // success
screen_wipe_success();
stop_comm();
return SHUTDOWN;
}
break;
case 6: // FirmwareErase
process_msg_FirmwareErase(active_iface, msg_size, buf);
break;
case 7: // FirmwareUpload
upload_response =
process_msg_FirmwareUpload(active_iface, msg_size, buf);
if (upload_response < 0 &&
upload_response !=
UPLOAD_ERR_USER_ABORT) { // error, but not user abort
ui_screen_fail();
stop_comm();
return SHUTDOWN;
} else if (upload_response == UPLOAD_ERR_USER_ABORT) {
stop_comm();
return RETURN;
} else if (upload_response == 0) { // last chunk received
ui_screen_install_progress_upload(1000);
ui_screen_done(4, sectrue);
ui_screen_done(3, secfalse);
hal_delay(1000);
ui_screen_done(2, secfalse);
hal_delay(1000);
ui_screen_done(1, secfalse);
hal_delay(1000);
stop_comm();
ui_screen_boot_empty(true);
return CONTINUE;
}
break;
case 55: // GetFeatures
process_msg_GetFeatures(active_iface, msg_size, buf, vhdr, hdr);
break;
default:
process_msg_unknown(active_iface, msg_size, buf);
break;
} }
} }
} }
} }
} }
#endif
static comm_result_t bootloader_comm_select(const vendor_header *const vhdr,
const image_header *const hdr) {
// if both are NULL, we don't have a firmware installed
// let's show a webusb landing page in this case
usb_init_all((vhdr == NULL && hdr == NULL) ? sectrue : secfalse);
#ifdef USE_BLE
bool usb = false;
for (int i = 0; i < 2000; i++) {
hal_delay(1);
if (usb_configured_now() == sectrue) {
usb = true;
break;
}
}
if (usb) {
return bootloader_usb_loop(vhdr, hdr);
} else {
usb_stop();
usb_deinit();
return bootloader_ble_loop(vhdr, hdr);
}
#else
return bootloader_usb_loop(vhdr, hdr);
#endif
}
secbool check_vendor_header_keys(const vendor_header *const vhdr) { secbool check_vendor_header_keys(const vendor_header *const vhdr) {
return check_vendor_header_sig(vhdr, BOOTLOADER_KEY_M, BOOTLOADER_KEY_N, return check_vendor_header_sig(vhdr, BOOTLOADER_KEY_M, BOOTLOADER_KEY_N,
@ -539,7 +550,7 @@ int bootloader_main(void) {
NULL); NULL);
// and start the usb loop // and start the usb loop
if (bootloader_comm_loop(NULL, NULL) != CONTINUE) { if (bootloader_comm_select(NULL, NULL) != CONTINUE) {
return 1; return 1;
} }
} }
@ -598,7 +609,7 @@ int bootloader_main(void) {
break; break;
case SCREEN_WAIT_FOR_HOST: case SCREEN_WAIT_FOR_HOST:
screen_connect(); screen_connect();
switch (bootloader_comm_loop(&vhdr, hdr)) { switch (bootloader_comm_select(&vhdr, hdr)) {
case CONTINUE: case CONTINUE:
continue_to_firmware = true; continue_to_firmware = true;
break; break;

@ -187,6 +187,15 @@ secbool usb_configured(void) {
return secfalse; return secfalse;
} }
secbool usb_configured_now(void) {
const USBD_HandleTypeDef *pdev = &usb_dev_handle;
if (pdev->dev_state == USBD_STATE_SUSPENDED &&
pdev->dev_old_state == USBD_STATE_CONFIGURED) {
return sectrue;
}
return secfalse;
}
/* /*
* Utility functions for USB interfaces * Utility functions for USB interfaces
*/ */

@ -144,5 +144,6 @@ void usb_deinit(void);
void usb_start(void); void usb_start(void);
void usb_stop(void); void usb_stop(void);
secbool usb_configured(void); secbool usb_configured(void);
secbool usb_configured_now(void);
#endif #endif

Loading…
Cancel
Save