1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-01-27 15:51:02 +00:00

feat(core): add support for setting BLE name from Trezor firmware

[no changelog]
This commit is contained in:
tychovrahe 2025-01-15 14:34:04 +01:00 committed by TychoVrahe
parent 205a3bee79
commit a5809c872e
10 changed files with 154 additions and 48 deletions

View File

@ -29,6 +29,8 @@
#define BLE_RX_PACKET_SIZE 244
#define BLE_TX_PACKET_SIZE 64
#define BLE_ADV_NAME_LEN 20
typedef enum {
BLE_SWITCH_OFF = 0, // Turn off BLE advertising, disconnect
BLE_SWITCH_ON = 1, // Turn on BLE advertising
@ -37,6 +39,18 @@ typedef enum {
BLE_ERASE_BONDS = 4, // Erase all bonding information
BLE_ALLOW_PAIRING = 5, // Accept pairing request
BLE_REJECT_PAIRING = 6, // Reject pairing request
} ble_command_type_t;
typedef union {
uint8_t raw[32];
uint8_t name[BLE_ADV_NAME_LEN];
} ble_command_data_t;
typedef struct {
ble_command_type_t cmd_type;
uint8_t data_len;
ble_command_data_t data;
} ble_command_t;
typedef enum {
@ -91,7 +105,7 @@ void ble_stop(void);
// Sends a specific command to the BLE module for execution.
//
// Returns `true` if the command was successfully issued.
bool ble_issue_command(ble_command_t command);
bool ble_issue_command(ble_command_t *command);
// Reads an event from the BLE module
//

View File

@ -26,6 +26,7 @@
#include <sys/irq.h>
#include <sys/systimer.h>
#include <util/tsqueue.h>
#include <util/unit_properties.h>
#include "ble_comm_defs.h"
@ -65,6 +66,7 @@ typedef struct {
tsqueue_entry_t ts_queue_entries[TX_QUEUE_LEN];
tsqueue_t tx_queue;
char adv_name[BLE_ADV_NAME_LEN];
systimer_t *timer;
uint16_t ping_cntr;
} ble_driver_t;
@ -80,11 +82,19 @@ static bool ble_send_state_request(ble_driver_t *drv) {
static bool ble_send_advertising_on(ble_driver_t *drv, bool whitelist) {
(void)drv;
uint8_t data[2];
data[0] = INTERNAL_CMD_ADVERTISING_ON;
data[1] = whitelist ? 1 : 0;
return nrf_send_msg(NRF_SERVICE_BLE_MANAGER, data, sizeof(data), NULL,
NULL) >= 0;
unit_properties_t props;
unit_properties_get(&props);
cmd_advertising_on_t data = {
.cmd_id = INTERNAL_CMD_ADVERTISING_ON,
.whitelist = whitelist ? 1 : 0,
.color = props.color,
};
memcpy(data.name, drv->adv_name, BLE_ADV_NAME_LEN);
return nrf_send_msg(NRF_SERVICE_BLE_MANAGER, (uint8_t *)&data, sizeof(data),
NULL, NULL) >= 0;
}
static bool ble_send_advertising_off(ble_driver_t *drv) {
@ -146,14 +156,6 @@ static void ble_process_rx_msg_status(const uint8_t *data, uint32_t len) {
event_status_msg_t msg;
memcpy(&msg, data, sizeof(event_status_msg_t));
if (!drv->status_valid) {
if (msg.peer_count > 0) {
drv->mode_requested = BLE_MODE_CONNECTABLE;
} else {
drv->mode_requested = BLE_MODE_OFF;
}
}
if (drv->connected != msg.connected) {
if (msg.connected) {
// new connection
@ -507,7 +509,7 @@ uint32_t ble_read(uint8_t *data, uint16_t max_len) {
return read_len;
}
bool ble_issue_command(ble_command_t command) {
bool ble_issue_command(ble_command_t *command) {
ble_driver_t *drv = &g_ble_driver;
if (!drv->initialized) {
@ -518,14 +520,16 @@ bool ble_issue_command(ble_command_t command) {
bool result = false;
switch (command) {
switch (command->cmd_type) {
case BLE_SWITCH_OFF:
drv->mode_requested = BLE_MODE_OFF;
break;
case BLE_SWITCH_ON:
memcpy(drv->adv_name, command->data.name, sizeof(drv->adv_name));
drv->mode_requested = BLE_MODE_CONNECTABLE;
break;
case BLE_PAIRING_MODE:
memcpy(drv->adv_name, command->data.name, sizeof(drv->adv_name));
drv->mode_requested = BLE_MODE_PAIRING;
break;
case BLE_DISCONNECT:

View File

@ -17,11 +17,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TREZORHAL_BLE_COMM_DEFS_H_
#define TREZORHAL_BLE_COMM_DEFS_H_
#pragma once
#include <trezor_types.h>
#include <io/ble.h>
typedef struct {
uint8_t msg_id;
uint8_t connected;
@ -56,4 +57,10 @@ typedef enum {
INTERNAL_CMD_ALLOW_PAIRING = 0x06,
INTERNAL_CMD_REJECT_PAIRING = 0x07,
} internal_cmd_t;
#endif
typedef struct {
uint8_t cmd_id;
uint8_t whitelist;
uint8_t color;
uint8_t name[BLE_ADV_NAME_LEN];
} cmd_advertising_on_t;

View File

@ -15,20 +15,43 @@ pub fn connected() -> bool {
}
}
pub fn pairing_mode() {
pub fn pairing_mode(name: &str) {
unsafe {
ffi::ble_issue_command(ffi::ble_command_t_BLE_PAIRING_MODE);
let mut cmd = ffi::ble_command_t {
cmd_type: ffi::ble_command_type_t_BLE_PAIRING_MODE,
data_len: 0,
data: ffi::ble_command_data_t { raw: [0; 32] },
};
let bytes = name.as_bytes();
// Determine how many bytes we can copy (min of buffer size and string length).
let len = bytes.len().min(cmd.data.name.len());
cmd.data.name[..len].copy_from_slice(&bytes[..len]);
ffi::ble_issue_command(&mut cmd as _);
}
}
pub fn allow_pairing() {
unsafe {
ffi::ble_issue_command(ffi::ble_command_t_BLE_ALLOW_PAIRING);
let mut cmd = ffi::ble_command_t {
cmd_type: ffi::ble_command_type_t_BLE_ALLOW_PAIRING,
data_len: 0,
data: ffi::ble_command_data_t { raw: [0; 32] },
};
ffi::ble_issue_command(&mut cmd as _);
}
}
pub fn reject_pairing() {
unsafe {
ffi::ble_issue_command(ffi::ble_command_t_BLE_REJECT_PAIRING);
let mut cmd = ffi::ble_command_t {
cmd_type: ffi::ble_command_type_t_BLE_REJECT_PAIRING,
data_len: 0,
data: ffi::ble_command_data_t { raw: [0; 32] },
};
ffi::ble_issue_command(&mut cmd as _);
}
}

View File

@ -687,8 +687,8 @@ __attribute((no_stack_protector)) void syscall_handler(uint32_t *args,
} break;
case SYSCALL_BLE_ISSUE_COMMAND: {
ble_command_t command = args[0];
ble_issue_command(command);
ble_command_t *command = (ble_command_t *)args[0];
args[0] = ble_issue_command__verified(command);
} break;
case SYSCALL_BLE_GET_STATE: {

View File

@ -655,7 +655,7 @@ secbool firmware_calc_hash(const uint8_t *challenge, size_t challenge_len,
void ble_start(void) { syscall_invoke0(SYSCALL_BLE_START); }
bool ble_issue_command(ble_command_t command) {
bool ble_issue_command(ble_command_t *command) {
return (bool)syscall_invoke1((uint32_t)command, SYSCALL_BLE_ISSUE_COMMAND);
}

View File

@ -718,6 +718,18 @@ access_violation:
// ---------------------------------------------------------------------
#ifdef USE_BLE
bool ble_issue_command__verified(ble_command_t *command) {
if (!probe_read_access(command, sizeof(*command))) {
goto access_violation;
}
return ble_issue_command(command);
access_violation:
apptask_access_violation();
return false;
}
void ble_get_state__verified(ble_state_t *state) {
if (!probe_write_access(state, sizeof(*state))) {
goto access_violation;

View File

@ -191,6 +191,8 @@ secbool firmware_get_vendor__verified(char *buff, size_t buff_size);
#include <io/ble.h>
bool ble_issue_command__verified(ble_command_t *state);
void ble_get_state__verified(ble_state_t *state);
bool ble_get_event__verified(ble_event_t *event);

View File

@ -124,18 +124,18 @@ STATIC mp_obj_t mod_trezorio_BLE_read(size_t n_args, const mp_obj_t *args) {
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorio_BLE_read_obj, 1, 2,
mod_trezorio_BLE_read);
/// def erase_bonds() -> None:
/// def erase_bonds() -> bool:
/// """
/// Erases all BLE bonds
/// """
STATIC mp_obj_t mod_trezorio_BLE_erase_bonds(void) {
ble_issue_command(BLE_ERASE_BONDS);
return mp_const_none;
ble_command_t cmd = {.cmd_type = BLE_ERASE_BONDS, .data_len = 0};
return mp_obj_new_bool(ble_issue_command(&cmd));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorio_BLE_erase_bonds_obj,
mod_trezorio_BLE_erase_bonds);
/// def start_comm() -> None:
/// def start_comm() -> bool:
/// """
/// Start communication with BLE chip
/// """
@ -146,41 +146,76 @@ STATIC mp_obj_t mod_trezorio_BLE_start_comm(void) {
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorio_BLE_start_comm_obj,
mod_trezorio_BLE_start_comm);
/// def start_advertising(whitelist: bool) -> None:
/// def start_advertising(whitelist: bool, name: str | None) -> bool:
/// """
/// Start advertising
/// """
STATIC mp_obj_t mod_trezorio_BLE_start_advertising(mp_obj_t whitelist) {
bool whitelist_bool = mp_obj_is_true(whitelist);
STATIC mp_obj_t mod_trezorio_BLE_start_advertising(size_t n_args,
const mp_obj_t *args) {
bool whitelist_bool = mp_obj_is_true(args[0]);
ble_issue_command(whitelist_bool ? BLE_SWITCH_ON : BLE_PAIRING_MODE);
return mp_const_none;
mp_buffer_info_t name = {0};
char *name_buf = NULL;
int name_len = 0;
if (n_args == 1 || !mp_get_buffer(args[1], &name, MP_BUFFER_READ)) {
name_buf = MODEL_FULL_NAME;
name_len = strlen(MODEL_FULL_NAME);
} else {
name_buf = name.buf;
name_len = name.len;
}
ble_command_t cmd = {
.cmd_type = whitelist_bool ? BLE_SWITCH_ON : BLE_PAIRING_MODE,
.data_len = name.len};
// get a minimum of the two lengths
int len = name_len < BLE_ADV_NAME_LEN ? name_len : BLE_ADV_NAME_LEN;
memcpy(cmd.data.name, name_buf, len);
return mp_obj_new_bool(ble_issue_command(&cmd));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorio_BLE_start_advertising_obj,
mod_trezorio_BLE_start_advertising);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(
mod_trezorio_BLE_start_advertising_obj, 1, 2,
mod_trezorio_BLE_start_advertising);
/// def stop_advertising(whitelist: bool) -> None:
/// def stop_advertising(whitelist: bool) -> bool:
/// """
/// Stop advertising
/// """
STATIC mp_obj_t mod_trezorio_BLE_stop_advertising(void) {
ble_issue_command(BLE_SWITCH_OFF);
return mp_const_none;
ble_command_t cmd = {.cmd_type = BLE_SWITCH_OFF, .data_len = 0};
return mp_obj_new_bool(ble_issue_command(&cmd));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorio_BLE_stop_advertising_obj,
mod_trezorio_BLE_stop_advertising);
/// def disconnect() -> None:
/// def disconnect() -> bool:
/// """
/// Disconnect BLE
/// """
STATIC mp_obj_t mod_trezorio_BLE_disconnect(void) {
ble_issue_command(BLE_DISCONNECT);
return mp_const_none;
ble_command_t cmd = {.cmd_type = BLE_DISCONNECT, .data_len = 0};
return mp_obj_new_bool(ble_issue_command(&cmd));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorio_BLE_disconnect_obj,
mod_trezorio_BLE_disconnect);
/// def peer_count() -> int:
/// """
/// Get peer count (number of bonded devices)
/// """
STATIC mp_obj_t mod_trezorio_BLE_peer_count(void) {
ble_state_t state;
ble_get_state(&state);
return MP_OBJ_NEW_SMALL_INT(state.peer_count);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorio_BLE_peer_count_obj,
mod_trezorio_BLE_peer_count);
STATIC const mp_rom_map_elem_t mod_trezorio_BLE_globals_table[] = {
{MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ble)},
// {MP_ROM_QSTR(MP_QSTR_update_init),
@ -199,6 +234,8 @@ STATIC const mp_rom_map_elem_t mod_trezorio_BLE_globals_table[] = {
MP_ROM_PTR(&mod_trezorio_BLE_stop_advertising_obj)},
{MP_ROM_QSTR(MP_QSTR_disconnect),
MP_ROM_PTR(&mod_trezorio_BLE_disconnect_obj)},
{MP_ROM_QSTR(MP_QSTR_peer_count),
MP_ROM_PTR(&mod_trezorio_BLE_peer_count_obj)},
};
STATIC MP_DEFINE_CONST_DICT(mod_trezorio_BLE_globals,
mod_trezorio_BLE_globals_table);

View File

@ -16,35 +16,42 @@ def read(buf: bytes, offset: int = 0) -> int
# upymod/modtrezorio/modtrezorio-ble.h
def erase_bonds() -> None:
def erase_bonds() -> bool:
"""
Erases all BLE bonds
"""
# upymod/modtrezorio/modtrezorio-ble.h
def start_comm() -> None:
def start_comm() -> bool:
"""
Start communication with BLE chip
"""
# upymod/modtrezorio/modtrezorio-ble.h
def start_advertising(whitelist: bool) -> None:
def start_advertising(whitelist: bool, name: str | None) -> bool:
"""
Start advertising
"""
# upymod/modtrezorio/modtrezorio-ble.h
def stop_advertising(whitelist: bool) -> None:
def stop_advertising(whitelist: bool) -> bool:
"""
Stop advertising
"""
# upymod/modtrezorio/modtrezorio-ble.h
def disconnect() -> None:
def disconnect() -> bool:
"""
Disconnect BLE
"""
# upymod/modtrezorio/modtrezorio-ble.h
def peer_count() -> int:
"""
Get peer count (number of bonded devices)
"""