You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by ja...@apache.org on 2022/08/04 06:57:27 UTC
[mynewt-nimble] branch master updated (f9eb3c8d -> c6444fac)
This is an automated email from the ASF dual-hosted git repository.
janc pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git
from f9eb3c8d nimble/ll: Fix continuation events handling
new 82dd24d8 tools/hci_throughput: testing over encrypted link
new c6444fac tools/hci_throughput: util path fix
The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
tools/hci_throughput/config.yaml.sample | 1 +
tools/hci_throughput/hci.py | 37 +++++++++++++++
tools/hci_throughput/hci_commands.py | 84 +++++++++++++++++++++++++++++++++
tools/hci_throughput/hci_device.py | 7 ++-
tools/hci_throughput/main.py | 8 +++-
tools/hci_throughput/util.py | 3 +-
6 files changed, 137 insertions(+), 3 deletions(-)
[mynewt-nimble] 01/02: tools/hci_throughput: testing over encrypted link
Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
janc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git
commit 82dd24d8257b2d66fb2f5b447e19c6493fb781a7
Author: Jakub <ja...@codecoup.pl>
AuthorDate: Wed Aug 3 17:38:47 2022 +0200
tools/hci_throughput: testing over encrypted link
Added option enable_encryption to run throughput
tests over encrypted link.
---
tools/hci_throughput/config.yaml.sample | 1 +
tools/hci_throughput/hci.py | 37 +++++++++++++++
tools/hci_throughput/hci_commands.py | 84 +++++++++++++++++++++++++++++++++
tools/hci_throughput/hci_device.py | 7 ++-
tools/hci_throughput/main.py | 8 +++-
5 files changed, 135 insertions(+), 2 deletions(-)
diff --git a/tools/hci_throughput/config.yaml.sample b/tools/hci_throughput/config.yaml.sample
index 7a833007..68068e3e 100644
--- a/tools/hci_throughput/config.yaml.sample
+++ b/tools/hci_throughput/config.yaml.sample
@@ -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
diff --git a/tools/hci_throughput/hci.py b/tools/hci_throughput/hci.py
index d0a0b8a1..e5eb1179 100644
--- a/tools/hci_throughput/hci.py
+++ b/tools/hci_throughput/hci.py
@@ -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
diff --git a/tools/hci_throughput/hci_commands.py b/tools/hci_throughput/hci_commands.py
index 83e6284f..31bed375 100644
--- a/tools/hci_throughput/hci_commands.py
+++ b/tools/hci_throughput/hci_commands.py
@@ -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")
diff --git a/tools/hci_throughput/hci_device.py b/tools/hci_throughput/hci_device.py
index dacb391c..b054b705 100644
--- a/tools/hci_throughput/hci_device.py
+++ b/tools/hci_throughput/hci_device.py
@@ -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)
diff --git a/tools/hci_throughput/main.py b/tools/hci_throughput/main.py
index b00780a0..565cce42 100644
--- a/tools/hci_throughput/main.py
+++ b/tools/hci_throughput/main.py
@@ -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:
[mynewt-nimble] 02/02: tools/hci_throughput: util path fix
Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
janc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git
commit c6444face72d5fc2fa58d0a68793b73bc18e05a3
Author: Jakub <ja...@codecoup.pl>
AuthorDate: Wed Aug 3 17:40:02 2022 +0200
tools/hci_throughput: util path fix
---
tools/hci_throughput/util.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/tools/hci_throughput/util.py b/tools/hci_throughput/util.py
index 472057b1..96bfd908 100644
--- a/tools/hci_throughput/util.py
+++ b/tools/hci_throughput/util.py
@@ -21,6 +21,7 @@ import logging
import shutil
import time
import os
+from pathlib import Path
def create_test_directory():
@@ -50,7 +51,7 @@ def configure_logging(log_filename, clear_log_file=True):
def copy_config_files_to_test_directory(files: list, test_directory: str):
for file in files:
- shutil.copy(file, test_directory + "/" + file)
+ shutil.copy(file, test_directory + "/" + Path(file).name)
def copy_log_files_to_test_directory(dir: str):