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):