bumble 0.0.219__py3-none-any.whl → 0.0.221__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bumble/_version.py +2 -2
- bumble/a2dp.py +5 -5
- bumble/apps/auracast.py +746 -479
- bumble/apps/bench.py +4 -5
- bumble/apps/console.py +5 -10
- bumble/apps/controller_info.py +12 -7
- bumble/apps/controller_loopback.py +1 -2
- bumble/apps/device_info.py +2 -3
- bumble/apps/gatt_dump.py +0 -1
- bumble/apps/lea_unicast/app.py +1 -1
- bumble/apps/pair.py +49 -46
- bumble/apps/pandora_server.py +2 -2
- bumble/apps/player/player.py +10 -12
- bumble/apps/rfcomm_bridge.py +10 -11
- bumble/apps/scan.py +1 -3
- bumble/apps/speaker/speaker.py +3 -4
- bumble/at.py +4 -5
- bumble/att.py +91 -25
- bumble/audio/io.py +8 -6
- bumble/avc.py +1 -2
- bumble/avctp.py +2 -3
- bumble/avdtp.py +53 -57
- bumble/avrcp.py +25 -27
- bumble/codecs.py +15 -15
- bumble/colors.py +7 -8
- bumble/controller.py +1201 -643
- bumble/core.py +41 -49
- bumble/crypto/__init__.py +2 -1
- bumble/crypto/builtin.py +2 -8
- bumble/data_types.py +2 -1
- bumble/decoder.py +2 -3
- bumble/device.py +278 -325
- bumble/drivers/__init__.py +3 -2
- bumble/drivers/intel.py +6 -8
- bumble/drivers/rtk.py +1 -1
- bumble/gatt.py +9 -9
- bumble/gatt_adapters.py +6 -6
- bumble/gatt_client.py +110 -60
- bumble/gatt_server.py +209 -139
- bumble/hci.py +87 -74
- bumble/helpers.py +5 -5
- bumble/hfp.py +27 -26
- bumble/hid.py +9 -9
- bumble/host.py +44 -50
- bumble/keys.py +17 -17
- bumble/l2cap.py +1015 -218
- bumble/link.py +54 -284
- bumble/ll.py +200 -0
- bumble/lmp.py +324 -0
- bumble/pairing.py +14 -15
- bumble/pandora/__init__.py +2 -2
- bumble/pandora/device.py +6 -4
- bumble/pandora/host.py +19 -10
- bumble/pandora/l2cap.py +8 -9
- bumble/pandora/security.py +18 -16
- bumble/pandora/utils.py +4 -4
- bumble/profiles/aics.py +6 -8
- bumble/profiles/ams.py +3 -5
- bumble/profiles/ancs.py +11 -11
- bumble/profiles/ascs.py +5 -5
- bumble/profiles/asha.py +10 -9
- bumble/profiles/bass.py +9 -3
- bumble/profiles/battery_service.py +1 -2
- bumble/profiles/csip.py +9 -10
- bumble/profiles/device_information_service.py +16 -17
- bumble/profiles/gap.py +3 -4
- bumble/profiles/gatt_service.py +0 -1
- bumble/profiles/gmap.py +12 -13
- bumble/profiles/hap.py +3 -3
- bumble/profiles/heart_rate_service.py +7 -8
- bumble/profiles/le_audio.py +1 -1
- bumble/profiles/mcp.py +28 -28
- bumble/profiles/pacs.py +13 -17
- bumble/profiles/pbp.py +16 -0
- bumble/profiles/vcs.py +2 -2
- bumble/profiles/vocs.py +6 -9
- bumble/rfcomm.py +19 -18
- bumble/sdp.py +12 -11
- bumble/smp.py +20 -30
- bumble/snoop.py +12 -5
- bumble/tools/generate_company_id_list.py +1 -1
- bumble/tools/intel_util.py +2 -2
- bumble/tools/rtk_fw_download.py +1 -1
- bumble/tools/rtk_util.py +1 -1
- bumble/transport/__init__.py +1 -2
- bumble/transport/android_emulator.py +2 -3
- bumble/transport/android_netsim.py +49 -40
- bumble/transport/common.py +9 -9
- bumble/transport/file.py +1 -2
- bumble/transport/hci_socket.py +2 -3
- bumble/transport/pty.py +3 -5
- bumble/transport/pyusb.py +8 -5
- bumble/transport/serial.py +1 -2
- bumble/transport/vhci.py +1 -2
- bumble/transport/ws_server.py +2 -3
- bumble/utils.py +23 -14
- bumble/vendor/android/hci.py +4 -2
- {bumble-0.0.219.dist-info → bumble-0.0.221.dist-info}/METADATA +4 -3
- bumble-0.0.221.dist-info/RECORD +185 -0
- bumble-0.0.219.dist-info/RECORD +0 -183
- {bumble-0.0.219.dist-info → bumble-0.0.221.dist-info}/WHEEL +0 -0
- {bumble-0.0.219.dist-info → bumble-0.0.221.dist-info}/entry_points.txt +0 -0
- {bumble-0.0.219.dist-info → bumble-0.0.221.dist-info}/licenses/LICENSE +0 -0
- {bumble-0.0.219.dist-info → bumble-0.0.221.dist-info}/top_level.txt +0 -0
bumble/controller.py
CHANGED
|
@@ -23,48 +23,14 @@ import itertools
|
|
|
23
23
|
import logging
|
|
24
24
|
import random
|
|
25
25
|
import struct
|
|
26
|
-
from typing import TYPE_CHECKING, Any,
|
|
26
|
+
from typing import TYPE_CHECKING, Any, cast
|
|
27
27
|
|
|
28
|
-
from bumble import hci
|
|
28
|
+
from bumble import hci, link, ll, lmp
|
|
29
|
+
from bumble import link as bumble_link
|
|
29
30
|
from bumble.colors import color
|
|
30
31
|
from bumble.core import PhysicalTransport
|
|
31
|
-
from bumble.hci import (
|
|
32
|
-
HCI_ACL_DATA_PACKET,
|
|
33
|
-
HCI_COMMAND_DISALLOWED_ERROR,
|
|
34
|
-
HCI_COMMAND_PACKET,
|
|
35
|
-
HCI_COMMAND_STATUS_PENDING,
|
|
36
|
-
HCI_CONTROLLER_BUSY_ERROR,
|
|
37
|
-
HCI_EVENT_PACKET,
|
|
38
|
-
HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR,
|
|
39
|
-
HCI_LE_1M_PHY,
|
|
40
|
-
HCI_REMOTE_USER_TERMINATED_CONNECTION_ERROR,
|
|
41
|
-
HCI_SUCCESS,
|
|
42
|
-
HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR,
|
|
43
|
-
HCI_UNKNOWN_HCI_COMMAND_ERROR,
|
|
44
|
-
HCI_VERSION_BLUETOOTH_CORE_5_0,
|
|
45
|
-
Address,
|
|
46
|
-
HCI_AclDataPacket,
|
|
47
|
-
HCI_AclDataPacketAssembler,
|
|
48
|
-
HCI_Command_Complete_Event,
|
|
49
|
-
HCI_Command_Status_Event,
|
|
50
|
-
HCI_Connection_Complete_Event,
|
|
51
|
-
HCI_Connection_Request_Event,
|
|
52
|
-
HCI_Disconnection_Complete_Event,
|
|
53
|
-
HCI_Encryption_Change_Event,
|
|
54
|
-
HCI_LE_Advertising_Report_Event,
|
|
55
|
-
HCI_LE_CIS_Established_Event,
|
|
56
|
-
HCI_LE_CIS_Request_Event,
|
|
57
|
-
HCI_LE_Connection_Complete_Event,
|
|
58
|
-
HCI_LE_Read_Remote_Features_Complete_Event,
|
|
59
|
-
HCI_Number_Of_Completed_Packets_Event,
|
|
60
|
-
HCI_Packet,
|
|
61
|
-
HCI_Role_Change_Event,
|
|
62
|
-
HCI_Synchronous_Connection_Complete_Event,
|
|
63
|
-
Role,
|
|
64
|
-
)
|
|
65
32
|
|
|
66
33
|
if TYPE_CHECKING:
|
|
67
|
-
from bumble.link import LocalLink
|
|
68
34
|
from bumble.transport.common import TransportSink
|
|
69
35
|
|
|
70
36
|
# -----------------------------------------------------------------------------
|
|
@@ -86,28 +52,156 @@ class CisLink:
|
|
|
86
52
|
handle: int
|
|
87
53
|
cis_id: int
|
|
88
54
|
cig_id: int
|
|
89
|
-
acl_connection:
|
|
55
|
+
acl_connection: Connection | None = None
|
|
90
56
|
data_paths: set[int] = dataclasses.field(default_factory=set)
|
|
91
57
|
|
|
92
58
|
|
|
59
|
+
# -----------------------------------------------------------------------------
|
|
60
|
+
@dataclasses.dataclass
|
|
61
|
+
class LegacyAdvertiser:
|
|
62
|
+
controller: Controller
|
|
63
|
+
advertising_interval_min: int = 0
|
|
64
|
+
advertising_interval_max: int = 0
|
|
65
|
+
advertising_type: int = 0
|
|
66
|
+
own_address_type: int = 0
|
|
67
|
+
peer_address_type: int = 0
|
|
68
|
+
peer_address: hci.Address = hci.Address.ANY
|
|
69
|
+
advertising_channel_map: int = 0
|
|
70
|
+
advertising_filter_policy: int = 0
|
|
71
|
+
|
|
72
|
+
advertising_data: bytes = b''
|
|
73
|
+
scan_response_data: bytes = b''
|
|
74
|
+
|
|
75
|
+
enabled: bool = False
|
|
76
|
+
timer_handle: asyncio.Handle | None = None
|
|
77
|
+
|
|
78
|
+
@property
|
|
79
|
+
def address(self) -> hci.Address:
|
|
80
|
+
'''Address used in advertising PDU.'''
|
|
81
|
+
if self.own_address_type == hci.Address.PUBLIC_DEVICE_ADDRESS:
|
|
82
|
+
return self.controller.public_address
|
|
83
|
+
else:
|
|
84
|
+
return self.controller.random_address
|
|
85
|
+
|
|
86
|
+
def _on_timer_fired(self) -> None:
|
|
87
|
+
self.send_advertising_data()
|
|
88
|
+
self.timer_handle = asyncio.get_running_loop().call_later(
|
|
89
|
+
self.advertising_interval_min / 1000.0, self._on_timer_fired
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
def start(self) -> None:
|
|
93
|
+
# Stop any ongoing advertising before we start again
|
|
94
|
+
self.stop()
|
|
95
|
+
self.enabled = True
|
|
96
|
+
|
|
97
|
+
# Advertise now
|
|
98
|
+
self.timer_handle = asyncio.get_running_loop().call_soon(self._on_timer_fired)
|
|
99
|
+
|
|
100
|
+
def stop(self) -> None:
|
|
101
|
+
if self.timer_handle is not None:
|
|
102
|
+
self.timer_handle.cancel()
|
|
103
|
+
self.timer_handle = None
|
|
104
|
+
self.enabled = False
|
|
105
|
+
|
|
106
|
+
def send_advertising_data(self) -> None:
|
|
107
|
+
if not self.enabled:
|
|
108
|
+
return
|
|
109
|
+
|
|
110
|
+
if (
|
|
111
|
+
self.advertising_type
|
|
112
|
+
== hci.HCI_LE_Set_Advertising_Parameters_Command.AdvertisingType.ADV_IND
|
|
113
|
+
):
|
|
114
|
+
self.controller.send_advertising_pdu(
|
|
115
|
+
ll.AdvInd(
|
|
116
|
+
advertiser_address=self.address,
|
|
117
|
+
data=self.advertising_data,
|
|
118
|
+
)
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
# -----------------------------------------------------------------------------
|
|
123
|
+
@dataclasses.dataclass
|
|
124
|
+
class AdvertisingSet:
|
|
125
|
+
controller: Controller
|
|
126
|
+
handle: int
|
|
127
|
+
parameters: hci.HCI_LE_Set_Extended_Advertising_Parameters_Command | None = None
|
|
128
|
+
data: bytearray = dataclasses.field(default_factory=bytearray)
|
|
129
|
+
scan_response_data: bytearray = dataclasses.field(default_factory=bytearray)
|
|
130
|
+
enabled: bool = False
|
|
131
|
+
timer_handle: asyncio.Handle | None = None
|
|
132
|
+
random_address: hci.Address | None = None
|
|
133
|
+
|
|
134
|
+
@property
|
|
135
|
+
def address(self) -> hci.Address | None:
|
|
136
|
+
'''Address used in advertising PDU.'''
|
|
137
|
+
if not self.parameters:
|
|
138
|
+
return None
|
|
139
|
+
if self.parameters.own_address_type == hci.Address.PUBLIC_DEVICE_ADDRESS:
|
|
140
|
+
return self.controller.public_address
|
|
141
|
+
else:
|
|
142
|
+
return self.random_address
|
|
143
|
+
|
|
144
|
+
def _on_extended_advertising_timer_fired(self) -> None:
|
|
145
|
+
if not self.enabled:
|
|
146
|
+
return
|
|
147
|
+
|
|
148
|
+
self.send_extended_advertising_data()
|
|
149
|
+
|
|
150
|
+
interval = (
|
|
151
|
+
self.parameters.primary_advertising_interval_min * 0.625 / 1000.0
|
|
152
|
+
if self.parameters
|
|
153
|
+
else 1.0
|
|
154
|
+
)
|
|
155
|
+
self.timer_handle = asyncio.get_running_loop().call_later(
|
|
156
|
+
interval, self._on_extended_advertising_timer_fired
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
def start(self) -> None:
|
|
160
|
+
self.enabled = True
|
|
161
|
+
asyncio.get_running_loop().call_soon(self._on_extended_advertising_timer_fired)
|
|
162
|
+
|
|
163
|
+
def stop(self) -> None:
|
|
164
|
+
self.enabled = False
|
|
165
|
+
if timer_handle := self.timer_handle:
|
|
166
|
+
timer_handle.cancel()
|
|
167
|
+
self.timer_handle = None
|
|
168
|
+
|
|
169
|
+
def send_extended_advertising_data(self) -> None:
|
|
170
|
+
if self.controller.link:
|
|
171
|
+
address = self.address
|
|
172
|
+
assert address
|
|
173
|
+
|
|
174
|
+
self.controller.send_advertising_pdu(ll.AdvInd(address, bytes(self.data)))
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
# -----------------------------------------------------------------------------
|
|
178
|
+
@dataclasses.dataclass
|
|
179
|
+
class ScoLink:
|
|
180
|
+
handle: int
|
|
181
|
+
link_type: int
|
|
182
|
+
peer_address: hci.Address
|
|
183
|
+
|
|
184
|
+
|
|
93
185
|
# -----------------------------------------------------------------------------
|
|
94
186
|
@dataclasses.dataclass
|
|
95
187
|
class Connection:
|
|
96
188
|
controller: Controller
|
|
97
189
|
handle: int
|
|
98
|
-
role: Role
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
190
|
+
role: hci.Role
|
|
191
|
+
self_address: hci.Address
|
|
192
|
+
peer_address: hci.Address
|
|
193
|
+
link: link.LocalLink
|
|
194
|
+
transport: PhysicalTransport
|
|
102
195
|
link_type: int
|
|
196
|
+
classic_allow_role_switch: bool = False
|
|
103
197
|
|
|
104
198
|
def __post_init__(self) -> None:
|
|
105
|
-
self.assembler = HCI_AclDataPacketAssembler(self.on_acl_pdu)
|
|
199
|
+
self.assembler = hci.HCI_AclDataPacketAssembler(self.on_acl_pdu)
|
|
106
200
|
|
|
107
201
|
def on_hci_acl_data_packet(self, packet: hci.HCI_AclDataPacket) -> None:
|
|
108
202
|
self.assembler.feed_packet(packet)
|
|
109
203
|
self.controller.send_hci_packet(
|
|
110
|
-
HCI_Number_Of_Completed_Packets_Event(
|
|
204
|
+
hci.HCI_Number_Of_Completed_Packets_Event(
|
|
111
205
|
connection_handles=[self.handle], num_completed_packets=[1]
|
|
112
206
|
)
|
|
113
207
|
)
|
|
@@ -118,24 +212,31 @@ class Connection:
|
|
|
118
212
|
self.controller, self.peer_address, self.transport, pdu
|
|
119
213
|
)
|
|
120
214
|
|
|
215
|
+
def send_ll_control_pdu(self, packet: ll.ControlPdu) -> None:
|
|
216
|
+
if self.link:
|
|
217
|
+
self.link.send_ll_control_pdu(
|
|
218
|
+
sender_address=self.self_address,
|
|
219
|
+
receiver_address=self.peer_address,
|
|
220
|
+
packet=packet,
|
|
221
|
+
)
|
|
222
|
+
|
|
121
223
|
|
|
122
224
|
# -----------------------------------------------------------------------------
|
|
123
225
|
class Controller:
|
|
124
|
-
hci_sink:
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
Address, Connection
|
|
131
|
-
] # Connections where this controller is the peripheral
|
|
132
|
-
classic_connections: dict[Address, Connection] # Connections in BR/EDR
|
|
226
|
+
hci_sink: TransportSink | None = None
|
|
227
|
+
|
|
228
|
+
le_connections: dict[hci.Address, Connection] # LE Connections
|
|
229
|
+
classic_connections: dict[hci.Address, Connection] # Connections in BR/EDR
|
|
230
|
+
classic_pending_commands: dict[hci.Address, dict[lmp.Opcode, asyncio.Future[int]]]
|
|
231
|
+
sco_links: dict[hci.Address, ScoLink] # SCO links by address
|
|
133
232
|
central_cis_links: dict[int, CisLink] # CIS links by handle
|
|
134
233
|
peripheral_cis_links: dict[int, CisLink] # CIS links by handle
|
|
234
|
+
advertising_sets: dict[int, AdvertisingSet] # Advertising sets by handle
|
|
235
|
+
le_legacy_advertiser: LegacyAdvertiser
|
|
135
236
|
|
|
136
|
-
hci_version: int = HCI_VERSION_BLUETOOTH_CORE_5_0
|
|
237
|
+
hci_version: int = hci.HCI_VERSION_BLUETOOTH_CORE_5_0
|
|
137
238
|
hci_revision: int = 0
|
|
138
|
-
lmp_version: int = HCI_VERSION_BLUETOOTH_CORE_5_0
|
|
239
|
+
lmp_version: int = hci.HCI_VERSION_BLUETOOTH_CORE_5_0
|
|
139
240
|
lmp_subversion: int = 0
|
|
140
241
|
lmp_features: bytes = bytes.fromhex(
|
|
141
242
|
'0000000060000000'
|
|
@@ -154,10 +255,20 @@ class Controller:
|
|
|
154
255
|
'30f0f9ff01008004002000000000000000000000000000000000000000000000'
|
|
155
256
|
)
|
|
156
257
|
le_event_mask: int = 0
|
|
157
|
-
|
|
158
|
-
|
|
258
|
+
le_features: hci.LeFeatureMask = (
|
|
259
|
+
hci.LeFeatureMask.LE_ENCRYPTION
|
|
260
|
+
| hci.LeFeatureMask.CONNECTION_PARAMETERS_REQUEST_PROCEDURE
|
|
261
|
+
| hci.LeFeatureMask.EXTENDED_REJECT_INDICATION
|
|
262
|
+
| hci.LeFeatureMask.PERIPHERAL_INITIATED_FEATURE_EXCHANGE
|
|
263
|
+
| hci.LeFeatureMask.LE_PING
|
|
264
|
+
| hci.LeFeatureMask.LE_DATA_PACKET_LENGTH_EXTENSION
|
|
265
|
+
| hci.LeFeatureMask.LL_PRIVACY
|
|
266
|
+
| hci.LeFeatureMask.EXTENDED_SCANNER_FILTER_POLICIES
|
|
267
|
+
| hci.LeFeatureMask.LE_2M_PHY
|
|
268
|
+
| hci.LeFeatureMask.LE_CODED_PHY
|
|
269
|
+
| hci.LeFeatureMask.CHANNEL_SELECTION_ALGORITHM_2
|
|
270
|
+
| hci.LeFeatureMask.MINIMUM_NUMBER_OF_USED_CHANNELS_PROCEDURE
|
|
159
271
|
)
|
|
160
|
-
le_features: bytes = bytes.fromhex('ff49010000000000')
|
|
161
272
|
le_states: bytes = bytes.fromhex('ffff3fffff030000')
|
|
162
273
|
advertising_channel_tx_power: int = 0
|
|
163
274
|
filter_accept_list_size: int = 8
|
|
@@ -173,49 +284,58 @@ class Controller:
|
|
|
173
284
|
le_scan_type: int = 0
|
|
174
285
|
le_scan_interval: int = 0x10
|
|
175
286
|
le_scan_window: int = 0x10
|
|
176
|
-
le_scan_enable:
|
|
177
|
-
le_scan_own_address_type: int = Address.RANDOM_DEVICE_ADDRESS
|
|
287
|
+
le_scan_enable: bool = False
|
|
288
|
+
le_scan_own_address_type: int = hci.Address.RANDOM_DEVICE_ADDRESS
|
|
178
289
|
le_scanning_filter_policy: int = 0
|
|
179
|
-
le_scan_response_data: Optional[bytes] = None
|
|
180
290
|
le_address_resolution: bool = False
|
|
181
291
|
le_rpa_timeout: int = 0
|
|
182
292
|
sync_flow_control: bool = False
|
|
183
293
|
local_name: str = 'Bumble'
|
|
184
294
|
advertising_interval: int = 2000
|
|
185
|
-
advertising_data:
|
|
186
|
-
advertising_timer_handle:
|
|
187
|
-
|
|
188
|
-
|
|
295
|
+
advertising_data: bytes | None = None
|
|
296
|
+
advertising_timer_handle: asyncio.Handle | None = None
|
|
297
|
+
classic_scan_enable: int = 0
|
|
298
|
+
classic_allow_role_switch: bool = True
|
|
299
|
+
pending_le_connection: (
|
|
300
|
+
hci.HCI_LE_Create_Connection_Command
|
|
301
|
+
| hci.HCI_LE_Extended_Create_Connection_Command
|
|
302
|
+
| None
|
|
303
|
+
) = None
|
|
304
|
+
|
|
305
|
+
_random_address: hci.Address = hci.Address('00:00:00:00:00:00')
|
|
189
306
|
|
|
190
307
|
def __init__(
|
|
191
308
|
self,
|
|
192
309
|
name: str,
|
|
193
310
|
host_source=None,
|
|
194
|
-
host_sink:
|
|
195
|
-
link:
|
|
196
|
-
public_address:
|
|
311
|
+
host_sink: TransportSink | None = None,
|
|
312
|
+
link: link.LocalLink | None = None,
|
|
313
|
+
public_address: bytes | str | hci.Address | None = None,
|
|
197
314
|
) -> None:
|
|
198
315
|
self.name = name
|
|
199
|
-
self.link = link
|
|
200
|
-
self.
|
|
201
|
-
self.peripheral_connections = {}
|
|
316
|
+
self.link = link or bumble_link.LocalLink()
|
|
317
|
+
self.le_connections = {}
|
|
202
318
|
self.classic_connections = {}
|
|
319
|
+
self.sco_links = {}
|
|
320
|
+
self.classic_pending_commands = {}
|
|
203
321
|
self.central_cis_links = {}
|
|
204
322
|
self.peripheral_cis_links = {}
|
|
323
|
+
self.advertising_sets = {}
|
|
205
324
|
self.default_phy = {
|
|
206
325
|
'all_phys': 0,
|
|
207
326
|
'tx_phys': 0,
|
|
208
327
|
'rx_phys': 0,
|
|
209
328
|
}
|
|
329
|
+
self.le_legacy_advertiser = LegacyAdvertiser(self)
|
|
210
330
|
|
|
211
|
-
if isinstance(public_address, Address):
|
|
331
|
+
if isinstance(public_address, hci.Address):
|
|
212
332
|
self._public_address = public_address
|
|
213
333
|
elif public_address is not None:
|
|
214
|
-
self._public_address = Address(
|
|
215
|
-
public_address, Address.PUBLIC_DEVICE_ADDRESS
|
|
334
|
+
self._public_address = hci.Address(
|
|
335
|
+
public_address, hci.Address.PUBLIC_DEVICE_ADDRESS
|
|
216
336
|
)
|
|
217
337
|
else:
|
|
218
|
-
self._public_address = Address('00:00:00:00:00:00')
|
|
338
|
+
self._public_address = hci.Address('00:00:00:00:00:00')
|
|
219
339
|
|
|
220
340
|
# Set the source and sink interfaces
|
|
221
341
|
if host_source:
|
|
@@ -231,41 +351,41 @@ class Controller:
|
|
|
231
351
|
)
|
|
232
352
|
|
|
233
353
|
@property
|
|
234
|
-
def host(self) ->
|
|
354
|
+
def host(self) -> TransportSink | None:
|
|
235
355
|
return self.hci_sink
|
|
236
356
|
|
|
237
357
|
@host.setter
|
|
238
|
-
def host(self, host:
|
|
358
|
+
def host(self, host: TransportSink | None) -> None:
|
|
239
359
|
'''
|
|
240
360
|
Sets the host (sink) for this controller, and set this controller as the
|
|
241
361
|
controller (sink) for the host
|
|
242
362
|
'''
|
|
243
363
|
self.set_packet_sink(host)
|
|
244
364
|
|
|
245
|
-
def set_packet_sink(self, sink:
|
|
365
|
+
def set_packet_sink(self, sink: TransportSink | None) -> None:
|
|
246
366
|
'''
|
|
247
367
|
Method from the Packet Source interface
|
|
248
368
|
'''
|
|
249
369
|
self.hci_sink = sink
|
|
250
370
|
|
|
251
371
|
@property
|
|
252
|
-
def public_address(self) -> Address:
|
|
372
|
+
def public_address(self) -> hci.Address:
|
|
253
373
|
return self._public_address
|
|
254
374
|
|
|
255
375
|
@public_address.setter
|
|
256
|
-
def public_address(self, address:
|
|
376
|
+
def public_address(self, address: hci.Address | str) -> None:
|
|
257
377
|
if isinstance(address, str):
|
|
258
|
-
address = Address(address)
|
|
378
|
+
address = hci.Address(address)
|
|
259
379
|
self._public_address = address
|
|
260
380
|
|
|
261
381
|
@property
|
|
262
|
-
def random_address(self) -> Address:
|
|
382
|
+
def random_address(self) -> hci.Address:
|
|
263
383
|
return self._random_address
|
|
264
384
|
|
|
265
385
|
@random_address.setter
|
|
266
|
-
def random_address(self, address:
|
|
386
|
+
def random_address(self, address: hci.Address | str) -> None:
|
|
267
387
|
if isinstance(address, str):
|
|
268
|
-
address = Address(address)
|
|
388
|
+
address = hci.Address(address)
|
|
269
389
|
self._random_address = address
|
|
270
390
|
logger.debug(f'new random address: {address}')
|
|
271
391
|
|
|
@@ -274,9 +394,9 @@ class Controller:
|
|
|
274
394
|
|
|
275
395
|
# Packet Sink protocol (packets coming from the host via HCI)
|
|
276
396
|
def on_packet(self, packet: bytes) -> None:
|
|
277
|
-
self.on_hci_packet(HCI_Packet.from_bytes(packet))
|
|
397
|
+
self.on_hci_packet(hci.HCI_Packet.from_bytes(packet))
|
|
278
398
|
|
|
279
|
-
def on_hci_packet(self, packet: HCI_Packet) -> None:
|
|
399
|
+
def on_hci_packet(self, packet: hci.HCI_Packet) -> None:
|
|
280
400
|
logger.debug(
|
|
281
401
|
f'{color("<<<", "blue")} [{self.name}] '
|
|
282
402
|
f'{color("HOST -> CONTROLLER", "blue")}: {packet}'
|
|
@@ -295,17 +415,17 @@ class Controller:
|
|
|
295
415
|
def on_hci_command_packet(self, command: hci.HCI_Command) -> None:
|
|
296
416
|
handler_name = f'on_{command.name.lower()}'
|
|
297
417
|
handler = getattr(self, handler_name, self.on_hci_command)
|
|
298
|
-
result:
|
|
418
|
+
result: bytes | None = handler(command)
|
|
299
419
|
if isinstance(result, bytes):
|
|
300
420
|
self.send_hci_packet(
|
|
301
|
-
HCI_Command_Complete_Event(
|
|
421
|
+
hci.HCI_Command_Complete_Event(
|
|
302
422
|
num_hci_command_packets=1,
|
|
303
423
|
command_opcode=command.op_code,
|
|
304
424
|
return_parameters=result,
|
|
305
425
|
)
|
|
306
426
|
)
|
|
307
427
|
|
|
308
|
-
def on_hci_event_packet(self, _event: HCI_Packet) -> None:
|
|
428
|
+
def on_hci_event_packet(self, _event: hci.HCI_Packet) -> None:
|
|
309
429
|
logger.warning('!!! unexpected event packet')
|
|
310
430
|
|
|
311
431
|
def on_hci_acl_data_packet(self, packet: hci.HCI_AclDataPacket) -> None:
|
|
@@ -320,13 +440,13 @@ class Controller:
|
|
|
320
440
|
# Pass the packet to the connection
|
|
321
441
|
connection.on_hci_acl_data_packet(packet)
|
|
322
442
|
|
|
323
|
-
def send_hci_packet(self, packet: HCI_Packet) -> None:
|
|
443
|
+
def send_hci_packet(self, packet: hci.HCI_Packet) -> None:
|
|
324
444
|
logger.debug(
|
|
325
445
|
f'{color(">>>", "green")} [{self.name}] '
|
|
326
446
|
f'{color("CONTROLLER -> HOST", "green")}: {packet}'
|
|
327
447
|
)
|
|
328
448
|
if self.host:
|
|
329
|
-
self.host.on_packet
|
|
449
|
+
asyncio.get_running_loop().call_soon(self.host.on_packet, bytes(packet))
|
|
330
450
|
|
|
331
451
|
# This method allows the controller to emulate the same API as a transport source
|
|
332
452
|
async def wait_for_termination(self) -> None:
|
|
@@ -336,99 +456,125 @@ class Controller:
|
|
|
336
456
|
# Link connections
|
|
337
457
|
############################################################
|
|
338
458
|
def allocate_connection_handle(self) -> int:
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
max_handle = max(max_handle, cis_handle)
|
|
354
|
-
if cis_handle == handle:
|
|
355
|
-
# Already used, continue searching after the current max
|
|
356
|
-
handle = max_handle + 1
|
|
357
|
-
return handle
|
|
358
|
-
|
|
359
|
-
def find_le_connection_by_address(self, address: Address) -> Optional[Connection]:
|
|
360
|
-
return self.central_connections.get(address) or self.peripheral_connections.get(
|
|
361
|
-
address
|
|
459
|
+
current_handles = set(
|
|
460
|
+
cast(Connection | CisLink | ScoLink, link).handle
|
|
461
|
+
for link in itertools.chain(
|
|
462
|
+
self.le_connections.values(),
|
|
463
|
+
self.classic_connections.values(),
|
|
464
|
+
self.sco_links.values(),
|
|
465
|
+
self.central_cis_links.values(),
|
|
466
|
+
self.peripheral_cis_links.values(),
|
|
467
|
+
)
|
|
468
|
+
)
|
|
469
|
+
return next(
|
|
470
|
+
handle
|
|
471
|
+
for handle in range(0x0001, 0xEFF + 1)
|
|
472
|
+
if handle not in current_handles
|
|
362
473
|
)
|
|
363
474
|
|
|
364
|
-
def
|
|
365
|
-
self, address: Address
|
|
366
|
-
) -> Optional[Connection]:
|
|
367
|
-
return self.classic_connections.get(address)
|
|
368
|
-
|
|
369
|
-
def find_connection_by_handle(self, handle: int) -> Optional[Connection]:
|
|
475
|
+
def find_connection_by_handle(self, handle: int) -> Connection | None:
|
|
370
476
|
for connection in itertools.chain(
|
|
371
|
-
self.
|
|
372
|
-
self.peripheral_connections.values(),
|
|
477
|
+
self.le_connections.values(),
|
|
373
478
|
self.classic_connections.values(),
|
|
374
479
|
):
|
|
375
480
|
if connection.handle == handle:
|
|
376
481
|
return connection
|
|
377
482
|
return None
|
|
378
483
|
|
|
379
|
-
def
|
|
380
|
-
for connection in self.
|
|
381
|
-
if connection.handle == handle:
|
|
382
|
-
return connection
|
|
383
|
-
return None
|
|
384
|
-
|
|
385
|
-
def find_peripheral_connection_by_handle(self, handle: int) -> Optional[Connection]:
|
|
386
|
-
for connection in self.peripheral_connections.values():
|
|
387
|
-
if connection.handle == handle:
|
|
388
|
-
return connection
|
|
389
|
-
return None
|
|
390
|
-
|
|
391
|
-
def find_classic_connection_by_handle(self, handle: int) -> Optional[Connection]:
|
|
392
|
-
for connection in self.classic_connections.values():
|
|
484
|
+
def find_classic_sco_link_by_handle(self, handle: int) -> ScoLink | None:
|
|
485
|
+
for connection in self.sco_links.values():
|
|
393
486
|
if connection.handle == handle:
|
|
394
487
|
return connection
|
|
395
488
|
return None
|
|
396
489
|
|
|
397
|
-
def find_iso_link_by_handle(self, handle: int) ->
|
|
490
|
+
def find_iso_link_by_handle(self, handle: int) -> CisLink | None:
|
|
398
491
|
return self.central_cis_links.get(handle) or self.peripheral_cis_links.get(
|
|
399
492
|
handle
|
|
400
493
|
)
|
|
401
494
|
|
|
402
|
-
def
|
|
495
|
+
def send_advertising_pdu(self, packet: ll.AdvertisingPdu) -> None:
|
|
496
|
+
logger.debug("[%s] >>> Advertising PDU: %s", self.name, packet)
|
|
497
|
+
if self.link:
|
|
498
|
+
self.link.send_advertising_pdu(self, packet)
|
|
499
|
+
|
|
500
|
+
def on_ll_control_pdu(
|
|
501
|
+
self, sender_address: hci.Address, packet: ll.ControlPdu
|
|
502
|
+
) -> None:
|
|
503
|
+
logger.debug("[%s] >>> LL Control PDU: %s", self.name, packet)
|
|
504
|
+
if not (connection := self.le_connections.get(sender_address)):
|
|
505
|
+
logger.error("Cannot find a connection for %s", sender_address)
|
|
506
|
+
return
|
|
507
|
+
|
|
508
|
+
if isinstance(packet, ll.TerminateInd):
|
|
509
|
+
self.on_le_disconnected(connection, packet.error_code)
|
|
510
|
+
elif isinstance(packet, ll.CisReq):
|
|
511
|
+
self.on_le_cis_request(connection, packet.cig_id, packet.cis_id)
|
|
512
|
+
elif isinstance(packet, ll.CisRsp):
|
|
513
|
+
self.on_le_cis_established(packet.cig_id, packet.cis_id)
|
|
514
|
+
connection.send_ll_control_pdu(ll.CisInd(packet.cig_id, packet.cis_id))
|
|
515
|
+
elif isinstance(packet, ll.CisInd):
|
|
516
|
+
self.on_le_cis_established(packet.cig_id, packet.cis_id)
|
|
517
|
+
elif isinstance(packet, ll.CisTerminateInd):
|
|
518
|
+
self.on_le_cis_disconnected(packet.cig_id, packet.cis_id)
|
|
519
|
+
elif isinstance(packet, ll.EncReq):
|
|
520
|
+
self.on_le_encrypted(connection)
|
|
521
|
+
|
|
522
|
+
def on_ll_advertising_pdu(self, packet: ll.AdvertisingPdu) -> None:
|
|
523
|
+
logger.debug("[%s] <<< Advertising PDU: %s", self.name, packet)
|
|
524
|
+
if isinstance(packet, ll.ConnectInd):
|
|
525
|
+
self.on_le_connect_ind(packet)
|
|
526
|
+
elif isinstance(packet, (ll.AdvInd, ll.AdvExtInd)):
|
|
527
|
+
self.on_advertising_pdu(packet)
|
|
528
|
+
|
|
529
|
+
def on_le_connect_ind(self, packet: ll.ConnectInd) -> None:
|
|
403
530
|
'''
|
|
404
531
|
Called when an incoming connection occurs from a central on the link
|
|
405
532
|
'''
|
|
533
|
+
advertiser: LegacyAdvertiser | AdvertisingSet | None
|
|
534
|
+
if (
|
|
535
|
+
self.le_legacy_advertiser.address == packet.advertiser_address
|
|
536
|
+
and self.le_legacy_advertiser.enabled
|
|
537
|
+
):
|
|
538
|
+
advertiser = self.le_legacy_advertiser
|
|
539
|
+
else:
|
|
540
|
+
advertiser = next(
|
|
541
|
+
(
|
|
542
|
+
advertising_set
|
|
543
|
+
for advertising_set in self.advertising_sets.values()
|
|
544
|
+
if advertising_set.address == packet.advertiser_address
|
|
545
|
+
and advertising_set.enabled
|
|
546
|
+
),
|
|
547
|
+
None,
|
|
548
|
+
)
|
|
549
|
+
|
|
550
|
+
if not advertiser:
|
|
551
|
+
# This is not send to us.
|
|
552
|
+
return
|
|
406
553
|
|
|
407
554
|
# Allocate (or reuse) a connection handle
|
|
408
|
-
peer_address =
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
logger.debug(f'New PERIPHERAL connection handle: 0x{connection_handle:04X}')
|
|
555
|
+
peer_address = packet.initiator_address
|
|
556
|
+
|
|
557
|
+
connection_handle = self.allocate_connection_handle()
|
|
558
|
+
connection = Connection(
|
|
559
|
+
controller=self,
|
|
560
|
+
handle=connection_handle,
|
|
561
|
+
role=hci.Role.PERIPHERAL,
|
|
562
|
+
self_address=packet.advertiser_address,
|
|
563
|
+
peer_address=peer_address,
|
|
564
|
+
link=self.link,
|
|
565
|
+
transport=PhysicalTransport.LE,
|
|
566
|
+
link_type=hci.HCI_Connection_Complete_Event.LinkType.ACL,
|
|
567
|
+
)
|
|
568
|
+
self.le_connections[peer_address] = connection
|
|
569
|
+
logger.debug(f'New PERIPHERAL connection handle: 0x{connection_handle:04X}')
|
|
424
570
|
|
|
425
571
|
# Then say that the connection has completed
|
|
426
572
|
self.send_hci_packet(
|
|
427
|
-
HCI_LE_Connection_Complete_Event(
|
|
428
|
-
status=HCI_SUCCESS,
|
|
573
|
+
hci.HCI_LE_Connection_Complete_Event(
|
|
574
|
+
status=hci.HCI_SUCCESS,
|
|
429
575
|
connection_handle=connection.handle,
|
|
430
576
|
role=connection.role,
|
|
431
|
-
peer_address_type=
|
|
577
|
+
peer_address_type=peer_address.address_type,
|
|
432
578
|
peer_address=peer_address,
|
|
433
579
|
connection_interval=10, # FIXME
|
|
434
580
|
peripheral_latency=0, # FIXME
|
|
@@ -437,175 +583,199 @@ class Controller:
|
|
|
437
583
|
)
|
|
438
584
|
)
|
|
439
585
|
|
|
440
|
-
|
|
441
|
-
'''
|
|
442
|
-
Called when an active disconnection occurs from a peer
|
|
443
|
-
'''
|
|
444
|
-
|
|
445
|
-
# Send a disconnection complete event
|
|
446
|
-
if connection := self.peripheral_connections.get(peer_address):
|
|
586
|
+
if isinstance(advertiser, AdvertisingSet):
|
|
447
587
|
self.send_hci_packet(
|
|
448
|
-
|
|
449
|
-
status=HCI_SUCCESS,
|
|
588
|
+
hci.HCI_LE_Advertising_Set_Terminated_Event(
|
|
589
|
+
status=hci.HCI_SUCCESS,
|
|
590
|
+
advertising_handle=advertiser.handle,
|
|
450
591
|
connection_handle=connection.handle,
|
|
451
|
-
|
|
592
|
+
num_completed_extended_advertising_events=0,
|
|
452
593
|
)
|
|
453
594
|
)
|
|
595
|
+
advertiser.stop()
|
|
454
596
|
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
reason=reason,
|
|
463
|
-
)
|
|
597
|
+
def on_le_disconnected(self, connection: Connection, reason: int) -> None:
|
|
598
|
+
# Send a disconnection complete event
|
|
599
|
+
self.send_hci_packet(
|
|
600
|
+
hci.HCI_Disconnection_Complete_Event(
|
|
601
|
+
status=hci.HCI_SUCCESS,
|
|
602
|
+
connection_handle=connection.handle,
|
|
603
|
+
reason=reason,
|
|
464
604
|
)
|
|
605
|
+
)
|
|
465
606
|
|
|
466
|
-
|
|
467
|
-
del self.central_connections[peer_address]
|
|
468
|
-
else:
|
|
469
|
-
logger.warning(f'!!! No peripheral connection found for {peer_address}')
|
|
470
|
-
|
|
471
|
-
def on_link_peripheral_connection_complete(
|
|
472
|
-
self,
|
|
473
|
-
le_create_connection_command: hci.HCI_LE_Create_Connection_Command,
|
|
474
|
-
status: int,
|
|
475
|
-
) -> None:
|
|
607
|
+
def create_le_connection(self, peer_address: hci.Address) -> None:
|
|
476
608
|
'''
|
|
477
|
-
Called
|
|
609
|
+
Called when we receive advertisement matching connection filter.
|
|
478
610
|
'''
|
|
611
|
+
pending_le_connection = self.pending_le_connection
|
|
612
|
+
assert pending_le_connection
|
|
479
613
|
|
|
480
|
-
if
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
614
|
+
if self.le_connections.get(peer_address):
|
|
615
|
+
logger.error("Connection for %s already exists?", peer_address)
|
|
616
|
+
return
|
|
617
|
+
|
|
618
|
+
self_address = (
|
|
619
|
+
self.public_address
|
|
620
|
+
if pending_le_connection.own_address_type == hci.OwnAddressType.PUBLIC
|
|
621
|
+
else self.random_address
|
|
622
|
+
)
|
|
623
|
+
|
|
624
|
+
# Allocate (or reuse) a connection handle
|
|
625
|
+
peer_address = pending_le_connection.peer_address
|
|
626
|
+
connection_handle = self.allocate_connection_handle()
|
|
627
|
+
connection = Connection(
|
|
628
|
+
controller=self,
|
|
629
|
+
handle=connection_handle,
|
|
630
|
+
role=hci.Role.CENTRAL,
|
|
631
|
+
self_address=self_address,
|
|
632
|
+
peer_address=peer_address,
|
|
633
|
+
link=self.link,
|
|
634
|
+
transport=PhysicalTransport.LE,
|
|
635
|
+
link_type=hci.HCI_Connection_Complete_Event.LinkType.ACL,
|
|
636
|
+
)
|
|
637
|
+
self.le_connections[peer_address] = connection
|
|
638
|
+
logger.debug(f'New CENTRAL connection handle: 0x{connection_handle:04X}')
|
|
501
639
|
|
|
640
|
+
if isinstance(
|
|
641
|
+
pending_le_connection, hci.HCI_LE_Extended_Create_Connection_Command
|
|
642
|
+
):
|
|
643
|
+
interval = pending_le_connection.connection_interval_mins[0]
|
|
644
|
+
latency = pending_le_connection.max_latencies[0]
|
|
645
|
+
timeout = pending_le_connection.supervision_timeouts[0]
|
|
646
|
+
else:
|
|
647
|
+
interval = pending_le_connection.connection_interval_min
|
|
648
|
+
latency = pending_le_connection.max_latency
|
|
649
|
+
timeout = pending_le_connection.supervision_timeout
|
|
650
|
+
|
|
651
|
+
self.send_advertising_pdu(
|
|
652
|
+
ll.ConnectInd(
|
|
653
|
+
initiator_address=self_address,
|
|
654
|
+
advertiser_address=peer_address,
|
|
655
|
+
interval=interval,
|
|
656
|
+
latency=latency,
|
|
657
|
+
timeout=timeout,
|
|
658
|
+
)
|
|
659
|
+
)
|
|
502
660
|
# Say that the connection has completed
|
|
503
661
|
self.send_hci_packet(
|
|
504
662
|
# pylint: disable=line-too-long
|
|
505
|
-
HCI_LE_Connection_Complete_Event(
|
|
506
|
-
status=
|
|
663
|
+
hci.HCI_LE_Connection_Complete_Event(
|
|
664
|
+
status=hci.HCI_SUCCESS,
|
|
507
665
|
connection_handle=connection.handle if connection else 0,
|
|
508
|
-
role=Role.CENTRAL,
|
|
509
|
-
peer_address_type=
|
|
510
|
-
peer_address=
|
|
511
|
-
connection_interval=
|
|
512
|
-
peripheral_latency=
|
|
513
|
-
supervision_timeout=
|
|
666
|
+
role=hci.Role.CENTRAL,
|
|
667
|
+
peer_address_type=peer_address.address_type,
|
|
668
|
+
peer_address=peer_address,
|
|
669
|
+
connection_interval=interval,
|
|
670
|
+
peripheral_latency=latency,
|
|
671
|
+
supervision_timeout=timeout,
|
|
514
672
|
central_clock_accuracy=0,
|
|
515
673
|
)
|
|
516
674
|
)
|
|
675
|
+
self.pending_le_connection = None
|
|
517
676
|
|
|
518
|
-
def
|
|
519
|
-
|
|
520
|
-
) -> None:
|
|
521
|
-
'''
|
|
522
|
-
Called when a disconnection has been completed
|
|
523
|
-
'''
|
|
524
|
-
|
|
525
|
-
# Send a disconnection complete event
|
|
677
|
+
def on_le_encrypted(self, connection: Connection) -> None:
|
|
678
|
+
# For now, just setup the encryption without asking the host
|
|
526
679
|
self.send_hci_packet(
|
|
527
|
-
|
|
528
|
-
status=
|
|
529
|
-
connection_handle=disconnection_command.connection_handle,
|
|
530
|
-
reason=disconnection_command.reason,
|
|
680
|
+
hci.HCI_Encryption_Change_Event(
|
|
681
|
+
status=0, connection_handle=connection.handle, encryption_enabled=1
|
|
531
682
|
)
|
|
532
683
|
)
|
|
533
684
|
|
|
534
|
-
# Remove the connection
|
|
535
|
-
if connection := self.find_central_connection_by_handle(
|
|
536
|
-
disconnection_command.connection_handle
|
|
537
|
-
):
|
|
538
|
-
logger.debug(f'CENTRAL Connection removed: {connection}')
|
|
539
|
-
del self.central_connections[connection.peer_address]
|
|
540
|
-
elif connection := self.find_peripheral_connection_by_handle(
|
|
541
|
-
disconnection_command.connection_handle
|
|
542
|
-
):
|
|
543
|
-
logger.debug(f'PERIPHERAL Connection removed: {connection}')
|
|
544
|
-
del self.peripheral_connections[connection.peer_address]
|
|
545
|
-
|
|
546
|
-
def on_link_encrypted(
|
|
547
|
-
self, peer_address: Address, _rand: int, _ediv: int, _ltk: bytes
|
|
548
|
-
) -> None:
|
|
549
|
-
# For now, just setup the encryption without asking the host
|
|
550
|
-
if connection := self.find_le_connection_by_address(peer_address):
|
|
551
|
-
self.send_hci_packet(
|
|
552
|
-
HCI_Encryption_Change_Event(
|
|
553
|
-
status=0, connection_handle=connection.handle, encryption_enabled=1
|
|
554
|
-
)
|
|
555
|
-
)
|
|
556
|
-
|
|
557
685
|
def on_link_acl_data(
|
|
558
|
-
self, sender_address: Address, transport: PhysicalTransport, data: bytes
|
|
686
|
+
self, sender_address: hci.Address, transport: PhysicalTransport, data: bytes
|
|
559
687
|
) -> None:
|
|
560
688
|
# Look for the connection to which this data belongs
|
|
561
689
|
if transport == PhysicalTransport.LE:
|
|
562
|
-
connection = self.
|
|
690
|
+
connection = self.le_connections.get(sender_address)
|
|
563
691
|
else:
|
|
564
|
-
connection = self.
|
|
692
|
+
connection = self.classic_connections.get(sender_address)
|
|
565
693
|
if connection is None:
|
|
566
694
|
logger.warning(f'!!! no connection for {sender_address}')
|
|
567
695
|
return
|
|
568
696
|
|
|
569
697
|
# Send the data to the host
|
|
570
698
|
# TODO: should fragment
|
|
571
|
-
acl_packet = HCI_AclDataPacket(connection.handle, 2, 0, len(data), data)
|
|
699
|
+
acl_packet = hci.HCI_AclDataPacket(connection.handle, 2, 0, len(data), data)
|
|
572
700
|
self.send_hci_packet(acl_packet)
|
|
573
701
|
|
|
574
|
-
def
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
702
|
+
def on_advertising_pdu(self, pdu: ll.AdvInd | ll.AdvExtInd) -> None:
|
|
703
|
+
if isinstance(pdu, ll.AdvExtInd):
|
|
704
|
+
direct_address = pdu.target_address
|
|
705
|
+
else:
|
|
706
|
+
direct_address = None
|
|
578
707
|
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
708
|
+
if self.le_scan_enable:
|
|
709
|
+
# Send a scan report
|
|
710
|
+
if self.le_features & hci.LeFeatureMask.LE_EXTENDED_ADVERTISING:
|
|
711
|
+
ext_report = hci.HCI_LE_Extended_Advertising_Report_Event.Report(
|
|
712
|
+
event_type=hci.HCI_LE_Extended_Advertising_Report_Event.EventType.CONNECTABLE_ADVERTISING,
|
|
713
|
+
address_type=pdu.advertiser_address.address_type,
|
|
714
|
+
address=pdu.advertiser_address,
|
|
715
|
+
primary_phy=hci.Phy.LE_1M,
|
|
716
|
+
secondary_phy=hci.Phy.LE_1M,
|
|
717
|
+
advertising_sid=0,
|
|
718
|
+
tx_power=0,
|
|
719
|
+
rssi=-50,
|
|
720
|
+
periodic_advertising_interval=0,
|
|
721
|
+
direct_address_type=(
|
|
722
|
+
direct_address.address_type if direct_address else 0
|
|
723
|
+
),
|
|
724
|
+
direct_address=direct_address or hci.Address.ANY,
|
|
725
|
+
data=pdu.data,
|
|
726
|
+
)
|
|
727
|
+
self.send_hci_packet(
|
|
728
|
+
hci.HCI_LE_Extended_Advertising_Report_Event([ext_report])
|
|
729
|
+
)
|
|
730
|
+
ext_report = hci.HCI_LE_Extended_Advertising_Report_Event.Report(
|
|
731
|
+
event_type=hci.HCI_LE_Extended_Advertising_Report_Event.EventType.SCAN_RESPONSE,
|
|
732
|
+
address_type=pdu.advertiser_address.address_type,
|
|
733
|
+
address=pdu.advertiser_address,
|
|
734
|
+
primary_phy=hci.Phy.LE_1M,
|
|
735
|
+
secondary_phy=hci.Phy.LE_1M,
|
|
736
|
+
advertising_sid=0,
|
|
737
|
+
tx_power=0,
|
|
738
|
+
rssi=-50,
|
|
739
|
+
periodic_advertising_interval=0,
|
|
740
|
+
direct_address_type=(
|
|
741
|
+
direct_address.address_type if direct_address else 0
|
|
742
|
+
),
|
|
743
|
+
direct_address=direct_address or hci.Address.ANY,
|
|
744
|
+
data=pdu.data,
|
|
745
|
+
)
|
|
746
|
+
self.send_hci_packet(
|
|
747
|
+
hci.HCI_LE_Extended_Advertising_Report_Event([ext_report])
|
|
748
|
+
)
|
|
749
|
+
else:
|
|
750
|
+
report = hci.HCI_LE_Advertising_Report_Event.Report(
|
|
751
|
+
event_type=hci.HCI_LE_Advertising_Report_Event.EventType.ADV_IND,
|
|
752
|
+
address_type=pdu.advertiser_address.address_type,
|
|
753
|
+
address=pdu.advertiser_address,
|
|
754
|
+
data=pdu.data,
|
|
755
|
+
rssi=-50,
|
|
756
|
+
)
|
|
757
|
+
self.send_hci_packet(hci.HCI_LE_Advertising_Report_Event([report]))
|
|
758
|
+
report = hci.HCI_LE_Advertising_Report_Event.Report(
|
|
759
|
+
event_type=hci.HCI_LE_Advertising_Report_Event.EventType.SCAN_RSP,
|
|
760
|
+
address_type=pdu.advertiser_address.address_type,
|
|
761
|
+
address=pdu.advertiser_address,
|
|
762
|
+
data=pdu.data,
|
|
763
|
+
rssi=-50,
|
|
764
|
+
)
|
|
765
|
+
self.send_hci_packet(hci.HCI_LE_Advertising_Report_Event([report]))
|
|
588
766
|
|
|
589
|
-
#
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
data=data,
|
|
595
|
-
rssi=-50,
|
|
596
|
-
)
|
|
597
|
-
self.send_hci_packet(HCI_LE_Advertising_Report_Event([report]))
|
|
767
|
+
# Create connection.
|
|
768
|
+
if (
|
|
769
|
+
pending_le_connection := self.pending_le_connection
|
|
770
|
+
) and pending_le_connection.peer_address == pdu.advertiser_address:
|
|
771
|
+
self.create_le_connection(pdu.advertiser_address)
|
|
598
772
|
|
|
599
|
-
def
|
|
600
|
-
self,
|
|
773
|
+
def on_le_cis_request(
|
|
774
|
+
self, connection: Connection, cig_id: int, cis_id: int
|
|
601
775
|
) -> None:
|
|
602
776
|
'''
|
|
603
777
|
Called when an incoming CIS request occurs from a central on the link
|
|
604
778
|
'''
|
|
605
|
-
|
|
606
|
-
connection = self.peripheral_connections.get(central_address)
|
|
607
|
-
assert connection
|
|
608
|
-
|
|
609
779
|
pending_cis_link = CisLink(
|
|
610
780
|
handle=self.allocate_connection_handle(),
|
|
611
781
|
cis_id=cis_id,
|
|
@@ -615,7 +785,7 @@ class Controller:
|
|
|
615
785
|
self.peripheral_cis_links[pending_cis_link.handle] = pending_cis_link
|
|
616
786
|
|
|
617
787
|
self.send_hci_packet(
|
|
618
|
-
HCI_LE_CIS_Request_Event(
|
|
788
|
+
hci.HCI_LE_CIS_Request_Event(
|
|
619
789
|
acl_connection_handle=connection.handle,
|
|
620
790
|
cis_connection_handle=pending_cis_link.handle,
|
|
621
791
|
cig_id=cig_id,
|
|
@@ -623,7 +793,7 @@ class Controller:
|
|
|
623
793
|
)
|
|
624
794
|
)
|
|
625
795
|
|
|
626
|
-
def
|
|
796
|
+
def on_le_cis_established(self, cig_id: int, cis_id: int) -> None:
|
|
627
797
|
'''
|
|
628
798
|
Called when an incoming CIS established.
|
|
629
799
|
'''
|
|
@@ -637,8 +807,8 @@ class Controller:
|
|
|
637
807
|
)
|
|
638
808
|
|
|
639
809
|
self.send_hci_packet(
|
|
640
|
-
HCI_LE_CIS_Established_Event(
|
|
641
|
-
status=HCI_SUCCESS,
|
|
810
|
+
hci.HCI_LE_CIS_Established_Event(
|
|
811
|
+
status=hci.HCI_SUCCESS,
|
|
642
812
|
connection_handle=cis_link.handle,
|
|
643
813
|
# CIS parameters are ignored.
|
|
644
814
|
cig_sync_delay=0,
|
|
@@ -658,7 +828,7 @@ class Controller:
|
|
|
658
828
|
)
|
|
659
829
|
)
|
|
660
830
|
|
|
661
|
-
def
|
|
831
|
+
def on_le_cis_disconnected(self, cig_id: int, cis_id: int) -> None:
|
|
662
832
|
'''
|
|
663
833
|
Called when a CIS disconnected.
|
|
664
834
|
'''
|
|
@@ -681,16 +851,16 @@ class Controller:
|
|
|
681
851
|
),
|
|
682
852
|
None,
|
|
683
853
|
):
|
|
684
|
-
# Keep central CIS on disconnection. They should be removed by HCI_LE_Remove_CIG_Command.
|
|
854
|
+
# Keep central CIS on disconnection. They should be removed by hci.HCI_LE_Remove_CIG_Command.
|
|
685
855
|
cis_link.acl_connection = None
|
|
686
856
|
else:
|
|
687
857
|
return
|
|
688
858
|
|
|
689
859
|
self.send_hci_packet(
|
|
690
|
-
HCI_Disconnection_Complete_Event(
|
|
691
|
-
status=HCI_SUCCESS,
|
|
860
|
+
hci.HCI_Disconnection_Complete_Event(
|
|
861
|
+
status=hci.HCI_SUCCESS,
|
|
692
862
|
connection_handle=cis_link.handle,
|
|
693
|
-
reason=HCI_REMOTE_USER_TERMINATED_CONNECTION_ERROR,
|
|
863
|
+
reason=hci.HCI_REMOTE_USER_TERMINATED_CONNECTION_ERROR,
|
|
694
864
|
)
|
|
695
865
|
)
|
|
696
866
|
|
|
@@ -698,11 +868,87 @@ class Controller:
|
|
|
698
868
|
# Classic link connections
|
|
699
869
|
############################################################
|
|
700
870
|
|
|
871
|
+
def send_lmp_packet(
|
|
872
|
+
self, receiver_address: hci.Address, packet: lmp.Packet
|
|
873
|
+
) -> asyncio.Future[int]:
|
|
874
|
+
loop = asyncio.get_running_loop()
|
|
875
|
+
assert self.link
|
|
876
|
+
self.link.send_lmp_packet(self, receiver_address, packet)
|
|
877
|
+
future = self.classic_pending_commands.setdefault(receiver_address, {})[
|
|
878
|
+
packet.opcode
|
|
879
|
+
] = loop.create_future()
|
|
880
|
+
return future
|
|
881
|
+
|
|
882
|
+
def on_lmp_packet(self, sender_address: hci.Address, packet: lmp.Packet):
|
|
883
|
+
if isinstance(packet, (lmp.LmpAccepted, lmp.LmpAcceptedExt)):
|
|
884
|
+
if future := self.classic_pending_commands.setdefault(
|
|
885
|
+
sender_address, {}
|
|
886
|
+
).get(packet.response_opcode):
|
|
887
|
+
future.set_result(hci.HCI_SUCCESS)
|
|
888
|
+
else:
|
|
889
|
+
logger.error("!!! Unhandled packet: %s", packet)
|
|
890
|
+
elif isinstance(packet, (lmp.LmpNotAccepted, lmp.LmpNotAcceptedExt)):
|
|
891
|
+
if future := self.classic_pending_commands.setdefault(
|
|
892
|
+
sender_address, {}
|
|
893
|
+
).get(packet.response_opcode):
|
|
894
|
+
future.set_result(packet.error_code)
|
|
895
|
+
else:
|
|
896
|
+
logger.error("!!! Unhandled packet: %s", packet)
|
|
897
|
+
elif isinstance(packet, (lmp.LmpHostConnectionReq)):
|
|
898
|
+
self.on_classic_connection_request(
|
|
899
|
+
sender_address, hci.HCI_Connection_Complete_Event.LinkType.ACL
|
|
900
|
+
)
|
|
901
|
+
elif isinstance(packet, (lmp.LmpScoLinkReq)):
|
|
902
|
+
self.on_classic_connection_request(
|
|
903
|
+
sender_address, hci.HCI_Connection_Complete_Event.LinkType.SCO
|
|
904
|
+
)
|
|
905
|
+
elif isinstance(packet, (lmp.LmpEscoLinkReq)):
|
|
906
|
+
self.on_classic_connection_request(
|
|
907
|
+
sender_address, hci.HCI_Connection_Complete_Event.LinkType.ESCO
|
|
908
|
+
)
|
|
909
|
+
elif isinstance(packet, (lmp.LmpDetach)):
|
|
910
|
+
self.on_classic_disconnected(
|
|
911
|
+
sender_address, hci.HCI_REMOTE_USER_TERMINATED_CONNECTION_ERROR
|
|
912
|
+
)
|
|
913
|
+
elif isinstance(packet, (lmp.LmpSwitchReq)):
|
|
914
|
+
self.on_classic_role_change_request(sender_address)
|
|
915
|
+
elif isinstance(packet, (lmp.LmpRemoveScoLinkReq, lmp.LmpRemoveEscoLinkReq)):
|
|
916
|
+
self.on_classic_sco_disconnected(sender_address, packet.error_code)
|
|
917
|
+
elif isinstance(packet, lmp.LmpNameReq):
|
|
918
|
+
self.on_classic_remote_name_request(sender_address, packet.name_offset)
|
|
919
|
+
elif isinstance(packet, lmp.LmpNameRes):
|
|
920
|
+
self.on_classic_remote_name_response(
|
|
921
|
+
sender_address,
|
|
922
|
+
packet.name_offset,
|
|
923
|
+
packet.name_length,
|
|
924
|
+
packet.name_fregment,
|
|
925
|
+
)
|
|
926
|
+
else:
|
|
927
|
+
logger.error("!!! Unhandled packet: %s", packet)
|
|
928
|
+
|
|
701
929
|
def on_classic_connection_request(
|
|
702
|
-
self, peer_address: Address, link_type: int
|
|
930
|
+
self, peer_address: hci.Address, link_type: int
|
|
703
931
|
) -> None:
|
|
932
|
+
if link_type == hci.HCI_Connection_Complete_Event.LinkType.ACL:
|
|
933
|
+
self.classic_connections[peer_address] = Connection(
|
|
934
|
+
controller=self,
|
|
935
|
+
handle=0,
|
|
936
|
+
role=hci.Role.PERIPHERAL,
|
|
937
|
+
self_address=self.public_address,
|
|
938
|
+
peer_address=peer_address,
|
|
939
|
+
link=self.link,
|
|
940
|
+
transport=PhysicalTransport.BR_EDR,
|
|
941
|
+
link_type=link_type,
|
|
942
|
+
classic_allow_role_switch=self.classic_allow_role_switch,
|
|
943
|
+
)
|
|
944
|
+
else:
|
|
945
|
+
self.sco_links[peer_address] = ScoLink(
|
|
946
|
+
handle=0,
|
|
947
|
+
link_type=link_type,
|
|
948
|
+
peer_address=peer_address,
|
|
949
|
+
)
|
|
704
950
|
self.send_hci_packet(
|
|
705
|
-
HCI_Connection_Request_Event(
|
|
951
|
+
hci.HCI_Connection_Request_Event(
|
|
706
952
|
bd_addr=peer_address,
|
|
707
953
|
class_of_device=0,
|
|
708
954
|
link_type=link_type,
|
|
@@ -710,99 +956,127 @@ class Controller:
|
|
|
710
956
|
)
|
|
711
957
|
|
|
712
958
|
def on_classic_connection_complete(
|
|
713
|
-
self, peer_address: Address, status: int
|
|
959
|
+
self, peer_address: hci.Address, status: int
|
|
714
960
|
) -> None:
|
|
715
|
-
if status == HCI_SUCCESS:
|
|
961
|
+
if status == hci.HCI_SUCCESS:
|
|
716
962
|
# Allocate (or reuse) a connection handle
|
|
717
963
|
peer_address = peer_address
|
|
718
|
-
|
|
719
|
-
if connection
|
|
720
|
-
|
|
964
|
+
connection_handle = self.allocate_connection_handle()
|
|
965
|
+
if connection := self.classic_connections.get(peer_address):
|
|
966
|
+
connection.handle = connection_handle
|
|
967
|
+
else:
|
|
721
968
|
connection = Connection(
|
|
722
969
|
controller=self,
|
|
723
970
|
handle=connection_handle,
|
|
724
|
-
|
|
725
|
-
|
|
971
|
+
role=hci.Role.CENTRAL,
|
|
972
|
+
self_address=self.public_address,
|
|
726
973
|
peer_address=peer_address,
|
|
727
974
|
link=self.link,
|
|
728
975
|
transport=PhysicalTransport.BR_EDR,
|
|
729
|
-
link_type=HCI_Connection_Complete_Event.LinkType.ACL,
|
|
976
|
+
link_type=hci.HCI_Connection_Complete_Event.LinkType.ACL,
|
|
730
977
|
)
|
|
731
978
|
self.classic_connections[peer_address] = connection
|
|
732
979
|
logger.debug(
|
|
733
980
|
f'New CLASSIC connection handle: 0x{connection_handle:04X}'
|
|
734
981
|
)
|
|
735
|
-
else:
|
|
736
|
-
connection_handle = connection.handle
|
|
737
982
|
self.send_hci_packet(
|
|
738
|
-
HCI_Connection_Complete_Event(
|
|
983
|
+
hci.HCI_Connection_Complete_Event(
|
|
739
984
|
status=status,
|
|
740
985
|
connection_handle=connection_handle,
|
|
741
986
|
bd_addr=peer_address,
|
|
742
987
|
encryption_enabled=False,
|
|
743
|
-
link_type=HCI_Connection_Complete_Event.LinkType.ACL,
|
|
988
|
+
link_type=hci.HCI_Connection_Complete_Event.LinkType.ACL,
|
|
744
989
|
)
|
|
745
990
|
)
|
|
746
991
|
else:
|
|
747
992
|
connection = None
|
|
748
993
|
self.send_hci_packet(
|
|
749
|
-
HCI_Connection_Complete_Event(
|
|
994
|
+
hci.HCI_Connection_Complete_Event(
|
|
750
995
|
status=status,
|
|
751
996
|
connection_handle=0,
|
|
752
997
|
bd_addr=peer_address,
|
|
753
998
|
encryption_enabled=False,
|
|
754
|
-
link_type=HCI_Connection_Complete_Event.LinkType.ACL,
|
|
999
|
+
link_type=hci.HCI_Connection_Complete_Event.LinkType.ACL,
|
|
755
1000
|
)
|
|
756
1001
|
)
|
|
757
1002
|
|
|
758
|
-
def on_classic_disconnected(self, peer_address: Address, reason: int) -> None:
|
|
1003
|
+
def on_classic_disconnected(self, peer_address: hci.Address, reason: int) -> None:
|
|
759
1004
|
# Send a disconnection complete event
|
|
760
|
-
if connection := self.classic_connections.
|
|
1005
|
+
if connection := self.classic_connections.pop(peer_address, None):
|
|
761
1006
|
self.send_hci_packet(
|
|
762
|
-
HCI_Disconnection_Complete_Event(
|
|
763
|
-
status=HCI_SUCCESS,
|
|
1007
|
+
hci.HCI_Disconnection_Complete_Event(
|
|
1008
|
+
status=hci.HCI_SUCCESS,
|
|
764
1009
|
connection_handle=connection.handle,
|
|
765
1010
|
reason=reason,
|
|
766
1011
|
)
|
|
767
1012
|
)
|
|
1013
|
+
else:
|
|
1014
|
+
logger.warning(f'!!! No classic connection found for {peer_address}')
|
|
768
1015
|
|
|
769
|
-
|
|
770
|
-
|
|
1016
|
+
def on_classic_sco_disconnected(
|
|
1017
|
+
self, peer_address: hci.Address, reason: int
|
|
1018
|
+
) -> None:
|
|
1019
|
+
# Send a disconnection complete event
|
|
1020
|
+
if sco_link := self.sco_links.pop(peer_address, None):
|
|
1021
|
+
self.send_hci_packet(
|
|
1022
|
+
hci.HCI_Disconnection_Complete_Event(
|
|
1023
|
+
status=hci.HCI_SUCCESS,
|
|
1024
|
+
connection_handle=sco_link.handle,
|
|
1025
|
+
reason=reason,
|
|
1026
|
+
)
|
|
1027
|
+
)
|
|
771
1028
|
else:
|
|
772
1029
|
logger.warning(f'!!! No classic connection found for {peer_address}')
|
|
773
1030
|
|
|
774
|
-
def
|
|
1031
|
+
def on_classic_role_change_request(self, peer_address: hci.Address) -> None:
|
|
1032
|
+
assert (connection := self.classic_connections.get(peer_address))
|
|
1033
|
+
if not connection.classic_allow_role_switch:
|
|
1034
|
+
self.send_lmp_packet(
|
|
1035
|
+
peer_address,
|
|
1036
|
+
lmp.LmpNotAccepted(
|
|
1037
|
+
lmp.Opcode.LMP_SWITCH_REQ, hci.HCI_ROLE_CHANGE_NOT_ALLOWED_ERROR
|
|
1038
|
+
),
|
|
1039
|
+
)
|
|
1040
|
+
else:
|
|
1041
|
+
self.send_lmp_packet(
|
|
1042
|
+
peer_address,
|
|
1043
|
+
lmp.LmpAccepted(lmp.Opcode.LMP_SWITCH_REQ),
|
|
1044
|
+
)
|
|
1045
|
+
self.classic_role_change(connection)
|
|
1046
|
+
|
|
1047
|
+
def classic_role_change(self, connection: Connection) -> None:
|
|
1048
|
+
new_role = (
|
|
1049
|
+
hci.Role.CENTRAL
|
|
1050
|
+
if connection.role == hci.Role.PERIPHERAL
|
|
1051
|
+
else hci.Role.PERIPHERAL
|
|
1052
|
+
)
|
|
1053
|
+
connection.role = new_role
|
|
775
1054
|
self.send_hci_packet(
|
|
776
|
-
HCI_Role_Change_Event(
|
|
777
|
-
status=HCI_SUCCESS,
|
|
778
|
-
bd_addr=peer_address,
|
|
1055
|
+
hci.HCI_Role_Change_Event(
|
|
1056
|
+
status=hci.HCI_SUCCESS,
|
|
1057
|
+
bd_addr=connection.peer_address,
|
|
779
1058
|
new_role=new_role,
|
|
780
1059
|
)
|
|
781
1060
|
)
|
|
782
1061
|
|
|
783
1062
|
def on_classic_sco_connection_complete(
|
|
784
|
-
self, peer_address: Address, status: int, link_type: int
|
|
1063
|
+
self, peer_address: hci.Address, status: int, link_type: int
|
|
785
1064
|
) -> None:
|
|
786
|
-
if status == HCI_SUCCESS:
|
|
1065
|
+
if status == hci.HCI_SUCCESS:
|
|
787
1066
|
# Allocate (or reuse) a connection handle
|
|
788
1067
|
connection_handle = self.allocate_connection_handle()
|
|
789
|
-
|
|
790
|
-
controller=self,
|
|
1068
|
+
sco_link = ScoLink(
|
|
791
1069
|
handle=connection_handle,
|
|
792
|
-
# Role doesn't matter in SCO.
|
|
793
|
-
role=Role.CENTRAL,
|
|
794
|
-
peer_address=peer_address,
|
|
795
|
-
link=self.link,
|
|
796
|
-
transport=PhysicalTransport.BR_EDR,
|
|
797
1070
|
link_type=link_type,
|
|
1071
|
+
peer_address=peer_address,
|
|
798
1072
|
)
|
|
799
|
-
self.
|
|
1073
|
+
self.sco_links[peer_address] = sco_link
|
|
800
1074
|
logger.debug(f'New SCO connection handle: 0x{connection_handle:04X}')
|
|
801
1075
|
else:
|
|
802
1076
|
connection_handle = 0
|
|
803
1077
|
|
|
804
1078
|
self.send_hci_packet(
|
|
805
|
-
HCI_Synchronous_Connection_Complete_Event(
|
|
1079
|
+
hci.HCI_Synchronous_Connection_Complete_Event(
|
|
806
1080
|
status=status,
|
|
807
1081
|
connection_handle=connection_handle,
|
|
808
1082
|
bd_addr=peer_address,
|
|
@@ -816,47 +1090,53 @@ class Controller:
|
|
|
816
1090
|
)
|
|
817
1091
|
)
|
|
818
1092
|
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
1093
|
+
def on_classic_remote_name_request(
|
|
1094
|
+
self, peer_address: hci.Address, name_offset: int
|
|
1095
|
+
):
|
|
1096
|
+
self.send_lmp_packet(
|
|
1097
|
+
peer_address,
|
|
1098
|
+
lmp.LmpNameRes(
|
|
1099
|
+
name_offset=name_offset,
|
|
1100
|
+
name_length=len(self.local_name),
|
|
1101
|
+
name_fregment=self.local_name.encode('utf-8'),
|
|
1102
|
+
),
|
|
826
1103
|
)
|
|
827
1104
|
|
|
828
|
-
def
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
1105
|
+
def on_classic_remote_name_response(
|
|
1106
|
+
self,
|
|
1107
|
+
peer_address: hci.Address,
|
|
1108
|
+
name_offset: int,
|
|
1109
|
+
name_length: int,
|
|
1110
|
+
name_fregment: bytes,
|
|
1111
|
+
):
|
|
1112
|
+
self.send_hci_packet(
|
|
1113
|
+
hci.HCI_Remote_Name_Request_Complete_Event(
|
|
1114
|
+
status=hci.HCI_SUCCESS,
|
|
1115
|
+
bd_addr=peer_address,
|
|
1116
|
+
remote_name=name_fregment,
|
|
1117
|
+
)
|
|
835
1118
|
)
|
|
836
1119
|
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
self.advertising_timer_handle = None
|
|
841
|
-
|
|
842
|
-
def send_advertising_data(self) -> None:
|
|
843
|
-
if self.link and self.advertising_data:
|
|
844
|
-
self.link.send_advertising_data(self.random_address, self.advertising_data)
|
|
1120
|
+
############################################################
|
|
1121
|
+
# Advertising support
|
|
1122
|
+
############################################################
|
|
845
1123
|
|
|
846
1124
|
@property
|
|
847
1125
|
def is_advertising(self) -> bool:
|
|
848
|
-
return self.
|
|
1126
|
+
return self.le_legacy_advertiser.enabled or any(
|
|
1127
|
+
s.enabled for s in self.advertising_sets.values()
|
|
1128
|
+
)
|
|
849
1129
|
|
|
850
1130
|
############################################################
|
|
851
1131
|
# HCI handlers
|
|
852
1132
|
############################################################
|
|
853
|
-
def on_hci_command(self, command: hci.HCI_Command) ->
|
|
1133
|
+
def on_hci_command(self, command: hci.HCI_Command) -> bytes | None:
|
|
854
1134
|
logger.warning(color(f'--- Unsupported command {command}', 'red'))
|
|
855
|
-
return bytes([HCI_UNKNOWN_HCI_COMMAND_ERROR])
|
|
1135
|
+
return bytes([hci.HCI_UNKNOWN_HCI_COMMAND_ERROR])
|
|
856
1136
|
|
|
857
1137
|
def on_hci_create_connection_command(
|
|
858
1138
|
self, command: hci.HCI_Create_Connection_Command
|
|
859
|
-
) ->
|
|
1139
|
+
) -> bytes | None:
|
|
860
1140
|
'''
|
|
861
1141
|
See Bluetooth spec Vol 4, Part E - 7.1.5 Create Connection command
|
|
862
1142
|
'''
|
|
@@ -866,38 +1146,54 @@ class Controller:
|
|
|
866
1146
|
logger.debug(f'Connection request to {command.bd_addr}')
|
|
867
1147
|
|
|
868
1148
|
# Check that we don't already have a pending connection
|
|
869
|
-
if self.
|
|
1149
|
+
if self.pending_le_connection:
|
|
870
1150
|
self.send_hci_packet(
|
|
871
|
-
HCI_Command_Status_Event(
|
|
872
|
-
status=HCI_CONTROLLER_BUSY_ERROR,
|
|
1151
|
+
hci.HCI_Command_Status_Event(
|
|
1152
|
+
status=hci.HCI_CONTROLLER_BUSY_ERROR,
|
|
873
1153
|
num_hci_command_packets=1,
|
|
874
1154
|
command_opcode=command.op_code,
|
|
875
1155
|
)
|
|
876
1156
|
)
|
|
877
1157
|
return None
|
|
878
1158
|
|
|
879
|
-
self.
|
|
1159
|
+
self.classic_connections[command.bd_addr] = Connection(
|
|
1160
|
+
controller=self,
|
|
1161
|
+
handle=0,
|
|
1162
|
+
role=hci.Role.CENTRAL,
|
|
1163
|
+
self_address=self.public_address,
|
|
1164
|
+
peer_address=command.bd_addr,
|
|
1165
|
+
link=self.link,
|
|
1166
|
+
transport=PhysicalTransport.BR_EDR,
|
|
1167
|
+
link_type=hci.HCI_Connection_Complete_Event.LinkType.ACL,
|
|
1168
|
+
classic_allow_role_switch=bool(command.allow_role_switch),
|
|
1169
|
+
)
|
|
880
1170
|
|
|
881
1171
|
# Say that the connection is pending
|
|
882
1172
|
self.send_hci_packet(
|
|
883
|
-
HCI_Command_Status_Event(
|
|
884
|
-
status=HCI_COMMAND_STATUS_PENDING,
|
|
1173
|
+
hci.HCI_Command_Status_Event(
|
|
1174
|
+
status=hci.HCI_COMMAND_STATUS_PENDING,
|
|
885
1175
|
num_hci_command_packets=1,
|
|
886
1176
|
command_opcode=command.op_code,
|
|
887
1177
|
)
|
|
888
1178
|
)
|
|
1179
|
+
future = self.send_lmp_packet(command.bd_addr, lmp.LmpHostConnectionReq())
|
|
1180
|
+
|
|
1181
|
+
def on_response(future: asyncio.Future[int]):
|
|
1182
|
+
self.on_classic_connection_complete(command.bd_addr, future.result())
|
|
1183
|
+
|
|
1184
|
+
future.add_done_callback(on_response)
|
|
889
1185
|
return None
|
|
890
1186
|
|
|
891
1187
|
def on_hci_disconnect_command(
|
|
892
1188
|
self, command: hci.HCI_Disconnect_Command
|
|
893
|
-
) ->
|
|
1189
|
+
) -> bytes | None:
|
|
894
1190
|
'''
|
|
895
1191
|
See Bluetooth spec Vol 4, Part E - 7.1.6 Disconnect Command
|
|
896
1192
|
'''
|
|
897
1193
|
# First, say that the disconnection is pending
|
|
898
1194
|
self.send_hci_packet(
|
|
899
|
-
HCI_Command_Status_Event(
|
|
900
|
-
status=HCI_COMMAND_STATUS_PENDING,
|
|
1195
|
+
hci.HCI_Command_Status_Event(
|
|
1196
|
+
status=hci.HCI_COMMAND_STATUS_PENDING,
|
|
901
1197
|
num_hci_command_packets=1,
|
|
902
1198
|
command_opcode=command.op_code,
|
|
903
1199
|
)
|
|
@@ -905,68 +1201,138 @@ class Controller:
|
|
|
905
1201
|
|
|
906
1202
|
# Notify the link of the disconnection
|
|
907
1203
|
handle = command.connection_handle
|
|
908
|
-
if connection := self.
|
|
909
|
-
if self.link:
|
|
910
|
-
self.link.disconnect(
|
|
911
|
-
self.random_address, connection.peer_address, command
|
|
912
|
-
)
|
|
913
|
-
else:
|
|
914
|
-
# Remove the connection
|
|
915
|
-
del self.central_connections[connection.peer_address]
|
|
916
|
-
elif connection := self.find_peripheral_connection_by_handle(handle):
|
|
1204
|
+
if connection := self.find_connection_by_handle(handle):
|
|
917
1205
|
if self.link:
|
|
918
|
-
|
|
919
|
-
self.
|
|
920
|
-
|
|
1206
|
+
if connection.transport == PhysicalTransport.BR_EDR:
|
|
1207
|
+
self.send_lmp_packet(
|
|
1208
|
+
connection.peer_address,
|
|
1209
|
+
lmp.LmpDetach(command.reason),
|
|
1210
|
+
)
|
|
1211
|
+
self.on_classic_disconnected(
|
|
1212
|
+
connection.peer_address, command.reason
|
|
1213
|
+
)
|
|
1214
|
+
else:
|
|
1215
|
+
connection.send_ll_control_pdu(ll.TerminateInd(command.reason))
|
|
1216
|
+
self.on_le_disconnected(connection, command.reason)
|
|
921
1217
|
else:
|
|
922
1218
|
# Remove the connection
|
|
923
|
-
del self.
|
|
924
|
-
elif
|
|
1219
|
+
del self.classic_connections[connection.peer_address]
|
|
1220
|
+
elif sco_link := self.find_classic_sco_link_by_handle(handle):
|
|
925
1221
|
if self.link:
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
1222
|
+
if (
|
|
1223
|
+
sco_link.link_type
|
|
1224
|
+
== hci.HCI_Connection_Complete_Event.LinkType.ESCO
|
|
1225
|
+
):
|
|
1226
|
+
self.send_lmp_packet(
|
|
1227
|
+
sco_link.peer_address,
|
|
1228
|
+
lmp.LmpRemoveScoLinkReq(
|
|
1229
|
+
sco_handle=0, error_code=command.reason
|
|
1230
|
+
),
|
|
1231
|
+
)
|
|
1232
|
+
else:
|
|
1233
|
+
self.send_lmp_packet(
|
|
1234
|
+
sco_link.peer_address,
|
|
1235
|
+
lmp.LmpRemoveEscoLinkReq(
|
|
1236
|
+
esco_handle=0, error_code=command.reason
|
|
1237
|
+
),
|
|
1238
|
+
)
|
|
1239
|
+
self.on_classic_sco_disconnected(sco_link.peer_address, command.reason)
|
|
931
1240
|
else:
|
|
932
1241
|
# Remove the connection
|
|
933
|
-
del self.
|
|
1242
|
+
del self.sco_links[sco_link.peer_address]
|
|
934
1243
|
elif cis_link := (
|
|
935
1244
|
self.central_cis_links.get(handle) or self.peripheral_cis_links.get(handle)
|
|
936
1245
|
):
|
|
937
1246
|
if self.link and cis_link.acl_connection:
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
cis_id=cis_link.cis_id,
|
|
1247
|
+
cis_link.acl_connection.send_ll_control_pdu(
|
|
1248
|
+
ll.CisTerminateInd(
|
|
1249
|
+
cis_link.cig_id, cis_link.cis_id, command.reason
|
|
1250
|
+
),
|
|
943
1251
|
)
|
|
1252
|
+
self.on_le_cis_disconnected(cis_link.cig_id, cis_link.cis_id)
|
|
944
1253
|
# Spec requires handle to be kept after disconnection.
|
|
945
1254
|
|
|
946
1255
|
return None
|
|
947
1256
|
|
|
948
1257
|
def on_hci_accept_connection_request_command(
|
|
949
1258
|
self, command: hci.HCI_Accept_Connection_Request_Command
|
|
950
|
-
) ->
|
|
1259
|
+
) -> bytes | None:
|
|
951
1260
|
'''
|
|
952
1261
|
See Bluetooth spec Vol 4, Part E - 7.1.8 Accept Connection Request command
|
|
953
1262
|
'''
|
|
954
1263
|
|
|
955
1264
|
if self.link is None:
|
|
956
1265
|
return None
|
|
1266
|
+
|
|
1267
|
+
if not (connection := self.classic_connections.get(command.bd_addr)):
|
|
1268
|
+
self.send_hci_packet(
|
|
1269
|
+
hci.HCI_Command_Status_Event(
|
|
1270
|
+
status=hci.HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR,
|
|
1271
|
+
num_hci_command_packets=1,
|
|
1272
|
+
command_opcode=command.op_code,
|
|
1273
|
+
)
|
|
1274
|
+
)
|
|
1275
|
+
return None
|
|
1276
|
+
self.send_hci_packet(
|
|
1277
|
+
hci.HCI_Command_Status_Event(
|
|
1278
|
+
status=hci.HCI_SUCCESS,
|
|
1279
|
+
num_hci_command_packets=1,
|
|
1280
|
+
command_opcode=command.op_code,
|
|
1281
|
+
)
|
|
1282
|
+
)
|
|
1283
|
+
|
|
1284
|
+
if command.role == hci.Role.CENTRAL:
|
|
1285
|
+
# Perform role switching before accept.
|
|
1286
|
+
future = self.send_lmp_packet(command.bd_addr, lmp.LmpSwitchReq())
|
|
1287
|
+
|
|
1288
|
+
def on_response(future: asyncio.Future[int]):
|
|
1289
|
+
if (status := future.result()) == hci.HCI_SUCCESS:
|
|
1290
|
+
self.classic_role_change(connection)
|
|
1291
|
+
# Continue connection setup.
|
|
1292
|
+
self.send_lmp_packet(
|
|
1293
|
+
command.bd_addr,
|
|
1294
|
+
lmp.LmpAccepted(lmp.Opcode.LMP_HOST_CONNECTION_REQ),
|
|
1295
|
+
)
|
|
1296
|
+
else:
|
|
1297
|
+
# Abort connection setup.
|
|
1298
|
+
self.send_lmp_packet(
|
|
1299
|
+
command.bd_addr,
|
|
1300
|
+
lmp.LmpNotAccepted(lmp.Opcode.LMP_HOST_CONNECTION_REQ, status),
|
|
1301
|
+
)
|
|
1302
|
+
self.on_classic_connection_complete(command.bd_addr, status)
|
|
1303
|
+
|
|
1304
|
+
future.add_done_callback(on_response)
|
|
1305
|
+
|
|
1306
|
+
else:
|
|
1307
|
+
# Simply accept connection.
|
|
1308
|
+
self.send_lmp_packet(
|
|
1309
|
+
command.bd_addr,
|
|
1310
|
+
lmp.LmpAccepted(lmp.Opcode.LMP_HOST_CONNECTION_REQ),
|
|
1311
|
+
)
|
|
1312
|
+
self.on_classic_connection_complete(command.bd_addr, hci.HCI_SUCCESS)
|
|
1313
|
+
return None
|
|
1314
|
+
|
|
1315
|
+
def on_hci_remote_name_request_command(
|
|
1316
|
+
self, command: hci.HCI_Remote_Name_Request_Command
|
|
1317
|
+
) -> bytes | None:
|
|
1318
|
+
'''
|
|
1319
|
+
See Bluetooth spec Vol 4, Part E - 7.1.19 Remote Name Request command
|
|
1320
|
+
'''
|
|
957
1321
|
self.send_hci_packet(
|
|
958
|
-
HCI_Command_Status_Event(
|
|
959
|
-
status=HCI_SUCCESS,
|
|
1322
|
+
hci.HCI_Command_Status_Event(
|
|
1323
|
+
status=hci.HCI_SUCCESS,
|
|
960
1324
|
num_hci_command_packets=1,
|
|
961
1325
|
command_opcode=command.op_code,
|
|
962
1326
|
)
|
|
963
1327
|
)
|
|
964
|
-
|
|
1328
|
+
|
|
1329
|
+
self.send_lmp_packet(command.bd_addr, lmp.LmpNameReq(0))
|
|
1330
|
+
|
|
965
1331
|
return None
|
|
966
1332
|
|
|
967
1333
|
def on_hci_enhanced_setup_synchronous_connection_command(
|
|
968
1334
|
self, command: hci.HCI_Enhanced_Setup_Synchronous_Connection_Command
|
|
969
|
-
) ->
|
|
1335
|
+
) -> bytes | None:
|
|
970
1336
|
'''
|
|
971
1337
|
See Bluetooth spec Vol 4, Part E - 7.1.45 Enhanced Setup Synchronous Connection command
|
|
972
1338
|
'''
|
|
@@ -975,13 +1341,11 @@ class Controller:
|
|
|
975
1341
|
return None
|
|
976
1342
|
|
|
977
1343
|
if not (
|
|
978
|
-
connection := self.
|
|
979
|
-
command.connection_handle
|
|
980
|
-
)
|
|
1344
|
+
connection := self.find_connection_by_handle(command.connection_handle)
|
|
981
1345
|
):
|
|
982
1346
|
self.send_hci_packet(
|
|
983
|
-
HCI_Command_Status_Event(
|
|
984
|
-
status=HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR,
|
|
1347
|
+
hci.HCI_Command_Status_Event(
|
|
1348
|
+
status=hci.HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR,
|
|
985
1349
|
num_hci_command_packets=1,
|
|
986
1350
|
command_opcode=command.op_code,
|
|
987
1351
|
)
|
|
@@ -989,20 +1353,43 @@ class Controller:
|
|
|
989
1353
|
return None
|
|
990
1354
|
|
|
991
1355
|
self.send_hci_packet(
|
|
992
|
-
HCI_Command_Status_Event(
|
|
993
|
-
status=HCI_SUCCESS,
|
|
1356
|
+
hci.HCI_Command_Status_Event(
|
|
1357
|
+
status=hci.HCI_SUCCESS,
|
|
994
1358
|
num_hci_command_packets=1,
|
|
995
1359
|
command_opcode=command.op_code,
|
|
996
1360
|
)
|
|
997
1361
|
)
|
|
998
|
-
self.
|
|
999
|
-
|
|
1362
|
+
future = self.send_lmp_packet(
|
|
1363
|
+
connection.peer_address,
|
|
1364
|
+
lmp.LmpEscoLinkReq(
|
|
1365
|
+
esco_handle=0,
|
|
1366
|
+
esco_lt_addr=0,
|
|
1367
|
+
timing_control_flags=0,
|
|
1368
|
+
d_esco=0,
|
|
1369
|
+
t_esco=0,
|
|
1370
|
+
w_esco=0,
|
|
1371
|
+
esco_packet_type_c_to_p=0,
|
|
1372
|
+
esco_packet_type_p_to_c=0,
|
|
1373
|
+
packet_length_c_to_p=0,
|
|
1374
|
+
packet_length_p_to_c=0,
|
|
1375
|
+
air_mode=0,
|
|
1376
|
+
negotiation_state=0,
|
|
1377
|
+
),
|
|
1000
1378
|
)
|
|
1379
|
+
|
|
1380
|
+
def on_response(future: asyncio.Future[int]):
|
|
1381
|
+
self.on_classic_sco_connection_complete(
|
|
1382
|
+
connection.peer_address,
|
|
1383
|
+
future.result(),
|
|
1384
|
+
hci.HCI_Connection_Complete_Event.LinkType.ESCO,
|
|
1385
|
+
)
|
|
1386
|
+
|
|
1387
|
+
future.add_done_callback(on_response)
|
|
1001
1388
|
return None
|
|
1002
1389
|
|
|
1003
1390
|
def on_hci_enhanced_accept_synchronous_connection_request_command(
|
|
1004
1391
|
self, command: hci.HCI_Enhanced_Accept_Synchronous_Connection_Request_Command
|
|
1005
|
-
) ->
|
|
1392
|
+
) -> bytes | None:
|
|
1006
1393
|
'''
|
|
1007
1394
|
See Bluetooth spec Vol 4, Part E - 7.1.46 Enhanced Accept Synchronous Connection Request command
|
|
1008
1395
|
'''
|
|
@@ -1010,10 +1397,10 @@ class Controller:
|
|
|
1010
1397
|
if self.link is None:
|
|
1011
1398
|
return None
|
|
1012
1399
|
|
|
1013
|
-
if not (connection := self.
|
|
1400
|
+
if not (connection := self.classic_connections.get(command.bd_addr)):
|
|
1014
1401
|
self.send_hci_packet(
|
|
1015
|
-
HCI_Command_Status_Event(
|
|
1016
|
-
status=HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR,
|
|
1402
|
+
hci.HCI_Command_Status_Event(
|
|
1403
|
+
status=hci.HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR,
|
|
1017
1404
|
num_hci_command_packets=1,
|
|
1018
1405
|
command_opcode=command.op_code,
|
|
1019
1406
|
)
|
|
@@ -1021,20 +1408,26 @@ class Controller:
|
|
|
1021
1408
|
return None
|
|
1022
1409
|
|
|
1023
1410
|
self.send_hci_packet(
|
|
1024
|
-
HCI_Command_Status_Event(
|
|
1025
|
-
status=HCI_SUCCESS,
|
|
1411
|
+
hci.HCI_Command_Status_Event(
|
|
1412
|
+
status=hci.HCI_SUCCESS,
|
|
1026
1413
|
num_hci_command_packets=1,
|
|
1027
1414
|
command_opcode=command.op_code,
|
|
1028
1415
|
)
|
|
1029
1416
|
)
|
|
1030
|
-
self.
|
|
1031
|
-
|
|
1417
|
+
self.send_lmp_packet(
|
|
1418
|
+
connection.peer_address,
|
|
1419
|
+
lmp.LmpAcceptedExt(lmp.Opcode.LMP_ESCO_LINK_REQ),
|
|
1420
|
+
)
|
|
1421
|
+
self.on_classic_sco_connection_complete(
|
|
1422
|
+
connection.peer_address,
|
|
1423
|
+
hci.HCI_SUCCESS,
|
|
1424
|
+
hci.HCI_Connection_Complete_Event.LinkType.ESCO,
|
|
1032
1425
|
)
|
|
1033
1426
|
return None
|
|
1034
1427
|
|
|
1035
1428
|
def on_hci_sniff_mode_command(
|
|
1036
1429
|
self, command: hci.HCI_Sniff_Mode_Command
|
|
1037
|
-
) ->
|
|
1430
|
+
) -> bytes | None:
|
|
1038
1431
|
'''
|
|
1039
1432
|
See Bluetooth spec Vol 4, Part E - 7.2.2 Sniff Mode command
|
|
1040
1433
|
'''
|
|
@@ -1050,14 +1443,14 @@ class Controller:
|
|
|
1050
1443
|
|
|
1051
1444
|
self.send_hci_packet(
|
|
1052
1445
|
hci.HCI_Command_Status_Event(
|
|
1053
|
-
status=HCI_SUCCESS,
|
|
1446
|
+
status=hci.HCI_SUCCESS,
|
|
1054
1447
|
num_hci_command_packets=1,
|
|
1055
1448
|
command_opcode=command.op_code,
|
|
1056
1449
|
)
|
|
1057
1450
|
)
|
|
1058
1451
|
self.send_hci_packet(
|
|
1059
1452
|
hci.HCI_Mode_Change_Event(
|
|
1060
|
-
status=HCI_SUCCESS,
|
|
1453
|
+
status=hci.HCI_SUCCESS,
|
|
1061
1454
|
connection_handle=command.connection_handle,
|
|
1062
1455
|
current_mode=hci.HCI_Mode_Change_Event.Mode.SNIFF,
|
|
1063
1456
|
interval=2,
|
|
@@ -1067,7 +1460,7 @@ class Controller:
|
|
|
1067
1460
|
|
|
1068
1461
|
def on_hci_exit_sniff_mode_command(
|
|
1069
1462
|
self, command: hci.HCI_Exit_Sniff_Mode_Command
|
|
1070
|
-
) ->
|
|
1463
|
+
) -> bytes | None:
|
|
1071
1464
|
'''
|
|
1072
1465
|
See Bluetooth spec Vol 4, Part E - 7.2.3 Exit Sniff Mode command
|
|
1073
1466
|
'''
|
|
@@ -1084,14 +1477,14 @@ class Controller:
|
|
|
1084
1477
|
|
|
1085
1478
|
self.send_hci_packet(
|
|
1086
1479
|
hci.HCI_Command_Status_Event(
|
|
1087
|
-
status=HCI_SUCCESS,
|
|
1480
|
+
status=hci.HCI_SUCCESS,
|
|
1088
1481
|
num_hci_command_packets=1,
|
|
1089
1482
|
command_opcode=command.op_code,
|
|
1090
1483
|
)
|
|
1091
1484
|
)
|
|
1092
1485
|
self.send_hci_packet(
|
|
1093
1486
|
hci.HCI_Mode_Change_Event(
|
|
1094
|
-
status=HCI_SUCCESS,
|
|
1487
|
+
status=hci.HCI_SUCCESS,
|
|
1095
1488
|
connection_handle=command.connection_handle,
|
|
1096
1489
|
current_mode=hci.HCI_Mode_Change_Event.Mode.ACTIVE,
|
|
1097
1490
|
interval=2,
|
|
@@ -1101,44 +1494,82 @@ class Controller:
|
|
|
1101
1494
|
|
|
1102
1495
|
def on_hci_switch_role_command(
|
|
1103
1496
|
self, command: hci.HCI_Switch_Role_Command
|
|
1104
|
-
) ->
|
|
1497
|
+
) -> bytes | None:
|
|
1105
1498
|
'''
|
|
1106
|
-
See Bluetooth spec Vol 4, Part E - 7.2.8 Switch Role command
|
|
1499
|
+
See Bluetooth spec Vol 4, Part E - 7.2.8 Switch hci.Role command
|
|
1107
1500
|
'''
|
|
1108
1501
|
|
|
1109
1502
|
if self.link is None:
|
|
1110
1503
|
return None
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1504
|
+
|
|
1505
|
+
if connection := self.classic_connections.get(command.bd_addr):
|
|
1506
|
+
current_role = connection.role
|
|
1507
|
+
self.send_hci_packet(
|
|
1508
|
+
hci.HCI_Command_Status_Event(
|
|
1509
|
+
status=hci.HCI_SUCCESS,
|
|
1510
|
+
num_hci_command_packets=1,
|
|
1511
|
+
command_opcode=command.op_code,
|
|
1512
|
+
)
|
|
1116
1513
|
)
|
|
1117
|
-
|
|
1118
|
-
|
|
1514
|
+
else:
|
|
1515
|
+
# Connection doesn't exist, reject.
|
|
1516
|
+
self.send_hci_packet(
|
|
1517
|
+
hci.HCI_Command_Status_Event(
|
|
1518
|
+
status=hci.HCI_COMMAND_DISALLOWED_ERROR,
|
|
1519
|
+
num_hci_command_packets=1,
|
|
1520
|
+
command_opcode=command.op_code,
|
|
1521
|
+
)
|
|
1522
|
+
)
|
|
1523
|
+
return None
|
|
1524
|
+
|
|
1525
|
+
# If role doesn't change, only send event to local host.
|
|
1526
|
+
if current_role == command.role:
|
|
1527
|
+
self.send_hci_packet(
|
|
1528
|
+
hci.HCI_Role_Change_Event(
|
|
1529
|
+
status=hci.HCI_SUCCESS,
|
|
1530
|
+
bd_addr=command.bd_addr,
|
|
1531
|
+
new_role=current_role,
|
|
1532
|
+
)
|
|
1533
|
+
)
|
|
1534
|
+
else:
|
|
1535
|
+
future = self.send_lmp_packet(command.bd_addr, lmp.LmpSwitchReq())
|
|
1536
|
+
|
|
1537
|
+
def on_response(future: asyncio.Future[int]):
|
|
1538
|
+
if (status := future.result()) == hci.HCI_SUCCESS:
|
|
1539
|
+
connection.role = hci.Role(command.role)
|
|
1540
|
+
self.send_hci_packet(
|
|
1541
|
+
hci.HCI_Role_Change_Event(
|
|
1542
|
+
status=status,
|
|
1543
|
+
bd_addr=command.bd_addr,
|
|
1544
|
+
new_role=connection.role,
|
|
1545
|
+
)
|
|
1546
|
+
)
|
|
1547
|
+
|
|
1548
|
+
future.add_done_callback(on_response)
|
|
1549
|
+
|
|
1119
1550
|
return None
|
|
1120
1551
|
|
|
1121
1552
|
def on_hci_set_event_mask_command(
|
|
1122
1553
|
self, command: hci.HCI_Set_Event_Mask_Command
|
|
1123
|
-
) ->
|
|
1554
|
+
) -> bytes | None:
|
|
1124
1555
|
'''
|
|
1125
1556
|
See Bluetooth spec Vol 4, Part E - 7.3.1 Set Event Mask Command
|
|
1126
1557
|
'''
|
|
1127
1558
|
self.event_mask = int.from_bytes(
|
|
1128
1559
|
command.event_mask, byteorder='little', signed=False
|
|
1129
1560
|
)
|
|
1130
|
-
return bytes([HCI_SUCCESS])
|
|
1561
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1131
1562
|
|
|
1132
|
-
def on_hci_reset_command(self, _command: hci.HCI_Reset_Command) ->
|
|
1563
|
+
def on_hci_reset_command(self, _command: hci.HCI_Reset_Command) -> bytes | None:
|
|
1133
1564
|
'''
|
|
1134
1565
|
See Bluetooth spec Vol 4, Part E - 7.3.2 Reset Command
|
|
1135
1566
|
'''
|
|
1136
1567
|
# TODO: cleanup what needs to be reset
|
|
1137
|
-
return bytes([HCI_SUCCESS])
|
|
1568
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1138
1569
|
|
|
1139
1570
|
def on_hci_write_local_name_command(
|
|
1140
1571
|
self, command: hci.HCI_Write_Local_Name_Command
|
|
1141
|
-
) ->
|
|
1572
|
+
) -> bytes | None:
|
|
1142
1573
|
'''
|
|
1143
1574
|
See Bluetooth spec Vol 4, Part E - 7.3.11 Write Local Name Command
|
|
1144
1575
|
'''
|
|
@@ -1151,11 +1582,11 @@ class Controller:
|
|
|
1151
1582
|
self.local_name = str(local_name, 'utf-8')
|
|
1152
1583
|
except UnicodeDecodeError:
|
|
1153
1584
|
pass
|
|
1154
|
-
return bytes([HCI_SUCCESS])
|
|
1585
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1155
1586
|
|
|
1156
1587
|
def on_hci_read_local_name_command(
|
|
1157
1588
|
self, _command: hci.HCI_Read_Local_Name_Command
|
|
1158
|
-
) ->
|
|
1589
|
+
) -> bytes | None:
|
|
1159
1590
|
'''
|
|
1160
1591
|
See Bluetooth spec Vol 4, Part E - 7.3.12 Read Local Name Command
|
|
1161
1592
|
'''
|
|
@@ -1163,27 +1594,27 @@ class Controller:
|
|
|
1163
1594
|
if len(local_name) < 248:
|
|
1164
1595
|
local_name = local_name + bytes(248 - len(local_name))
|
|
1165
1596
|
|
|
1166
|
-
return bytes([HCI_SUCCESS]) + local_name
|
|
1597
|
+
return bytes([hci.HCI_SUCCESS]) + local_name
|
|
1167
1598
|
|
|
1168
1599
|
def on_hci_read_class_of_device_command(
|
|
1169
1600
|
self, _command: hci.HCI_Read_Class_Of_Device_Command
|
|
1170
|
-
) ->
|
|
1601
|
+
) -> bytes | None:
|
|
1171
1602
|
'''
|
|
1172
1603
|
See Bluetooth spec Vol 4, Part E - 7.3.25 Read Class of Device Command
|
|
1173
1604
|
'''
|
|
1174
|
-
return bytes([HCI_SUCCESS, 0, 0, 0])
|
|
1605
|
+
return bytes([hci.HCI_SUCCESS, 0, 0, 0])
|
|
1175
1606
|
|
|
1176
1607
|
def on_hci_write_class_of_device_command(
|
|
1177
1608
|
self, _command: hci.HCI_Write_Class_Of_Device_Command
|
|
1178
|
-
) ->
|
|
1609
|
+
) -> bytes | None:
|
|
1179
1610
|
'''
|
|
1180
1611
|
See Bluetooth spec Vol 4, Part E - 7.3.26 Write Class of Device Command
|
|
1181
1612
|
'''
|
|
1182
|
-
return bytes([HCI_SUCCESS])
|
|
1613
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1183
1614
|
|
|
1184
1615
|
def on_hci_read_synchronous_flow_control_enable_command(
|
|
1185
1616
|
self, _command: hci.HCI_Read_Synchronous_Flow_Control_Enable_Command
|
|
1186
|
-
) ->
|
|
1617
|
+
) -> bytes | None:
|
|
1187
1618
|
'''
|
|
1188
1619
|
See Bluetooth spec Vol 4, Part E - 7.3.36 Read Synchronous Flow Control Enable
|
|
1189
1620
|
Command
|
|
@@ -1192,109 +1623,109 @@ class Controller:
|
|
|
1192
1623
|
ret = 1
|
|
1193
1624
|
else:
|
|
1194
1625
|
ret = 0
|
|
1195
|
-
return bytes([HCI_SUCCESS, ret])
|
|
1626
|
+
return bytes([hci.HCI_SUCCESS, ret])
|
|
1196
1627
|
|
|
1197
1628
|
def on_hci_write_synchronous_flow_control_enable_command(
|
|
1198
1629
|
self, command: hci.HCI_Write_Synchronous_Flow_Control_Enable_Command
|
|
1199
|
-
) ->
|
|
1630
|
+
) -> bytes | None:
|
|
1200
1631
|
'''
|
|
1201
1632
|
See Bluetooth spec Vol 4, Part E - 7.3.37 Write Synchronous Flow Control Enable
|
|
1202
1633
|
Command
|
|
1203
1634
|
'''
|
|
1204
|
-
ret = HCI_SUCCESS
|
|
1635
|
+
ret = hci.HCI_SUCCESS
|
|
1205
1636
|
if command.synchronous_flow_control_enable == 1:
|
|
1206
1637
|
self.sync_flow_control = True
|
|
1207
1638
|
elif command.synchronous_flow_control_enable == 0:
|
|
1208
1639
|
self.sync_flow_control = False
|
|
1209
1640
|
else:
|
|
1210
|
-
ret = HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR
|
|
1641
|
+
ret = hci.HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR
|
|
1211
1642
|
return bytes([ret])
|
|
1212
1643
|
|
|
1213
1644
|
def on_hci_set_controller_to_host_flow_control_command(
|
|
1214
1645
|
self, _command: hci.HCI_Set_Controller_To_Host_Flow_Control_Command
|
|
1215
|
-
) ->
|
|
1646
|
+
) -> bytes | None:
|
|
1216
1647
|
'''
|
|
1217
1648
|
See Bluetooth spec Vol 4, Part E - 7.3.38 Set Controller To Host Flow Control
|
|
1218
1649
|
Command
|
|
1219
1650
|
'''
|
|
1220
1651
|
# For now we just accept the command but ignore the values.
|
|
1221
1652
|
# TODO: respect the passed in values.
|
|
1222
|
-
return bytes([HCI_SUCCESS])
|
|
1653
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1223
1654
|
|
|
1224
1655
|
def on_hci_host_buffer_size_command(
|
|
1225
1656
|
self, _command: hci.HCI_Host_Buffer_Size_Command
|
|
1226
|
-
) ->
|
|
1657
|
+
) -> bytes | None:
|
|
1227
1658
|
'''
|
|
1228
1659
|
See Bluetooth spec Vol 4, Part E - 7.3.39 Host Buffer Size Command
|
|
1229
1660
|
'''
|
|
1230
1661
|
# For now we just accept the command but ignore the values.
|
|
1231
1662
|
# TODO: respect the passed in values.
|
|
1232
|
-
return bytes([HCI_SUCCESS])
|
|
1663
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1233
1664
|
|
|
1234
1665
|
def on_hci_write_extended_inquiry_response_command(
|
|
1235
1666
|
self, _command: hci.HCI_Write_Extended_Inquiry_Response_Command
|
|
1236
|
-
) ->
|
|
1667
|
+
) -> bytes | None:
|
|
1237
1668
|
'''
|
|
1238
1669
|
See Bluetooth spec Vol 4, Part E - 7.3.56 Write Extended Inquiry Response
|
|
1239
1670
|
Command
|
|
1240
1671
|
'''
|
|
1241
|
-
return bytes([HCI_SUCCESS])
|
|
1672
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1242
1673
|
|
|
1243
1674
|
def on_hci_write_simple_pairing_mode_command(
|
|
1244
1675
|
self, _command: hci.HCI_Write_Simple_Pairing_Mode_Command
|
|
1245
|
-
) ->
|
|
1676
|
+
) -> bytes | None:
|
|
1246
1677
|
'''
|
|
1247
1678
|
See Bluetooth spec Vol 4, Part E - 7.3.59 Write Simple Pairing Mode Command
|
|
1248
1679
|
'''
|
|
1249
|
-
return bytes([HCI_SUCCESS])
|
|
1680
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1250
1681
|
|
|
1251
1682
|
def on_hci_set_event_mask_page_2_command(
|
|
1252
1683
|
self, command: hci.HCI_Set_Event_Mask_Page_2_Command
|
|
1253
|
-
) ->
|
|
1684
|
+
) -> bytes | None:
|
|
1254
1685
|
'''
|
|
1255
1686
|
See Bluetooth spec Vol 4, Part E - 7.3.69 Set Event Mask Page 2 Command
|
|
1256
1687
|
'''
|
|
1257
1688
|
self.event_mask_page_2 = int.from_bytes(
|
|
1258
1689
|
command.event_mask_page_2, byteorder='little', signed=False
|
|
1259
1690
|
)
|
|
1260
|
-
return bytes([HCI_SUCCESS])
|
|
1691
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1261
1692
|
|
|
1262
1693
|
def on_hci_read_le_host_support_command(
|
|
1263
1694
|
self, _command: hci.HCI_Read_LE_Host_Support_Command
|
|
1264
|
-
) ->
|
|
1695
|
+
) -> bytes | None:
|
|
1265
1696
|
'''
|
|
1266
1697
|
See Bluetooth spec Vol 4, Part E - 7.3.78 Write LE Host Support Command
|
|
1267
1698
|
'''
|
|
1268
|
-
return bytes([HCI_SUCCESS, 1, 0])
|
|
1699
|
+
return bytes([hci.HCI_SUCCESS, 1, 0])
|
|
1269
1700
|
|
|
1270
1701
|
def on_hci_write_le_host_support_command(
|
|
1271
1702
|
self, _command: hci.HCI_Write_LE_Host_Support_Command
|
|
1272
|
-
) ->
|
|
1703
|
+
) -> bytes | None:
|
|
1273
1704
|
'''
|
|
1274
1705
|
See Bluetooth spec Vol 4, Part E - 7.3.79 Write LE Host Support Command
|
|
1275
1706
|
'''
|
|
1276
1707
|
# TODO / Just ignore for now
|
|
1277
|
-
return bytes([HCI_SUCCESS])
|
|
1708
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1278
1709
|
|
|
1279
1710
|
def on_hci_write_authenticated_payload_timeout_command(
|
|
1280
1711
|
self, command: hci.HCI_Write_Authenticated_Payload_Timeout_Command
|
|
1281
|
-
) ->
|
|
1712
|
+
) -> bytes | None:
|
|
1282
1713
|
'''
|
|
1283
1714
|
See Bluetooth spec Vol 4, Part E - 7.3.94 Write Authenticated Payload Timeout
|
|
1284
1715
|
Command
|
|
1285
1716
|
'''
|
|
1286
1717
|
# TODO
|
|
1287
|
-
return struct.pack('<BH', HCI_SUCCESS, command.connection_handle)
|
|
1718
|
+
return struct.pack('<BH', hci.HCI_SUCCESS, command.connection_handle)
|
|
1288
1719
|
|
|
1289
1720
|
def on_hci_read_local_version_information_command(
|
|
1290
1721
|
self, _command: hci.HCI_Read_Local_Version_Information_Command
|
|
1291
|
-
) ->
|
|
1722
|
+
) -> bytes | None:
|
|
1292
1723
|
'''
|
|
1293
1724
|
See Bluetooth spec Vol 4, Part E - 7.4.1 Read Local Version Information Command
|
|
1294
1725
|
'''
|
|
1295
1726
|
return struct.pack(
|
|
1296
1727
|
'<BBHBHH',
|
|
1297
|
-
HCI_SUCCESS,
|
|
1728
|
+
hci.HCI_SUCCESS,
|
|
1298
1729
|
self.hci_version,
|
|
1299
1730
|
self.hci_revision,
|
|
1300
1731
|
self.lmp_version,
|
|
@@ -1304,33 +1735,33 @@ class Controller:
|
|
|
1304
1735
|
|
|
1305
1736
|
def on_hci_read_local_supported_commands_command(
|
|
1306
1737
|
self, _command: hci.HCI_Read_Local_Supported_Commands_Command
|
|
1307
|
-
) ->
|
|
1738
|
+
) -> bytes | None:
|
|
1308
1739
|
'''
|
|
1309
1740
|
See Bluetooth spec Vol 4, Part E - 7.4.2 Read Local Supported Commands Command
|
|
1310
1741
|
'''
|
|
1311
|
-
return bytes([HCI_SUCCESS]) + self.supported_commands
|
|
1742
|
+
return bytes([hci.HCI_SUCCESS]) + self.supported_commands
|
|
1312
1743
|
|
|
1313
1744
|
def on_hci_read_local_supported_features_command(
|
|
1314
1745
|
self, _command: hci.HCI_Read_Local_Supported_Features_Command
|
|
1315
|
-
) ->
|
|
1746
|
+
) -> bytes | None:
|
|
1316
1747
|
'''
|
|
1317
1748
|
See Bluetooth spec Vol 4, Part E - 7.4.3 Read Local Supported Features Command
|
|
1318
1749
|
'''
|
|
1319
|
-
return bytes([HCI_SUCCESS]) + self.lmp_features[:8]
|
|
1750
|
+
return bytes([hci.HCI_SUCCESS]) + self.lmp_features[:8]
|
|
1320
1751
|
|
|
1321
1752
|
def on_hci_read_local_extended_features_command(
|
|
1322
1753
|
self, command: hci.HCI_Read_Local_Extended_Features_Command
|
|
1323
|
-
) ->
|
|
1754
|
+
) -> bytes | None:
|
|
1324
1755
|
'''
|
|
1325
1756
|
See Bluetooth spec Vol 4, Part E - 7.4.4 Read Local Extended Features Command
|
|
1326
1757
|
'''
|
|
1327
1758
|
if command.page_number * 8 > len(self.lmp_features):
|
|
1328
|
-
return bytes([HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
|
|
1759
|
+
return bytes([hci.HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
|
|
1329
1760
|
return (
|
|
1330
1761
|
bytes(
|
|
1331
1762
|
[
|
|
1332
1763
|
# Status
|
|
1333
|
-
HCI_SUCCESS,
|
|
1764
|
+
hci.HCI_SUCCESS,
|
|
1334
1765
|
# Page number
|
|
1335
1766
|
command.page_number,
|
|
1336
1767
|
# Max page number
|
|
@@ -1343,13 +1774,13 @@ class Controller:
|
|
|
1343
1774
|
|
|
1344
1775
|
def on_hci_read_buffer_size_command(
|
|
1345
1776
|
self, _command: hci.HCI_Read_Buffer_Size_Command
|
|
1346
|
-
) ->
|
|
1777
|
+
) -> bytes | None:
|
|
1347
1778
|
'''
|
|
1348
1779
|
See Bluetooth spec Vol 4, Part E - 7.4.5 Read Buffer Size Command
|
|
1349
1780
|
'''
|
|
1350
1781
|
return struct.pack(
|
|
1351
1782
|
'<BHBHH',
|
|
1352
|
-
HCI_SUCCESS,
|
|
1783
|
+
hci.HCI_SUCCESS,
|
|
1353
1784
|
self.acl_data_packet_length,
|
|
1354
1785
|
0,
|
|
1355
1786
|
self.total_num_acl_data_packets,
|
|
@@ -1358,7 +1789,7 @@ class Controller:
|
|
|
1358
1789
|
|
|
1359
1790
|
def on_hci_read_bd_addr_command(
|
|
1360
1791
|
self, _command: hci.HCI_Read_BD_ADDR_Command
|
|
1361
|
-
) ->
|
|
1792
|
+
) -> bytes | None:
|
|
1362
1793
|
'''
|
|
1363
1794
|
See Bluetooth spec Vol 4, Part E - 7.4.6 Read BD_ADDR Command
|
|
1364
1795
|
'''
|
|
@@ -1367,11 +1798,11 @@ class Controller:
|
|
|
1367
1798
|
if self._public_address is not None
|
|
1368
1799
|
else bytes(6)
|
|
1369
1800
|
)
|
|
1370
|
-
return bytes([HCI_SUCCESS]) + bd_addr
|
|
1801
|
+
return bytes([hci.HCI_SUCCESS]) + bd_addr
|
|
1371
1802
|
|
|
1372
1803
|
def on_hci_le_set_default_subrate_command(
|
|
1373
1804
|
self, command: hci.HCI_LE_Set_Default_Subrate_Command
|
|
1374
|
-
) ->
|
|
1805
|
+
) -> bytes | None:
|
|
1375
1806
|
'''
|
|
1376
1807
|
See Bluetooth spec Vol 6, Part E - 7.8.123 LE Set Event Mask Command
|
|
1377
1808
|
'''
|
|
@@ -1381,13 +1812,13 @@ class Controller:
|
|
|
1381
1812
|
or command.subrate_max < command.subrate_min
|
|
1382
1813
|
or command.continuation_number >= command.subrate_max
|
|
1383
1814
|
):
|
|
1384
|
-
return bytes([HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
|
|
1815
|
+
return bytes([hci.HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
|
|
1385
1816
|
|
|
1386
|
-
return bytes([HCI_SUCCESS])
|
|
1817
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1387
1818
|
|
|
1388
1819
|
def on_hci_le_subrate_request_command(
|
|
1389
1820
|
self, command: hci.HCI_LE_Subrate_Request_Command
|
|
1390
|
-
) ->
|
|
1821
|
+
) -> bytes | None:
|
|
1391
1822
|
'''
|
|
1392
1823
|
See Bluetooth spec Vol 6, Part E - 7.8.124 LE Subrate Request command
|
|
1393
1824
|
'''
|
|
@@ -1397,7 +1828,7 @@ class Controller:
|
|
|
1397
1828
|
or command.subrate_max < command.subrate_min
|
|
1398
1829
|
or command.continuation_number >= command.subrate_max
|
|
1399
1830
|
):
|
|
1400
|
-
return bytes([HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
|
|
1831
|
+
return bytes([hci.HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
|
|
1401
1832
|
|
|
1402
1833
|
self.send_hci_packet(
|
|
1403
1834
|
hci.HCI_Command_Status_Event(
|
|
@@ -1421,37 +1852,37 @@ class Controller:
|
|
|
1421
1852
|
|
|
1422
1853
|
def on_hci_le_set_event_mask_command(
|
|
1423
1854
|
self, command: hci.HCI_LE_Set_Event_Mask_Command
|
|
1424
|
-
) ->
|
|
1855
|
+
) -> bytes | None:
|
|
1425
1856
|
'''
|
|
1426
1857
|
See Bluetooth spec Vol 4, Part E - 7.8.1 LE Set Event Mask Command
|
|
1427
1858
|
'''
|
|
1428
1859
|
self.le_event_mask = int.from_bytes(
|
|
1429
1860
|
command.le_event_mask, byteorder='little', signed=False
|
|
1430
1861
|
)
|
|
1431
|
-
return bytes([HCI_SUCCESS])
|
|
1862
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1432
1863
|
|
|
1433
1864
|
def on_hci_le_read_buffer_size_command(
|
|
1434
1865
|
self, _command: hci.HCI_LE_Read_Buffer_Size_Command
|
|
1435
|
-
) ->
|
|
1866
|
+
) -> bytes | None:
|
|
1436
1867
|
'''
|
|
1437
1868
|
See Bluetooth spec Vol 4, Part E - 7.8.2 LE Read Buffer Size Command
|
|
1438
1869
|
'''
|
|
1439
1870
|
return struct.pack(
|
|
1440
1871
|
'<BHB',
|
|
1441
|
-
HCI_SUCCESS,
|
|
1872
|
+
hci.HCI_SUCCESS,
|
|
1442
1873
|
self.le_acl_data_packet_length,
|
|
1443
1874
|
self.total_num_le_acl_data_packets,
|
|
1444
1875
|
)
|
|
1445
1876
|
|
|
1446
1877
|
def on_hci_le_read_buffer_size_v2_command(
|
|
1447
1878
|
self, _command: hci.HCI_LE_Read_Buffer_Size_V2_Command
|
|
1448
|
-
) ->
|
|
1879
|
+
) -> bytes | None:
|
|
1449
1880
|
'''
|
|
1450
1881
|
See Bluetooth spec Vol 4, Part E - 7.8.2 LE Read Buffer Size Command
|
|
1451
1882
|
'''
|
|
1452
1883
|
return struct.pack(
|
|
1453
1884
|
'<BHBHB',
|
|
1454
|
-
HCI_SUCCESS,
|
|
1885
|
+
hci.HCI_SUCCESS,
|
|
1455
1886
|
self.le_acl_data_packet_length,
|
|
1456
1887
|
self.total_num_le_acl_data_packets,
|
|
1457
1888
|
self.iso_data_packet_length,
|
|
@@ -1460,100 +1891,116 @@ class Controller:
|
|
|
1460
1891
|
|
|
1461
1892
|
def on_hci_le_read_local_supported_features_command(
|
|
1462
1893
|
self, _command: hci.HCI_LE_Read_Local_Supported_Features_Command
|
|
1463
|
-
) ->
|
|
1894
|
+
) -> bytes | None:
|
|
1464
1895
|
'''
|
|
1465
1896
|
See Bluetooth spec Vol 4, Part E - 7.8.3 LE Read Local Supported Features
|
|
1466
1897
|
Command
|
|
1467
1898
|
'''
|
|
1468
|
-
return bytes([HCI_SUCCESS]) + self.le_features
|
|
1899
|
+
return bytes([hci.HCI_SUCCESS]) + self.le_features.value.to_bytes(8, 'little')
|
|
1469
1900
|
|
|
1470
1901
|
def on_hci_le_set_random_address_command(
|
|
1471
1902
|
self, command: hci.HCI_LE_Set_Random_Address_Command
|
|
1472
|
-
) ->
|
|
1903
|
+
) -> bytes | None:
|
|
1473
1904
|
'''
|
|
1474
|
-
See Bluetooth spec Vol 4, Part E - 7.8.4 LE Set Random Address Command
|
|
1905
|
+
See Bluetooth spec Vol 4, Part E - 7.8.4 LE Set Random hci.Address Command
|
|
1475
1906
|
'''
|
|
1476
1907
|
self.random_address = command.random_address
|
|
1477
|
-
return bytes([HCI_SUCCESS])
|
|
1908
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1478
1909
|
|
|
1479
1910
|
def on_hci_le_set_advertising_parameters_command(
|
|
1480
1911
|
self, command: hci.HCI_LE_Set_Advertising_Parameters_Command
|
|
1481
|
-
) ->
|
|
1912
|
+
) -> bytes | None:
|
|
1482
1913
|
'''
|
|
1483
1914
|
See Bluetooth spec Vol 4, Part E - 7.8.5 LE Set Advertising Parameters Command
|
|
1484
1915
|
'''
|
|
1485
|
-
self.
|
|
1486
|
-
|
|
1916
|
+
self.le_legacy_advertiser.advertising_interval_min = (
|
|
1917
|
+
command.advertising_interval_min
|
|
1918
|
+
)
|
|
1919
|
+
self.le_legacy_advertiser.advertising_interval_max = (
|
|
1920
|
+
command.advertising_interval_max
|
|
1921
|
+
)
|
|
1922
|
+
self.le_legacy_advertiser.advertising_type = command.advertising_type
|
|
1923
|
+
self.le_legacy_advertiser.own_address_type = command.own_address_type
|
|
1924
|
+
self.le_legacy_advertiser.peer_address_type = command.peer_address_type
|
|
1925
|
+
self.le_legacy_advertiser.peer_address = command.peer_address
|
|
1926
|
+
self.le_legacy_advertiser.advertising_channel_map = (
|
|
1927
|
+
command.advertising_channel_map
|
|
1928
|
+
)
|
|
1929
|
+
self.le_legacy_advertiser.advertising_filter_policy = (
|
|
1930
|
+
command.advertising_filter_policy
|
|
1931
|
+
)
|
|
1932
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1487
1933
|
|
|
1488
1934
|
def on_hci_le_read_advertising_physical_channel_tx_power_command(
|
|
1489
1935
|
self, _command: hci.HCI_LE_Read_Advertising_Physical_Channel_Tx_Power_Command
|
|
1490
|
-
) ->
|
|
1936
|
+
) -> bytes | None:
|
|
1491
1937
|
'''
|
|
1492
1938
|
See Bluetooth spec Vol 4, Part E - 7.8.6 LE Read Advertising Physical Channel
|
|
1493
1939
|
Tx Power Command
|
|
1494
1940
|
'''
|
|
1495
|
-
return bytes([HCI_SUCCESS, self.advertising_channel_tx_power])
|
|
1941
|
+
return bytes([hci.HCI_SUCCESS, self.advertising_channel_tx_power])
|
|
1496
1942
|
|
|
1497
1943
|
def on_hci_le_set_advertising_data_command(
|
|
1498
1944
|
self, command: hci.HCI_LE_Set_Advertising_Data_Command
|
|
1499
|
-
) ->
|
|
1945
|
+
) -> bytes | None:
|
|
1500
1946
|
'''
|
|
1501
1947
|
See Bluetooth spec Vol 4, Part E - 7.8.7 LE Set Advertising Data Command
|
|
1502
1948
|
'''
|
|
1503
|
-
self.advertising_data = command.advertising_data
|
|
1504
|
-
|
|
1949
|
+
self.le_legacy_advertiser.advertising_data = command.advertising_data
|
|
1950
|
+
|
|
1951
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1505
1952
|
|
|
1506
1953
|
def on_hci_le_set_scan_response_data_command(
|
|
1507
1954
|
self, command: hci.HCI_LE_Set_Scan_Response_Data_Command
|
|
1508
|
-
) ->
|
|
1955
|
+
) -> bytes | None:
|
|
1509
1956
|
'''
|
|
1510
1957
|
See Bluetooth spec Vol 4, Part E - 7.8.8 LE Set Scan Response Data Command
|
|
1511
1958
|
'''
|
|
1512
|
-
self.
|
|
1513
|
-
return bytes([HCI_SUCCESS])
|
|
1959
|
+
self.le_legacy_advertiser.scan_response_data = command.scan_response_data
|
|
1960
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1514
1961
|
|
|
1515
1962
|
def on_hci_le_set_advertising_enable_command(
|
|
1516
1963
|
self, command: hci.HCI_LE_Set_Advertising_Enable_Command
|
|
1517
|
-
) ->
|
|
1964
|
+
) -> bytes | None:
|
|
1518
1965
|
'''
|
|
1519
1966
|
See Bluetooth spec Vol 4, Part E - 7.8.9 LE Set Advertising Enable Command
|
|
1520
1967
|
'''
|
|
1521
1968
|
if command.advertising_enable:
|
|
1522
|
-
self.
|
|
1969
|
+
self.le_legacy_advertiser.start()
|
|
1523
1970
|
else:
|
|
1524
|
-
self.
|
|
1971
|
+
self.le_legacy_advertiser.stop()
|
|
1525
1972
|
|
|
1526
|
-
return bytes([HCI_SUCCESS])
|
|
1973
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1527
1974
|
|
|
1528
1975
|
def on_hci_le_set_scan_parameters_command(
|
|
1529
1976
|
self, command: hci.HCI_LE_Set_Scan_Parameters_Command
|
|
1530
|
-
) ->
|
|
1977
|
+
) -> bytes | None:
|
|
1531
1978
|
'''
|
|
1532
1979
|
See Bluetooth spec Vol 4, Part E - 7.8.10 LE Set Scan Parameters Command
|
|
1533
1980
|
'''
|
|
1534
1981
|
if self.le_scan_enable:
|
|
1535
|
-
return bytes([HCI_COMMAND_DISALLOWED_ERROR])
|
|
1982
|
+
return bytes([hci.HCI_COMMAND_DISALLOWED_ERROR])
|
|
1536
1983
|
|
|
1537
1984
|
self.le_scan_type = command.le_scan_type
|
|
1538
1985
|
self.le_scan_interval = command.le_scan_interval
|
|
1539
1986
|
self.le_scan_window = command.le_scan_window
|
|
1540
1987
|
self.le_scan_own_address_type = hci.AddressType(command.own_address_type)
|
|
1541
1988
|
self.le_scanning_filter_policy = command.scanning_filter_policy
|
|
1542
|
-
return bytes([HCI_SUCCESS])
|
|
1989
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1543
1990
|
|
|
1544
1991
|
def on_hci_le_set_scan_enable_command(
|
|
1545
1992
|
self, command: hci.HCI_LE_Set_Scan_Enable_Command
|
|
1546
|
-
) ->
|
|
1993
|
+
) -> bytes | None:
|
|
1547
1994
|
'''
|
|
1548
1995
|
See Bluetooth spec Vol 4, Part E - 7.8.11 LE Set Scan Enable Command
|
|
1549
1996
|
'''
|
|
1550
1997
|
self.le_scan_enable = bool(command.le_scan_enable)
|
|
1551
1998
|
self.filter_duplicates = bool(command.filter_duplicates)
|
|
1552
|
-
return bytes([HCI_SUCCESS])
|
|
1999
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1553
2000
|
|
|
1554
2001
|
def on_hci_le_create_connection_command(
|
|
1555
2002
|
self, command: hci.HCI_LE_Create_Connection_Command
|
|
1556
|
-
) ->
|
|
2003
|
+
) -> bytes | None:
|
|
1557
2004
|
'''
|
|
1558
2005
|
See Bluetooth spec Vol 4, Part E - 7.8.12 LE Create Connection Command
|
|
1559
2006
|
'''
|
|
@@ -1564,23 +2011,22 @@ class Controller:
|
|
|
1564
2011
|
logger.debug(f'Connection request to {command.peer_address}')
|
|
1565
2012
|
|
|
1566
2013
|
# Check that we don't already have a pending connection
|
|
1567
|
-
if self.
|
|
2014
|
+
if self.pending_le_connection:
|
|
1568
2015
|
self.send_hci_packet(
|
|
1569
|
-
HCI_Command_Status_Event(
|
|
1570
|
-
status=HCI_COMMAND_DISALLOWED_ERROR,
|
|
2016
|
+
hci.HCI_Command_Status_Event(
|
|
2017
|
+
status=hci.HCI_COMMAND_DISALLOWED_ERROR,
|
|
1571
2018
|
num_hci_command_packets=1,
|
|
1572
2019
|
command_opcode=command.op_code,
|
|
1573
2020
|
)
|
|
1574
2021
|
)
|
|
1575
2022
|
return None
|
|
1576
2023
|
|
|
1577
|
-
|
|
1578
|
-
self.link.connect(self.random_address, command)
|
|
2024
|
+
self.pending_le_connection = command
|
|
1579
2025
|
|
|
1580
2026
|
# Say that the connection is pending
|
|
1581
2027
|
self.send_hci_packet(
|
|
1582
|
-
HCI_Command_Status_Event(
|
|
1583
|
-
status=HCI_COMMAND_STATUS_PENDING,
|
|
2028
|
+
hci.HCI_Command_Status_Event(
|
|
2029
|
+
status=hci.HCI_COMMAND_STATUS_PENDING,
|
|
1584
2030
|
num_hci_command_packets=1,
|
|
1585
2031
|
command_opcode=command.op_code,
|
|
1586
2032
|
)
|
|
@@ -1589,50 +2035,90 @@ class Controller:
|
|
|
1589
2035
|
|
|
1590
2036
|
def on_hci_le_create_connection_cancel_command(
|
|
1591
2037
|
self, _command: hci.HCI_LE_Create_Connection_Cancel_Command
|
|
1592
|
-
) ->
|
|
2038
|
+
) -> bytes | None:
|
|
1593
2039
|
'''
|
|
1594
2040
|
See Bluetooth spec Vol 4, Part E - 7.8.13 LE Create Connection Cancel Command
|
|
1595
2041
|
'''
|
|
1596
|
-
return bytes([HCI_SUCCESS])
|
|
2042
|
+
return bytes([hci.HCI_SUCCESS])
|
|
2043
|
+
|
|
2044
|
+
def on_hci_le_extended_create_connection_command(
|
|
2045
|
+
self, command: hci.HCI_LE_Extended_Create_Connection_Command
|
|
2046
|
+
) -> bytes | None:
|
|
2047
|
+
'''
|
|
2048
|
+
See Bluetooth spec Vol 4, Part E - 7.8.66 LE Extended Create Connection Command
|
|
2049
|
+
'''
|
|
2050
|
+
if not self.link:
|
|
2051
|
+
return None
|
|
2052
|
+
|
|
2053
|
+
# Check pending
|
|
2054
|
+
if self.pending_le_connection:
|
|
2055
|
+
self.send_hci_packet(
|
|
2056
|
+
hci.HCI_Command_Status_Event(
|
|
2057
|
+
status=hci.HCI_COMMAND_DISALLOWED_ERROR,
|
|
2058
|
+
num_hci_command_packets=1,
|
|
2059
|
+
command_opcode=command.op_code,
|
|
2060
|
+
)
|
|
2061
|
+
)
|
|
2062
|
+
return None
|
|
2063
|
+
|
|
2064
|
+
self.pending_le_connection = command
|
|
2065
|
+
|
|
2066
|
+
self.send_hci_packet(
|
|
2067
|
+
hci.HCI_Command_Status_Event(
|
|
2068
|
+
status=hci.HCI_COMMAND_STATUS_PENDING,
|
|
2069
|
+
num_hci_command_packets=1,
|
|
2070
|
+
command_opcode=command.op_code,
|
|
2071
|
+
)
|
|
2072
|
+
)
|
|
2073
|
+
return None
|
|
1597
2074
|
|
|
1598
2075
|
def on_hci_le_read_filter_accept_list_size_command(
|
|
1599
2076
|
self, _command: hci.HCI_LE_Read_Filter_Accept_List_Size_Command
|
|
1600
|
-
) ->
|
|
2077
|
+
) -> bytes | None:
|
|
1601
2078
|
'''
|
|
1602
2079
|
See Bluetooth spec Vol 4, Part E - 7.8.14 LE Read Filter Accept List Size
|
|
1603
2080
|
Command
|
|
1604
2081
|
'''
|
|
1605
|
-
return bytes([HCI_SUCCESS, self.filter_accept_list_size])
|
|
2082
|
+
return bytes([hci.HCI_SUCCESS, self.filter_accept_list_size])
|
|
1606
2083
|
|
|
1607
2084
|
def on_hci_le_clear_filter_accept_list_command(
|
|
1608
2085
|
self, _command: hci.HCI_LE_Clear_Filter_Accept_List_Command
|
|
1609
|
-
) ->
|
|
2086
|
+
) -> bytes | None:
|
|
1610
2087
|
'''
|
|
1611
2088
|
See Bluetooth spec Vol 4, Part E - 7.8.15 LE Clear Filter Accept List Command
|
|
1612
2089
|
'''
|
|
1613
|
-
return bytes([HCI_SUCCESS])
|
|
2090
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1614
2091
|
|
|
1615
2092
|
def on_hci_le_add_device_to_filter_accept_list_command(
|
|
1616
2093
|
self, _command: hci.HCI_LE_Add_Device_To_Filter_Accept_List_Command
|
|
1617
|
-
) ->
|
|
2094
|
+
) -> bytes | None:
|
|
1618
2095
|
'''
|
|
1619
2096
|
See Bluetooth spec Vol 4, Part E - 7.8.16 LE Add Device To Filter Accept List
|
|
1620
2097
|
Command
|
|
1621
2098
|
'''
|
|
1622
|
-
return bytes([HCI_SUCCESS])
|
|
2099
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1623
2100
|
|
|
1624
2101
|
def on_hci_le_remove_device_from_filter_accept_list_command(
|
|
1625
2102
|
self, _command: hci.HCI_LE_Remove_Device_From_Filter_Accept_List_Command
|
|
1626
|
-
) ->
|
|
2103
|
+
) -> bytes | None:
|
|
1627
2104
|
'''
|
|
1628
2105
|
See Bluetooth spec Vol 4, Part E - 7.8.17 LE Remove Device From Filter Accept
|
|
1629
2106
|
List Command
|
|
1630
2107
|
'''
|
|
1631
|
-
return bytes([HCI_SUCCESS])
|
|
2108
|
+
return bytes([hci.HCI_SUCCESS])
|
|
2109
|
+
|
|
2110
|
+
def on_hci_write_scan_enable_command(
|
|
2111
|
+
self, command: hci.HCI_Write_Scan_Enable_Command
|
|
2112
|
+
) -> bytes | None:
|
|
2113
|
+
'''
|
|
2114
|
+
See Bluetooth spec Vol 4, Part E - 7.3.18 Write Scan Enable Command
|
|
2115
|
+
'''
|
|
2116
|
+
self.classic_scan_enable = command.scan_enable
|
|
2117
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1632
2118
|
|
|
1633
2119
|
def on_hci_le_read_remote_features_command(
|
|
1634
2120
|
self, command: hci.HCI_LE_Read_Remote_Features_Command
|
|
1635
|
-
) ->
|
|
2121
|
+
) -> bytes | None:
|
|
1636
2122
|
'''
|
|
1637
2123
|
See Bluetooth spec Vol 4, Part E - 7.8.21 LE Read Remote Features Command
|
|
1638
2124
|
'''
|
|
@@ -1641,8 +2127,8 @@ class Controller:
|
|
|
1641
2127
|
|
|
1642
2128
|
if not self.find_connection_by_handle(handle):
|
|
1643
2129
|
self.send_hci_packet(
|
|
1644
|
-
HCI_Command_Status_Event(
|
|
1645
|
-
status=HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR,
|
|
2130
|
+
hci.HCI_Command_Status_Event(
|
|
2131
|
+
status=hci.HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR,
|
|
1646
2132
|
num_hci_command_packets=1,
|
|
1647
2133
|
command_opcode=command.op_code,
|
|
1648
2134
|
)
|
|
@@ -1651,8 +2137,8 @@ class Controller:
|
|
|
1651
2137
|
|
|
1652
2138
|
# First, say that the command is pending
|
|
1653
2139
|
self.send_hci_packet(
|
|
1654
|
-
HCI_Command_Status_Event(
|
|
1655
|
-
status=HCI_COMMAND_STATUS_PENDING,
|
|
2140
|
+
hci.HCI_Command_Status_Event(
|
|
2141
|
+
status=hci.HCI_COMMAND_STATUS_PENDING,
|
|
1656
2142
|
num_hci_command_packets=1,
|
|
1657
2143
|
command_opcode=command.op_code,
|
|
1658
2144
|
)
|
|
@@ -1660,25 +2146,23 @@ class Controller:
|
|
|
1660
2146
|
|
|
1661
2147
|
# Then send the remote features
|
|
1662
2148
|
self.send_hci_packet(
|
|
1663
|
-
HCI_LE_Read_Remote_Features_Complete_Event(
|
|
1664
|
-
status=HCI_SUCCESS,
|
|
2149
|
+
hci.HCI_LE_Read_Remote_Features_Complete_Event(
|
|
2150
|
+
status=hci.HCI_SUCCESS,
|
|
1665
2151
|
connection_handle=handle,
|
|
1666
2152
|
le_features=bytes.fromhex('dd40000000000000'),
|
|
1667
2153
|
)
|
|
1668
2154
|
)
|
|
1669
2155
|
return None
|
|
1670
2156
|
|
|
1671
|
-
def on_hci_le_rand_command(
|
|
1672
|
-
self, _command: hci.HCI_LE_Rand_Command
|
|
1673
|
-
) -> Optional[bytes]:
|
|
2157
|
+
def on_hci_le_rand_command(self, _command: hci.HCI_LE_Rand_Command) -> bytes | None:
|
|
1674
2158
|
'''
|
|
1675
2159
|
See Bluetooth spec Vol 4, Part E - 7.8.23 LE Rand Command
|
|
1676
2160
|
'''
|
|
1677
|
-
return bytes([HCI_SUCCESS]) + struct.pack('Q', random.randint(0, 1 << 64))
|
|
2161
|
+
return bytes([hci.HCI_SUCCESS]) + struct.pack('Q', random.randint(0, 1 << 64))
|
|
1678
2162
|
|
|
1679
2163
|
def on_hci_le_enable_encryption_command(
|
|
1680
2164
|
self, command: hci.HCI_LE_Enable_Encryption_Command
|
|
1681
|
-
) ->
|
|
2165
|
+
) -> bytes | None:
|
|
1682
2166
|
'''
|
|
1683
2167
|
See Bluetooth spec Vol 4, Part E - 7.8.24 LE Enable Encryption Command
|
|
1684
2168
|
'''
|
|
@@ -1686,58 +2170,61 @@ class Controller:
|
|
|
1686
2170
|
return None
|
|
1687
2171
|
|
|
1688
2172
|
# Check the parameters
|
|
1689
|
-
if
|
|
1690
|
-
|
|
1691
|
-
command.connection_handle
|
|
2173
|
+
if (
|
|
2174
|
+
not (
|
|
2175
|
+
connection := self.find_connection_by_handle(command.connection_handle)
|
|
1692
2176
|
)
|
|
2177
|
+
or connection.transport != PhysicalTransport.LE
|
|
1693
2178
|
):
|
|
1694
2179
|
logger.warning('connection not found')
|
|
1695
|
-
return bytes([HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
|
|
2180
|
+
return bytes([hci.HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
|
|
1696
2181
|
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
command.long_term_key,
|
|
2182
|
+
connection.send_ll_control_pdu(
|
|
2183
|
+
ll.EncReq(
|
|
2184
|
+
rand=command.random_number,
|
|
2185
|
+
ediv=command.encrypted_diversifier,
|
|
2186
|
+
ltk=command.long_term_key,
|
|
2187
|
+
),
|
|
1704
2188
|
)
|
|
1705
2189
|
|
|
1706
2190
|
self.send_hci_packet(
|
|
1707
|
-
HCI_Command_Status_Event(
|
|
1708
|
-
status=HCI_COMMAND_STATUS_PENDING,
|
|
2191
|
+
hci.HCI_Command_Status_Event(
|
|
2192
|
+
status=hci.HCI_COMMAND_STATUS_PENDING,
|
|
1709
2193
|
num_hci_command_packets=1,
|
|
1710
2194
|
command_opcode=command.op_code,
|
|
1711
2195
|
)
|
|
1712
2196
|
)
|
|
1713
2197
|
|
|
2198
|
+
# TODO: Handle authentication
|
|
2199
|
+
self.on_le_encrypted(connection)
|
|
2200
|
+
|
|
1714
2201
|
return None
|
|
1715
2202
|
|
|
1716
2203
|
def on_hci_le_read_supported_states_command(
|
|
1717
2204
|
self, _command: hci.HCI_LE_Read_Supported_States_Command
|
|
1718
|
-
) ->
|
|
2205
|
+
) -> bytes | None:
|
|
1719
2206
|
'''
|
|
1720
2207
|
See Bluetooth spec Vol 4, Part E - 7.8.27 LE Read Supported States Command
|
|
1721
2208
|
'''
|
|
1722
|
-
return bytes([HCI_SUCCESS]) + self.le_states
|
|
2209
|
+
return bytes([hci.HCI_SUCCESS]) + self.le_states
|
|
1723
2210
|
|
|
1724
2211
|
def on_hci_le_read_suggested_default_data_length_command(
|
|
1725
2212
|
self, _command: hci.HCI_LE_Read_Suggested_Default_Data_Length_Command
|
|
1726
|
-
) ->
|
|
2213
|
+
) -> bytes | None:
|
|
1727
2214
|
'''
|
|
1728
2215
|
See Bluetooth spec Vol 4, Part E - 7.8.34 LE Read Suggested Default Data Length
|
|
1729
2216
|
Command
|
|
1730
2217
|
'''
|
|
1731
2218
|
return struct.pack(
|
|
1732
2219
|
'<BHH',
|
|
1733
|
-
HCI_SUCCESS,
|
|
2220
|
+
hci.HCI_SUCCESS,
|
|
1734
2221
|
self.suggested_max_tx_octets,
|
|
1735
2222
|
self.suggested_max_tx_time,
|
|
1736
2223
|
)
|
|
1737
2224
|
|
|
1738
2225
|
def on_hci_le_write_suggested_default_data_length_command(
|
|
1739
2226
|
self, command: hci.HCI_LE_Write_Suggested_Default_Data_Length_Command
|
|
1740
|
-
) ->
|
|
2227
|
+
) -> bytes | None:
|
|
1741
2228
|
'''
|
|
1742
2229
|
See Bluetooth spec Vol 4, Part E - 7.8.35 LE Write Suggested Default Data Length
|
|
1743
2230
|
Command
|
|
@@ -1745,77 +2232,77 @@ class Controller:
|
|
|
1745
2232
|
self.suggested_max_tx_octets, self.suggested_max_tx_time = struct.unpack(
|
|
1746
2233
|
'<HH', command.parameters[:4]
|
|
1747
2234
|
)
|
|
1748
|
-
return bytes([HCI_SUCCESS])
|
|
2235
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1749
2236
|
|
|
1750
2237
|
def on_hci_le_read_local_p_256_public_key_command(
|
|
1751
2238
|
self, _command: hci.HCI_LE_Read_Local_P_256_Public_Key_Command
|
|
1752
|
-
) ->
|
|
2239
|
+
) -> bytes | None:
|
|
1753
2240
|
'''
|
|
1754
2241
|
See Bluetooth spec Vol 4, Part E - 7.8.36 LE Read P-256 Public Key Command
|
|
1755
2242
|
'''
|
|
1756
|
-
# TODO create key and send HCI_LE_Read_Local_P-256_Public_Key_Complete event
|
|
1757
|
-
return bytes([HCI_SUCCESS])
|
|
2243
|
+
# TODO create key and send hci.HCI_LE_Read_Local_P-256_Public_Key_Complete event
|
|
2244
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1758
2245
|
|
|
1759
2246
|
def on_hci_le_add_device_to_resolving_list_command(
|
|
1760
2247
|
self, _command: hci.HCI_LE_Add_Device_To_Resolving_List_Command
|
|
1761
|
-
) ->
|
|
2248
|
+
) -> bytes | None:
|
|
1762
2249
|
'''
|
|
1763
2250
|
See Bluetooth spec Vol 4, Part E - 7.8.38 LE Add Device To Resolving List
|
|
1764
2251
|
Command
|
|
1765
2252
|
'''
|
|
1766
|
-
return bytes([HCI_SUCCESS])
|
|
2253
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1767
2254
|
|
|
1768
2255
|
def on_hci_le_clear_resolving_list_command(
|
|
1769
2256
|
self, _command: hci.HCI_LE_Clear_Resolving_List_Command
|
|
1770
|
-
) ->
|
|
2257
|
+
) -> bytes | None:
|
|
1771
2258
|
'''
|
|
1772
2259
|
See Bluetooth spec Vol 4, Part E - 7.8.40 LE Clear Resolving List Command
|
|
1773
2260
|
'''
|
|
1774
|
-
return bytes([HCI_SUCCESS])
|
|
2261
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1775
2262
|
|
|
1776
2263
|
def on_hci_le_read_resolving_list_size_command(
|
|
1777
2264
|
self, _command: hci.HCI_LE_Read_Resolving_List_Size_Command
|
|
1778
|
-
) ->
|
|
2265
|
+
) -> bytes | None:
|
|
1779
2266
|
'''
|
|
1780
2267
|
See Bluetooth spec Vol 4, Part E - 7.8.41 LE Read Resolving List Size Command
|
|
1781
2268
|
'''
|
|
1782
|
-
return bytes([HCI_SUCCESS, self.resolving_list_size])
|
|
2269
|
+
return bytes([hci.HCI_SUCCESS, self.resolving_list_size])
|
|
1783
2270
|
|
|
1784
2271
|
def on_hci_le_set_address_resolution_enable_command(
|
|
1785
2272
|
self, command: hci.HCI_LE_Set_Address_Resolution_Enable_Command
|
|
1786
|
-
) ->
|
|
2273
|
+
) -> bytes | None:
|
|
1787
2274
|
'''
|
|
1788
|
-
See Bluetooth spec Vol 4, Part E - 7.8.44 LE Set Address Resolution Enable
|
|
2275
|
+
See Bluetooth spec Vol 4, Part E - 7.8.44 LE Set hci.Address Resolution Enable
|
|
1789
2276
|
Command
|
|
1790
2277
|
'''
|
|
1791
|
-
ret = HCI_SUCCESS
|
|
2278
|
+
ret = hci.HCI_SUCCESS
|
|
1792
2279
|
if command.address_resolution_enable == 1:
|
|
1793
2280
|
self.le_address_resolution = True
|
|
1794
2281
|
elif command.address_resolution_enable == 0:
|
|
1795
2282
|
self.le_address_resolution = False
|
|
1796
2283
|
else:
|
|
1797
|
-
ret = HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR
|
|
2284
|
+
ret = hci.HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR
|
|
1798
2285
|
return bytes([ret])
|
|
1799
2286
|
|
|
1800
2287
|
def on_hci_le_set_resolvable_private_address_timeout_command(
|
|
1801
2288
|
self, command: hci.HCI_LE_Set_Resolvable_Private_Address_Timeout_Command
|
|
1802
|
-
) ->
|
|
2289
|
+
) -> bytes | None:
|
|
1803
2290
|
'''
|
|
1804
|
-
See Bluetooth spec Vol 4, Part E - 7.8.45 LE Set Resolvable Private Address
|
|
2291
|
+
See Bluetooth spec Vol 4, Part E - 7.8.45 LE Set Resolvable Private hci.Address
|
|
1805
2292
|
Timeout Command
|
|
1806
2293
|
'''
|
|
1807
2294
|
self.le_rpa_timeout = command.rpa_timeout
|
|
1808
|
-
return bytes([HCI_SUCCESS])
|
|
2295
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1809
2296
|
|
|
1810
2297
|
def on_hci_le_read_maximum_data_length_command(
|
|
1811
2298
|
self, _command: hci.HCI_LE_Read_Maximum_Data_Length_Command
|
|
1812
|
-
) ->
|
|
2299
|
+
) -> bytes | None:
|
|
1813
2300
|
'''
|
|
1814
2301
|
See Bluetooth spec Vol 4, Part E - 7.8.46 LE Read Maximum Data Length Command
|
|
1815
2302
|
'''
|
|
1816
2303
|
return struct.pack(
|
|
1817
2304
|
'<BHHHH',
|
|
1818
|
-
HCI_SUCCESS,
|
|
2305
|
+
hci.HCI_SUCCESS,
|
|
1819
2306
|
self.supported_max_tx_octets,
|
|
1820
2307
|
self.supported_max_tx_time,
|
|
1821
2308
|
self.supported_max_rx_octets,
|
|
@@ -1824,130 +2311,207 @@ class Controller:
|
|
|
1824
2311
|
|
|
1825
2312
|
def on_hci_le_read_phy_command(
|
|
1826
2313
|
self, command: hci.HCI_LE_Read_PHY_Command
|
|
1827
|
-
) ->
|
|
2314
|
+
) -> bytes | None:
|
|
1828
2315
|
'''
|
|
1829
2316
|
See Bluetooth spec Vol 4, Part E - 7.8.47 LE Read PHY Command
|
|
1830
2317
|
'''
|
|
1831
2318
|
return struct.pack(
|
|
1832
2319
|
'<BHBB',
|
|
1833
|
-
HCI_SUCCESS,
|
|
2320
|
+
hci.HCI_SUCCESS,
|
|
1834
2321
|
command.connection_handle,
|
|
1835
|
-
HCI_LE_1M_PHY,
|
|
1836
|
-
HCI_LE_1M_PHY,
|
|
2322
|
+
hci.HCI_LE_1M_PHY,
|
|
2323
|
+
hci.HCI_LE_1M_PHY,
|
|
1837
2324
|
)
|
|
1838
2325
|
|
|
1839
2326
|
def on_hci_le_set_default_phy_command(
|
|
1840
2327
|
self, command: hci.HCI_LE_Set_Default_PHY_Command
|
|
1841
|
-
) ->
|
|
2328
|
+
) -> bytes | None:
|
|
1842
2329
|
'''
|
|
1843
2330
|
See Bluetooth spec Vol 4, Part E - 7.8.48 LE Set Default PHY Command
|
|
1844
2331
|
'''
|
|
1845
2332
|
self.default_phy['all_phys'] = command.all_phys
|
|
1846
2333
|
self.default_phy['tx_phys'] = command.tx_phys
|
|
1847
2334
|
self.default_phy['rx_phys'] = command.rx_phys
|
|
1848
|
-
return bytes([HCI_SUCCESS])
|
|
2335
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1849
2336
|
|
|
1850
2337
|
def on_hci_le_set_advertising_set_random_address_command(
|
|
1851
|
-
self,
|
|
1852
|
-
) ->
|
|
2338
|
+
self, command: hci.HCI_LE_Set_Advertising_Set_Random_Address_Command
|
|
2339
|
+
) -> bytes | None:
|
|
1853
2340
|
'''
|
|
1854
|
-
See Bluetooth spec Vol 4, Part E - 7.8.52 LE Set Advertising Set Random Address
|
|
2341
|
+
See Bluetooth spec Vol 4, Part E - 7.8.52 LE Set Advertising Set Random hci.Address
|
|
1855
2342
|
Command
|
|
1856
2343
|
'''
|
|
1857
|
-
|
|
2344
|
+
handle = command.advertising_handle
|
|
2345
|
+
if handle not in self.advertising_sets:
|
|
2346
|
+
self.advertising_sets[handle] = AdvertisingSet(
|
|
2347
|
+
controller=self, handle=handle
|
|
2348
|
+
)
|
|
2349
|
+
self.advertising_sets[handle].random_address = command.random_address
|
|
2350
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1858
2351
|
|
|
1859
2352
|
def on_hci_le_set_extended_advertising_parameters_command(
|
|
1860
|
-
self,
|
|
1861
|
-
) ->
|
|
2353
|
+
self, command: hci.HCI_LE_Set_Extended_Advertising_Parameters_Command
|
|
2354
|
+
) -> bytes | None:
|
|
1862
2355
|
'''
|
|
1863
2356
|
See Bluetooth spec Vol 4, Part E - 7.8.53 LE Set Extended Advertising Parameters
|
|
1864
2357
|
Command
|
|
1865
2358
|
'''
|
|
1866
|
-
|
|
2359
|
+
handle = command.advertising_handle
|
|
2360
|
+
if handle not in self.advertising_sets:
|
|
2361
|
+
self.advertising_sets[handle] = AdvertisingSet(
|
|
2362
|
+
controller=self, handle=handle
|
|
2363
|
+
)
|
|
2364
|
+
|
|
2365
|
+
self.advertising_sets[handle].parameters = command
|
|
2366
|
+
return bytes([hci.HCI_SUCCESS, 0])
|
|
1867
2367
|
|
|
1868
2368
|
def on_hci_le_set_extended_advertising_data_command(
|
|
1869
|
-
self,
|
|
1870
|
-
) ->
|
|
2369
|
+
self, command: hci.HCI_LE_Set_Extended_Advertising_Data_Command
|
|
2370
|
+
) -> bytes | None:
|
|
1871
2371
|
'''
|
|
1872
2372
|
See Bluetooth spec Vol 4, Part E - 7.8.54 LE Set Extended Advertising Data
|
|
1873
2373
|
Command
|
|
1874
2374
|
'''
|
|
1875
|
-
|
|
2375
|
+
handle = command.advertising_handle
|
|
2376
|
+
if not (adv_set := self.advertising_sets.get(handle)):
|
|
2377
|
+
return bytes([hci.HCI_UNKNOWN_ADVERTISING_IDENTIFIER_ERROR])
|
|
2378
|
+
|
|
2379
|
+
if command.operation in (
|
|
2380
|
+
hci.HCI_LE_Set_Extended_Advertising_Data_Command.Operation.FIRST_FRAGMENT,
|
|
2381
|
+
hci.HCI_LE_Set_Extended_Advertising_Data_Command.Operation.COMPLETE_DATA,
|
|
2382
|
+
):
|
|
2383
|
+
adv_set.data = bytearray(command.advertising_data)
|
|
2384
|
+
elif command.operation in (
|
|
2385
|
+
hci.HCI_LE_Set_Extended_Advertising_Data_Command.Operation.INTERMEDIATE_FRAGMENT,
|
|
2386
|
+
hci.HCI_LE_Set_Extended_Advertising_Data_Command.Operation.LAST_FRAGMENT,
|
|
2387
|
+
):
|
|
2388
|
+
adv_set.data.extend(command.advertising_data)
|
|
2389
|
+
|
|
2390
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1876
2391
|
|
|
1877
2392
|
def on_hci_le_set_extended_scan_response_data_command(
|
|
1878
|
-
self,
|
|
1879
|
-
) ->
|
|
2393
|
+
self, command: hci.HCI_LE_Set_Extended_Scan_Response_Data_Command
|
|
2394
|
+
) -> bytes | None:
|
|
1880
2395
|
'''
|
|
1881
2396
|
See Bluetooth spec Vol 4, Part E - 7.8.55 LE Set Extended Scan Response Data
|
|
1882
2397
|
Command
|
|
1883
2398
|
'''
|
|
1884
|
-
|
|
2399
|
+
handle = command.advertising_handle
|
|
2400
|
+
if not (adv_set := self.advertising_sets.get(handle)):
|
|
2401
|
+
return bytes([hci.HCI_UNKNOWN_ADVERTISING_IDENTIFIER_ERROR])
|
|
2402
|
+
|
|
2403
|
+
if command.operation in (
|
|
2404
|
+
hci.HCI_LE_Set_Extended_Advertising_Data_Command.Operation.FIRST_FRAGMENT,
|
|
2405
|
+
hci.HCI_LE_Set_Extended_Advertising_Data_Command.Operation.COMPLETE_DATA,
|
|
2406
|
+
):
|
|
2407
|
+
adv_set.scan_response_data = bytearray(command.scan_response_data)
|
|
2408
|
+
elif command.operation in (
|
|
2409
|
+
hci.HCI_LE_Set_Extended_Advertising_Data_Command.Operation.INTERMEDIATE_FRAGMENT,
|
|
2410
|
+
hci.HCI_LE_Set_Extended_Advertising_Data_Command.Operation.LAST_FRAGMENT,
|
|
2411
|
+
):
|
|
2412
|
+
adv_set.scan_response_data.extend(command.scan_response_data)
|
|
2413
|
+
|
|
2414
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1885
2415
|
|
|
1886
2416
|
def on_hci_le_set_extended_advertising_enable_command(
|
|
1887
|
-
self,
|
|
1888
|
-
) ->
|
|
2417
|
+
self, command: hci.HCI_LE_Set_Extended_Advertising_Enable_Command
|
|
2418
|
+
) -> bytes | None:
|
|
1889
2419
|
'''
|
|
1890
2420
|
See Bluetooth spec Vol 4, Part E - 7.8.56 LE Set Extended Advertising Enable
|
|
1891
2421
|
Command
|
|
1892
2422
|
'''
|
|
1893
|
-
|
|
2423
|
+
if command.enable:
|
|
2424
|
+
for handle in command.advertising_handles:
|
|
2425
|
+
if advertising_set := self.advertising_sets.get(handle):
|
|
2426
|
+
advertising_set.start()
|
|
2427
|
+
else:
|
|
2428
|
+
if not command.advertising_handles:
|
|
2429
|
+
for advertising_set in self.advertising_sets.values():
|
|
2430
|
+
advertising_set.stop()
|
|
2431
|
+
else:
|
|
2432
|
+
for handle in command.advertising_handles:
|
|
2433
|
+
if advertising_set := self.advertising_sets.get(handle):
|
|
2434
|
+
advertising_set.stop()
|
|
2435
|
+
return bytes([hci.HCI_SUCCESS])
|
|
2436
|
+
|
|
2437
|
+
def on_hci_le_remove_advertising_set_command(
|
|
2438
|
+
self, command: hci.HCI_LE_Remove_Advertising_Set_Command
|
|
2439
|
+
) -> bytes | None:
|
|
2440
|
+
'''
|
|
2441
|
+
See Bluetooth spec Vol 4, Part E - 7.8.59 LE Remove Advertising Set Command
|
|
2442
|
+
'''
|
|
2443
|
+
handle = command.advertising_handle
|
|
2444
|
+
if advertising_set := self.advertising_sets.pop(handle, None):
|
|
2445
|
+
advertising_set.stop()
|
|
2446
|
+
return bytes([hci.HCI_SUCCESS])
|
|
2447
|
+
|
|
2448
|
+
def on_hci_le_clear_advertising_sets_command(
|
|
2449
|
+
self, _command: hci.HCI_LE_Clear_Advertising_Sets_Command
|
|
2450
|
+
) -> bytes | None:
|
|
2451
|
+
'''
|
|
2452
|
+
See Bluetooth spec Vol 4, Part E - 7.8.60 LE Clear Advertising Sets Command
|
|
2453
|
+
'''
|
|
2454
|
+
for advertising_set in self.advertising_sets.values():
|
|
2455
|
+
advertising_set.stop()
|
|
2456
|
+
self.advertising_sets.clear()
|
|
2457
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1894
2458
|
|
|
1895
2459
|
def on_hci_le_read_maximum_advertising_data_length_command(
|
|
1896
2460
|
self, _command: hci.HCI_LE_Read_Maximum_Advertising_Data_Length_Command
|
|
1897
|
-
) ->
|
|
2461
|
+
) -> bytes | None:
|
|
1898
2462
|
'''
|
|
1899
2463
|
See Bluetooth spec Vol 4, Part E - 7.8.57 LE Read Maximum Advertising Data
|
|
1900
2464
|
Length Command
|
|
1901
2465
|
'''
|
|
1902
|
-
return struct.pack('<BH', HCI_SUCCESS, 0x0672)
|
|
2466
|
+
return struct.pack('<BH', hci.HCI_SUCCESS, 0x0672)
|
|
1903
2467
|
|
|
1904
2468
|
def on_hci_le_read_number_of_supported_advertising_sets_command(
|
|
1905
2469
|
self, _command: hci.HCI_LE_Read_Number_Of_Supported_Advertising_Sets_Command
|
|
1906
|
-
) ->
|
|
2470
|
+
) -> bytes | None:
|
|
1907
2471
|
'''
|
|
1908
2472
|
See Bluetooth spec Vol 4, Part E - 7.8.58 LE Read Number of Supported
|
|
1909
2473
|
Advertising Set Command
|
|
1910
2474
|
'''
|
|
1911
|
-
return struct.pack('<BB', HCI_SUCCESS, 0xF0)
|
|
2475
|
+
return struct.pack('<BB', hci.HCI_SUCCESS, 0xF0)
|
|
1912
2476
|
|
|
1913
2477
|
def on_hci_le_set_periodic_advertising_parameters_command(
|
|
1914
2478
|
self, _command: hci.HCI_LE_Set_Periodic_Advertising_Parameters_Command
|
|
1915
|
-
) ->
|
|
2479
|
+
) -> bytes | None:
|
|
1916
2480
|
'''
|
|
1917
2481
|
See Bluetooth spec Vol 4, Part E - 7.8.61 LE Set Periodic Advertising Parameters
|
|
1918
2482
|
Command
|
|
1919
2483
|
'''
|
|
1920
|
-
return bytes([HCI_SUCCESS])
|
|
2484
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1921
2485
|
|
|
1922
2486
|
def on_hci_le_set_periodic_advertising_data_command(
|
|
1923
2487
|
self, _command: hci.HCI_LE_Set_Periodic_Advertising_Data_Command
|
|
1924
|
-
) ->
|
|
2488
|
+
) -> bytes | None:
|
|
1925
2489
|
'''
|
|
1926
2490
|
See Bluetooth spec Vol 4, Part E - 7.8.62 LE Set Periodic Advertising Data
|
|
1927
2491
|
Command
|
|
1928
2492
|
'''
|
|
1929
|
-
return bytes([HCI_SUCCESS])
|
|
2493
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1930
2494
|
|
|
1931
2495
|
def on_hci_le_set_periodic_advertising_enable_command(
|
|
1932
2496
|
self, _command: hci.HCI_LE_Set_Periodic_Advertising_Enable_Command
|
|
1933
|
-
) ->
|
|
2497
|
+
) -> bytes | None:
|
|
1934
2498
|
'''
|
|
1935
2499
|
See Bluetooth spec Vol 4, Part E - 7.8.63 LE Set Periodic Advertising Enable
|
|
1936
2500
|
Command
|
|
1937
2501
|
'''
|
|
1938
|
-
return bytes([HCI_SUCCESS])
|
|
2502
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1939
2503
|
|
|
1940
2504
|
def on_hci_le_read_transmit_power_command(
|
|
1941
2505
|
self, _command: hci.HCI_LE_Read_Transmit_Power_Command
|
|
1942
|
-
) ->
|
|
2506
|
+
) -> bytes | None:
|
|
1943
2507
|
'''
|
|
1944
2508
|
See Bluetooth spec Vol 4, Part E - 7.8.74 LE Read Transmit Power Command
|
|
1945
2509
|
'''
|
|
1946
|
-
return struct.pack('<BBB', HCI_SUCCESS, 0, 0)
|
|
2510
|
+
return struct.pack('<BBB', hci.HCI_SUCCESS, 0, 0)
|
|
1947
2511
|
|
|
1948
2512
|
def on_hci_le_set_cig_parameters_command(
|
|
1949
2513
|
self, command: hci.HCI_LE_Set_CIG_Parameters_Command
|
|
1950
|
-
) ->
|
|
2514
|
+
) -> bytes | None:
|
|
1951
2515
|
'''
|
|
1952
2516
|
See Bluetooth spec Vol 4, Part E - 7.8.97 LE Set CIG Parameter Command
|
|
1953
2517
|
'''
|
|
@@ -1968,12 +2532,12 @@ class Controller:
|
|
|
1968
2532
|
handle=handle,
|
|
1969
2533
|
)
|
|
1970
2534
|
return struct.pack(
|
|
1971
|
-
'<BBB', HCI_SUCCESS, command.cig_id, len(handles)
|
|
2535
|
+
'<BBB', hci.HCI_SUCCESS, command.cig_id, len(handles)
|
|
1972
2536
|
) + b''.join([struct.pack('<H', handle) for handle in handles])
|
|
1973
2537
|
|
|
1974
2538
|
def on_hci_le_create_cis_command(
|
|
1975
2539
|
self, command: hci.HCI_LE_Create_CIS_Command
|
|
1976
|
-
) ->
|
|
2540
|
+
) -> bytes | None:
|
|
1977
2541
|
'''
|
|
1978
2542
|
See Bluetooth spec Vol 4, Part E - 7.8.99 LE Create CIS Command
|
|
1979
2543
|
'''
|
|
@@ -1985,24 +2549,21 @@ class Controller:
|
|
|
1985
2549
|
):
|
|
1986
2550
|
if not (connection := self.find_connection_by_handle(acl_handle)):
|
|
1987
2551
|
logger.error(f'Cannot find connection with handle={acl_handle}')
|
|
1988
|
-
return bytes([HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
|
|
2552
|
+
return bytes([hci.HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
|
|
1989
2553
|
|
|
1990
2554
|
if not (cis_link := self.central_cis_links.get(cis_handle)):
|
|
1991
2555
|
logger.error(f'Cannot find CIS with handle={cis_handle}')
|
|
1992
|
-
return bytes([HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
|
|
2556
|
+
return bytes([hci.HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
|
|
1993
2557
|
|
|
1994
2558
|
cis_link.acl_connection = connection
|
|
1995
2559
|
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
peripheral_address=connection.peer_address,
|
|
1999
|
-
cig_id=cis_link.cig_id,
|
|
2000
|
-
cis_id=cis_link.cis_id,
|
|
2560
|
+
connection.send_ll_control_pdu(
|
|
2561
|
+
ll.CisReq(cig_id=cis_link.cig_id, cis_id=cis_link.cis_id)
|
|
2001
2562
|
)
|
|
2002
2563
|
|
|
2003
2564
|
self.send_hci_packet(
|
|
2004
|
-
HCI_Command_Status_Event(
|
|
2005
|
-
status=HCI_COMMAND_STATUS_PENDING,
|
|
2565
|
+
hci.HCI_Command_Status_Event(
|
|
2566
|
+
status=hci.HCI_COMMAND_STATUS_PENDING,
|
|
2006
2567
|
num_hci_command_packets=1,
|
|
2007
2568
|
command_opcode=command.op_code,
|
|
2008
2569
|
)
|
|
@@ -2011,24 +2572,24 @@ class Controller:
|
|
|
2011
2572
|
|
|
2012
2573
|
def on_hci_le_remove_cig_command(
|
|
2013
2574
|
self, command: hci.HCI_LE_Remove_CIG_Command
|
|
2014
|
-
) ->
|
|
2575
|
+
) -> bytes | None:
|
|
2015
2576
|
'''
|
|
2016
2577
|
See Bluetooth spec Vol 4, Part E - 7.8.100 LE Remove CIG Command
|
|
2017
2578
|
'''
|
|
2018
2579
|
|
|
2019
|
-
status = HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR
|
|
2580
|
+
status = hci.HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR
|
|
2020
2581
|
|
|
2021
2582
|
cis_links = list(self.central_cis_links.items())
|
|
2022
2583
|
for cis_handle, cis_link in cis_links:
|
|
2023
2584
|
if cis_link.cig_id == command.cig_id:
|
|
2024
2585
|
self.central_cis_links.pop(cis_handle)
|
|
2025
|
-
status = HCI_SUCCESS
|
|
2586
|
+
status = hci.HCI_SUCCESS
|
|
2026
2587
|
|
|
2027
2588
|
return struct.pack('<BH', status, command.cig_id)
|
|
2028
2589
|
|
|
2029
2590
|
def on_hci_le_accept_cis_request_command(
|
|
2030
2591
|
self, command: hci.HCI_LE_Accept_CIS_Request_Command
|
|
2031
|
-
) ->
|
|
2592
|
+
) -> bytes | None:
|
|
2032
2593
|
'''
|
|
2033
2594
|
See Bluetooth spec Vol 4, Part E - 7.8.101 LE Accept CIS Request Command
|
|
2034
2595
|
'''
|
|
@@ -2039,19 +2600,16 @@ class Controller:
|
|
|
2039
2600
|
pending_cis_link := self.peripheral_cis_links.get(command.connection_handle)
|
|
2040
2601
|
):
|
|
2041
2602
|
logger.error(f'Cannot find CIS with handle={command.connection_handle}')
|
|
2042
|
-
return bytes([HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
|
|
2603
|
+
return bytes([hci.HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
|
|
2043
2604
|
|
|
2044
2605
|
assert pending_cis_link.acl_connection
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
central_address=pending_cis_link.acl_connection.peer_address,
|
|
2048
|
-
cig_id=pending_cis_link.cig_id,
|
|
2049
|
-
cis_id=pending_cis_link.cis_id,
|
|
2606
|
+
pending_cis_link.acl_connection.send_ll_control_pdu(
|
|
2607
|
+
ll.CisRsp(cig_id=pending_cis_link.cig_id, cis_id=pending_cis_link.cis_id),
|
|
2050
2608
|
)
|
|
2051
2609
|
|
|
2052
2610
|
self.send_hci_packet(
|
|
2053
|
-
HCI_Command_Status_Event(
|
|
2054
|
-
status=HCI_COMMAND_STATUS_PENDING,
|
|
2611
|
+
hci.HCI_Command_Status_Event(
|
|
2612
|
+
status=hci.HCI_COMMAND_STATUS_PENDING,
|
|
2055
2613
|
num_hci_command_packets=1,
|
|
2056
2614
|
command_opcode=command.op_code,
|
|
2057
2615
|
)
|
|
@@ -2060,35 +2618,35 @@ class Controller:
|
|
|
2060
2618
|
|
|
2061
2619
|
def on_hci_le_setup_iso_data_path_command(
|
|
2062
2620
|
self, command: hci.HCI_LE_Setup_ISO_Data_Path_Command
|
|
2063
|
-
) ->
|
|
2621
|
+
) -> bytes | None:
|
|
2064
2622
|
'''
|
|
2065
2623
|
See Bluetooth spec Vol 4, Part E - 7.8.109 LE Setup ISO Data Path Command
|
|
2066
2624
|
'''
|
|
2067
2625
|
if not (iso_link := self.find_iso_link_by_handle(command.connection_handle)):
|
|
2068
2626
|
return struct.pack(
|
|
2069
2627
|
'<BH',
|
|
2070
|
-
HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR,
|
|
2628
|
+
hci.HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR,
|
|
2071
2629
|
command.connection_handle,
|
|
2072
2630
|
)
|
|
2073
2631
|
if command.data_path_direction in iso_link.data_paths:
|
|
2074
2632
|
return struct.pack(
|
|
2075
2633
|
'<BH',
|
|
2076
|
-
HCI_COMMAND_DISALLOWED_ERROR,
|
|
2634
|
+
hci.HCI_COMMAND_DISALLOWED_ERROR,
|
|
2077
2635
|
command.connection_handle,
|
|
2078
2636
|
)
|
|
2079
2637
|
iso_link.data_paths.add(command.data_path_direction)
|
|
2080
|
-
return struct.pack('<BH', HCI_SUCCESS, command.connection_handle)
|
|
2638
|
+
return struct.pack('<BH', hci.HCI_SUCCESS, command.connection_handle)
|
|
2081
2639
|
|
|
2082
2640
|
def on_hci_le_remove_iso_data_path_command(
|
|
2083
2641
|
self, command: hci.HCI_LE_Remove_ISO_Data_Path_Command
|
|
2084
|
-
) ->
|
|
2642
|
+
) -> bytes | None:
|
|
2085
2643
|
'''
|
|
2086
2644
|
See Bluetooth spec Vol 4, Part E - 7.8.110 LE Remove ISO Data Path Command
|
|
2087
2645
|
'''
|
|
2088
2646
|
if not (iso_link := self.find_iso_link_by_handle(command.connection_handle)):
|
|
2089
2647
|
return struct.pack(
|
|
2090
2648
|
'<BH',
|
|
2091
|
-
HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR,
|
|
2649
|
+
hci.HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR,
|
|
2092
2650
|
command.connection_handle,
|
|
2093
2651
|
)
|
|
2094
2652
|
data_paths: set[int] = set(
|
|
@@ -2099,16 +2657,16 @@ class Controller:
|
|
|
2099
2657
|
if not data_paths.issubset(iso_link.data_paths):
|
|
2100
2658
|
return struct.pack(
|
|
2101
2659
|
'<BH',
|
|
2102
|
-
HCI_COMMAND_DISALLOWED_ERROR,
|
|
2660
|
+
hci.HCI_COMMAND_DISALLOWED_ERROR,
|
|
2103
2661
|
command.connection_handle,
|
|
2104
2662
|
)
|
|
2105
2663
|
iso_link.data_paths.difference_update(data_paths)
|
|
2106
|
-
return struct.pack('<BH', HCI_SUCCESS, command.connection_handle)
|
|
2664
|
+
return struct.pack('<BH', hci.HCI_SUCCESS, command.connection_handle)
|
|
2107
2665
|
|
|
2108
2666
|
def on_hci_le_set_host_feature_command(
|
|
2109
2667
|
self, _command: hci.HCI_LE_Set_Host_Feature_Command
|
|
2110
|
-
) ->
|
|
2668
|
+
) -> bytes | None:
|
|
2111
2669
|
'''
|
|
2112
2670
|
See Bluetooth spec Vol 4, Part E - 7.8.115 LE Set Host Feature command
|
|
2113
2671
|
'''
|
|
2114
|
-
return bytes([HCI_SUCCESS])
|
|
2672
|
+
return bytes([hci.HCI_SUCCESS])
|