mirror of
https://github.com/espressif/esp-nimble.git
synced 2026-08-21 09:20:02 +00:00
tools/hci_throughput: testing over encrypted link
Added option enable_encryption to run throughput tests over encrypted link.
This commit is contained in:
@@ -43,6 +43,7 @@ adv:
|
||||
peer_address: 00:00:00:00:00:00
|
||||
advertising_channel_map: 7
|
||||
advertising_filter_policy: 0
|
||||
enable_encryption: true
|
||||
conn:
|
||||
le_scan_interval: 2400
|
||||
le_scan_window: 2400
|
||||
|
||||
@@ -35,6 +35,7 @@ HCI_EVENT_PACKET = 0x04
|
||||
L2CAP_HDR_BYTES = 4
|
||||
|
||||
HCI_EV_CODE_DISCONN_CMP = 0x05
|
||||
HCI_EV_CODE_ENCRYPTION_CHANGE = 0x08
|
||||
HCI_EV_CODE_CMD_CMP = 0x0e
|
||||
HCI_EV_CODE_CMD_STATUS = 0x0f
|
||||
HCI_EV_CODE_LE_META_EVENT = 0x3e
|
||||
@@ -42,6 +43,7 @@ HCI_SUBEV_CODE_LE_ENHANCED_CONN_CMP = 0x0a
|
||||
HCI_SUBEV_CODE_LE_DATA_LEN_CHANGE = 0x07
|
||||
HCI_SUBEV_CODE_LE_PHY_UPDATE_CMP = 0x0c
|
||||
HCI_SUBEV_CODE_LE_CHAN_SEL_ALG = 0x14
|
||||
HCI_SUBEV_CODE_LE_LONG_TERM_KEY_REQUEST = 0x05
|
||||
HCI_EV_NUM_COMP_PKTS = 0x13
|
||||
|
||||
CONN_FAILED_TO_BE_ESTABLISHED = 0x3e
|
||||
@@ -66,6 +68,8 @@ OCF_LE_SET_ADVERTISE_ENABLE = 0x000a
|
||||
OCF_LE_SET_SCAN_PARAMETERS = 0x000b
|
||||
OCF_LE_SET_SCAN_ENABLE = 0x000c
|
||||
OCF_LE_CREATE_CONN = 0x000d
|
||||
OCF_LE_ENABLE_ENCRYPTION = 0x0019
|
||||
OCF_LE_LONG_TERM_KEY_REQUEST_REPLY = 0x001A
|
||||
OCF_LE_SET_DATA_LEN = 0x0022
|
||||
OCF_LE_READ_SUGGESTED_DFLT_DATA_LEN = 0x0023
|
||||
OCF_LE_READ_MAX_DATA_LEN = 0x002f
|
||||
@@ -106,6 +110,7 @@ num_of_completed_packets_cnt = 0
|
||||
num_of_completed_packets_time = 0
|
||||
read_local_commands = None
|
||||
le_read_local_supported_features = None
|
||||
ltk = None
|
||||
|
||||
############
|
||||
# FUNCTIONS
|
||||
@@ -303,6 +308,21 @@ class HCI_Ev_Cmd_Status:
|
||||
self.opcode = opcode
|
||||
|
||||
|
||||
@dataclass
|
||||
class HCI_Ev_LE_Encryption_Change():
|
||||
status: int
|
||||
connection_handle: int
|
||||
encryption_enabled: int
|
||||
|
||||
def __init__(self):
|
||||
self.set()
|
||||
|
||||
def set(self, status=0, connection_handle=0, encryption_enabled=0):
|
||||
self.status = status
|
||||
self.connection_handle = connection_handle
|
||||
self.encryption_enabled = encryption_enabled
|
||||
|
||||
|
||||
@dataclass
|
||||
class HCI_Ev_LE_Meta:
|
||||
subevent_code: int
|
||||
@@ -374,6 +394,23 @@ class HCI_Ev_LE_Data_Length_Change(HCI_Ev_LE_Meta):
|
||||
self.triggered = triggered
|
||||
|
||||
|
||||
@dataclass
|
||||
class HCI_Ev_LE_Long_Term_Key_Request(HCI_Ev_LE_Meta):
|
||||
conn_handle: int
|
||||
random_number: int
|
||||
encrypted_diversifier: int
|
||||
|
||||
def __init__(self):
|
||||
self.set()
|
||||
|
||||
def set(self, subevent_code=0, conn_handle=0, random_number=0,
|
||||
encrypted_diversifier=0):
|
||||
super().set(subevent_code)
|
||||
self.conn_handle = conn_handle
|
||||
self.random_number = random_number
|
||||
self.encrypted_diversifier = encrypted_diversifier
|
||||
|
||||
|
||||
@dataclass
|
||||
class HCI_Ev_LE_PHY_Update_Complete(HCI_Ev_LE_Meta):
|
||||
status: int
|
||||
|
||||
@@ -47,6 +47,7 @@ class HCI_Commands():
|
||||
self.async_sem_cmd = asyncio.Semaphore()
|
||||
self.async_ev_cmd_end = asyncio.Event()
|
||||
self.async_ev_connected = asyncio.Event()
|
||||
self.async_ev_encryption_change = asyncio.Event()
|
||||
self.async_ev_set_data_len = asyncio.Event()
|
||||
self.async_ev_update_phy = asyncio.Event()
|
||||
self.async_ev_num_cmp_pckts = asyncio.Event()
|
||||
@@ -219,6 +220,41 @@ class HCI_Commands():
|
||||
await self.async_ev_cmd_end.wait()
|
||||
self.async_ev_cmd_end.clear()
|
||||
|
||||
async def cmd_le_enable_encryption(self, conn_handle: int, random_number: int, ediv: int, ltk: int):
|
||||
async with self.async_sem_cmd:
|
||||
hci.ltk = ltk
|
||||
random_number_bytes = random_number.to_bytes(8, byteorder='little')
|
||||
ltk_bytes = ltk.to_bytes(16, byteorder='little')
|
||||
data_bytes = struct.pack("<H", conn_handle) + random_number_bytes + \
|
||||
struct.pack("<H", ediv) + ltk_bytes
|
||||
self.hci_send_cmd.set(
|
||||
hci.OGF_LE_CTL,
|
||||
hci.OCF_LE_ENABLE_ENCRYPTION,
|
||||
data_bytes)
|
||||
logging.debug("%s %s", self.cmd_le_enable_encryption.__name__,
|
||||
self.hci_send_cmd)
|
||||
await self.send(self.hci_send_cmd.ba_full_message)
|
||||
await self.async_ev_cmd_end.wait()
|
||||
self.async_ev_cmd_end.clear()
|
||||
|
||||
async def cmd_le_long_term_key_request_reply(self, conn_handle: int, ltk: int):
|
||||
async with self.async_sem_cmd:
|
||||
ltk_bytes = ltk.to_bytes(16, byteorder='little')
|
||||
data_bytes = struct.pack('<H', conn_handle) + ltk_bytes
|
||||
self.hci_send_cmd.set(
|
||||
hci.OGF_LE_CTL,
|
||||
hci.OCF_LE_LONG_TERM_KEY_REQUEST_REPLY,
|
||||
data_bytes)
|
||||
logging.debug(
|
||||
"%s %s",
|
||||
self.cmd_le_long_term_key_request_reply.__name__,
|
||||
self.hci_send_cmd)
|
||||
await self.send(self.hci_send_cmd.ba_full_message)
|
||||
# Is run from another command,
|
||||
# don't need to wait for cmd complete.
|
||||
# await self.async_ev_cmd_end.wait()
|
||||
# self.async_ev_cmd_end.clear()
|
||||
|
||||
async def cmd_le_set_data_len(self, conn_handle: int, tx_octets: int, tx_time: int):
|
||||
""" conn_handle: Range 0x0000 to 0x0EFF
|
||||
tx_octets: Range 0x001B to 0x00FB
|
||||
@@ -358,6 +394,11 @@ class HCI_Commands():
|
||||
ev_cmd_stat.set(*struct.unpack('<BBH', bytes(data[:4])))
|
||||
return ev_cmd_stat
|
||||
|
||||
def parse_ev_encryption_change(self, data: bytes):
|
||||
ev_encryption_change = hci.HCI_Ev_LE_Encryption_Change()
|
||||
ev_encryption_change.set(*struct.unpack('<BHB', bytes(data[:4])))
|
||||
return ev_encryption_change
|
||||
|
||||
def parse_ev_le_meta(self, data: bytes):
|
||||
ev_le_meta = hci.HCI_Ev_LE_Meta()
|
||||
ev_le_meta.set(data[0])
|
||||
@@ -377,6 +418,12 @@ class HCI_Commands():
|
||||
ev_le_data_len_change.set(*struct.unpack('<BHHHHH', bytes(data[:11])))
|
||||
return ev_le_data_len_change
|
||||
|
||||
def parse_subev_le_long_term_key_request(self, data: bytes):
|
||||
ev_le_long_term_key_request = hci.HCI_Ev_LE_Long_Term_Key_Request()
|
||||
ev_le_long_term_key_request.set(
|
||||
*struct.unpack('<BHQH', bytes(data[:13])))
|
||||
return ev_le_long_term_key_request
|
||||
|
||||
def parse_subev_le_phy_update_cmp(self, data: bytes):
|
||||
le_phy_update_cmp = hci.HCI_Ev_LE_PHY_Update_Complete()
|
||||
le_phy_update_cmp.set(*struct.unpack('<BBHBB', data))
|
||||
@@ -533,6 +580,15 @@ class HCI_Commands():
|
||||
self.hci_recv_ev_packet.current_event))
|
||||
return hci.HCI_SUBEV_CODE_LE_ENHANCED_CONN_CMP
|
||||
|
||||
elif subev_code == hci.HCI_SUBEV_CODE_LE_LONG_TERM_KEY_REQUEST:
|
||||
self.hci_recv_ev_packet.current_event = \
|
||||
self.parse_subev_le_long_term_key_request(
|
||||
self.hci_recv_ev_packet.recv_data)
|
||||
hci.events_list.append(
|
||||
(hci.HCI_SUBEV_CODE_LE_LONG_TERM_KEY_REQUEST,
|
||||
self.hci_recv_ev_packet.current_event))
|
||||
return hci.HCI_SUBEV_CODE_LE_LONG_TERM_KEY_REQUEST
|
||||
|
||||
elif subev_code == hci.HCI_SUBEV_CODE_LE_DATA_LEN_CHANGE:
|
||||
self.hci_recv_ev_packet.current_event = \
|
||||
self.parse_subev_le_data_len_change(
|
||||
@@ -584,6 +640,14 @@ class HCI_Commands():
|
||||
self.hci_recv_ev_packet.current_event))
|
||||
return hci.HCI_EV_CODE_CMD_STATUS
|
||||
|
||||
elif self.hci_recv_ev_packet.ev_code == hci.HCI_EV_CODE_ENCRYPTION_CHANGE:
|
||||
self.hci_recv_ev_packet.current_event = \
|
||||
self.parse_ev_encryption_change(
|
||||
self.hci_recv_ev_packet.recv_data)
|
||||
hci.events_list.append((hci.HCI_EV_CODE_ENCRYPTION_CHANGE,
|
||||
self.hci_recv_ev_packet.current_event))
|
||||
return hci.HCI_EV_CODE_ENCRYPTION_CHANGE
|
||||
|
||||
elif self.hci_recv_ev_packet.ev_code == hci.HCI_EV_CODE_LE_META_EVENT:
|
||||
self.hci_recv_ev_packet.current_event = \
|
||||
self.parse_ev_le_meta(self.hci_recv_ev_packet.recv_data)
|
||||
@@ -647,6 +711,19 @@ class HCI_Commands():
|
||||
logging.error("Status: %s for event: %s", status, curr_ev)
|
||||
self.async_ev_cmd_end.set()
|
||||
|
||||
elif event_code == hci.HCI_EV_CODE_ENCRYPTION_CHANGE:
|
||||
logging.debug(
|
||||
"Received code: %s - HCI_EV_CODE_ENCRYPTION_CHANGE",
|
||||
event_code)
|
||||
status = curr_ev.status
|
||||
encryption_enabled = curr_ev.encryption_enabled
|
||||
if (status == 0 and encryption_enabled != 0):
|
||||
self.async_ev_encryption_change.set()
|
||||
else:
|
||||
raise Exception(
|
||||
"Encryption failed. Status: %d, encryption enabled: %d",
|
||||
status, encryption_enabled)
|
||||
|
||||
elif event_code == hci.HCI_EV_CODE_LE_META_EVENT:
|
||||
logging.debug(
|
||||
"Received code: %s - HCI_EV_CODE_LE_META_EVENT", event_code)
|
||||
@@ -678,6 +755,13 @@ class HCI_Commands():
|
||||
"Received subev code: %s - HCI_SUBEV_CODE_LE_CHAN_SEL_ALG",
|
||||
subev_code)
|
||||
|
||||
elif subev_code == hci.HCI_SUBEV_CODE_LE_LONG_TERM_KEY_REQUEST:
|
||||
logging.debug(
|
||||
"Received subev code: %s - HCI_SUBEV_CODE_LE_LONG_TERM_KEY_REQUEST",
|
||||
subev_code)
|
||||
await self.cmd_le_long_term_key_request_reply(
|
||||
hci.conn_handle, hci.ltk)
|
||||
|
||||
elif subev_code < 0:
|
||||
logging.warning(f"Unknown received subevent: {buffer}\n")
|
||||
|
||||
|
||||
@@ -218,6 +218,10 @@ async def async_main_tx(bt_dev: hci_commands.HCI_Commands, ini: dict, cfg: dict)
|
||||
hci.le_read_local_supported_features.le_features)
|
||||
await hci_commands.wait_for_event(bt_dev.async_ev_update_phy, hci.WAIT_FOR_EVENT_TIMEOUT)
|
||||
|
||||
if cfg["enable_encryption"]:
|
||||
await bt_dev.cmd_le_enable_encryption(hci.conn_handle, random_number=0, ediv=0, ltk=hci.ltk)
|
||||
await hci_commands.wait_for_event(bt_dev.async_ev_encryption_change, 10)
|
||||
|
||||
############
|
||||
# L2CAP SEND
|
||||
############
|
||||
@@ -289,9 +293,10 @@ def parse_cfg_files(args) -> dict:
|
||||
with open(args.init_file, "r") as file:
|
||||
init_file = yaml.safe_load(file)
|
||||
ini = init_file[args.mode]
|
||||
global test_dir, transport_directory
|
||||
global test_dir, transport_directory, ltk
|
||||
test_dir = init_file["test_dir"]
|
||||
transport_directory = init_file["transport_directory"]
|
||||
hci.ltk = int(init_file["ltk"], 16)
|
||||
|
||||
with open(args.config_file) as f:
|
||||
cfg = yaml.safe_load(f)
|
||||
|
||||
@@ -29,6 +29,7 @@ import csv
|
||||
import util
|
||||
import os
|
||||
import math
|
||||
import random
|
||||
|
||||
PROCESS_TIMEOUT = 500 # seconds, adjust if necessary
|
||||
|
||||
@@ -94,6 +95,10 @@ def change_config_var(filename: str, group: str, variable: str,
|
||||
yaml.safe_dump(cfg, file, indent=1, sort_keys=False,
|
||||
default_style=None, default_flow_style=False)
|
||||
|
||||
def generate_long_term_key():
|
||||
rand_val = random.getrandbits(128)
|
||||
return rand_val.to_bytes(16, byteorder='little')
|
||||
|
||||
|
||||
def get_init_dict(filename: str, args_list: list, modes: list, dir: str,
|
||||
transport_directory: str):
|
||||
@@ -115,7 +120,8 @@ def get_init_dict(filename: str, args_list: list, modes: list, dir: str,
|
||||
"peer_address": args_list[0][2]
|
||||
},
|
||||
"test_dir": dir,
|
||||
"transport_directory": transport_directory
|
||||
"transport_directory": transport_directory,
|
||||
"ltk": hex(random.getrandbits(128))
|
||||
}
|
||||
|
||||
with open(filename, 'w') as file:
|
||||
|
||||
Reference in New Issue
Block a user