bumble 0.0.219__py3-none-any.whl → 0.0.220__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/controller.py CHANGED
@@ -23,45 +23,11 @@ import itertools
23
23
  import logging
24
24
  import random
25
25
  import struct
26
- from typing import TYPE_CHECKING, Any, Optional, Union
26
+ from typing import TYPE_CHECKING, Any, Optional, Union, cast
27
27
 
28
- from bumble import hci
28
+ from bumble import hci, lmp
29
29
  from bumble.colors import color
30
30
  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
31
 
66
32
  if TYPE_CHECKING:
67
33
  from bumble.link import LocalLink
@@ -90,24 +56,33 @@ class CisLink:
90
56
  data_paths: set[int] = dataclasses.field(default_factory=set)
91
57
 
92
58
 
59
+ # -----------------------------------------------------------------------------
60
+ @dataclasses.dataclass
61
+ class ScoLink:
62
+ handle: int
63
+ link_type: int
64
+ peer_address: hci.Address
65
+
66
+
93
67
  # -----------------------------------------------------------------------------
94
68
  @dataclasses.dataclass
95
69
  class Connection:
96
70
  controller: Controller
97
71
  handle: int
98
- role: Role
99
- peer_address: Address
72
+ role: hci.Role
73
+ peer_address: hci.Address
100
74
  link: Any
101
75
  transport: int
102
76
  link_type: int
77
+ classic_allow_role_switch: bool = False
103
78
 
104
79
  def __post_init__(self) -> None:
105
- self.assembler = HCI_AclDataPacketAssembler(self.on_acl_pdu)
80
+ self.assembler = hci.HCI_AclDataPacketAssembler(self.on_acl_pdu)
106
81
 
107
82
  def on_hci_acl_data_packet(self, packet: hci.HCI_AclDataPacket) -> None:
108
83
  self.assembler.feed_packet(packet)
109
84
  self.controller.send_hci_packet(
110
- HCI_Number_Of_Completed_Packets_Event(
85
+ hci.HCI_Number_Of_Completed_Packets_Event(
111
86
  connection_handles=[self.handle], num_completed_packets=[1]
112
87
  )
113
88
  )
@@ -124,18 +99,20 @@ class Controller:
124
99
  hci_sink: Optional[TransportSink] = None
125
100
 
126
101
  central_connections: dict[
127
- Address, Connection
102
+ hci.Address, Connection
128
103
  ] # Connections where this controller is the central
129
104
  peripheral_connections: dict[
130
- Address, Connection
105
+ hci.Address, Connection
131
106
  ] # Connections where this controller is the peripheral
132
- classic_connections: dict[Address, Connection] # Connections in BR/EDR
107
+ classic_connections: dict[hci.Address, Connection] # Connections in BR/EDR
108
+ classic_pending_commands: dict[hci.Address, dict[lmp.Opcode, asyncio.Future[int]]]
109
+ sco_links: dict[hci.Address, ScoLink] # SCO links by address
133
110
  central_cis_links: dict[int, CisLink] # CIS links by handle
134
111
  peripheral_cis_links: dict[int, CisLink] # CIS links by handle
135
112
 
136
- hci_version: int = HCI_VERSION_BLUETOOTH_CORE_5_0
113
+ hci_version: int = hci.HCI_VERSION_BLUETOOTH_CORE_5_0
137
114
  hci_revision: int = 0
138
- lmp_version: int = HCI_VERSION_BLUETOOTH_CORE_5_0
115
+ lmp_version: int = hci.HCI_VERSION_BLUETOOTH_CORE_5_0
139
116
  lmp_subversion: int = 0
140
117
  lmp_features: bytes = bytes.fromhex(
141
118
  '0000000060000000'
@@ -174,7 +151,7 @@ class Controller:
174
151
  le_scan_interval: int = 0x10
175
152
  le_scan_window: int = 0x10
176
153
  le_scan_enable: int = 0
177
- le_scan_own_address_type: int = Address.RANDOM_DEVICE_ADDRESS
154
+ le_scan_own_address_type: int = hci.Address.RANDOM_DEVICE_ADDRESS
178
155
  le_scanning_filter_policy: int = 0
179
156
  le_scan_response_data: Optional[bytes] = None
180
157
  le_address_resolution: bool = False
@@ -184,8 +161,10 @@ class Controller:
184
161
  advertising_interval: int = 2000
185
162
  advertising_data: Optional[bytes] = None
186
163
  advertising_timer_handle: Optional[asyncio.Handle] = None
164
+ classic_scan_enable: int = 0
165
+ classic_allow_role_switch: bool = True
187
166
 
188
- _random_address: 'Address' = Address('00:00:00:00:00:00')
167
+ _random_address: hci.Address = hci.Address('00:00:00:00:00:00')
189
168
 
190
169
  def __init__(
191
170
  self,
@@ -193,13 +172,15 @@ class Controller:
193
172
  host_source=None,
194
173
  host_sink: Optional[TransportSink] = None,
195
174
  link: Optional[LocalLink] = None,
196
- public_address: Optional[Union[bytes, str, Address]] = None,
175
+ public_address: Optional[Union[bytes, str, hci.Address]] = None,
197
176
  ) -> None:
198
177
  self.name = name
199
178
  self.link = link
200
179
  self.central_connections = {}
201
180
  self.peripheral_connections = {}
202
181
  self.classic_connections = {}
182
+ self.sco_links = {}
183
+ self.classic_pending_commands = {}
203
184
  self.central_cis_links = {}
204
185
  self.peripheral_cis_links = {}
205
186
  self.default_phy = {
@@ -208,14 +189,14 @@ class Controller:
208
189
  'rx_phys': 0,
209
190
  }
210
191
 
211
- if isinstance(public_address, Address):
192
+ if isinstance(public_address, hci.Address):
212
193
  self._public_address = public_address
213
194
  elif public_address is not None:
214
- self._public_address = Address(
215
- public_address, Address.PUBLIC_DEVICE_ADDRESS
195
+ self._public_address = hci.Address(
196
+ public_address, hci.Address.PUBLIC_DEVICE_ADDRESS
216
197
  )
217
198
  else:
218
- self._public_address = Address('00:00:00:00:00:00')
199
+ self._public_address = hci.Address('00:00:00:00:00:00')
219
200
 
220
201
  # Set the source and sink interfaces
221
202
  if host_source:
@@ -249,23 +230,23 @@ class Controller:
249
230
  self.hci_sink = sink
250
231
 
251
232
  @property
252
- def public_address(self) -> Address:
233
+ def public_address(self) -> hci.Address:
253
234
  return self._public_address
254
235
 
255
236
  @public_address.setter
256
- def public_address(self, address: Union[Address, str]) -> None:
237
+ def public_address(self, address: Union[hci.Address, str]) -> None:
257
238
  if isinstance(address, str):
258
- address = Address(address)
239
+ address = hci.Address(address)
259
240
  self._public_address = address
260
241
 
261
242
  @property
262
- def random_address(self) -> Address:
243
+ def random_address(self) -> hci.Address:
263
244
  return self._random_address
264
245
 
265
246
  @random_address.setter
266
- def random_address(self, address: Union[Address, str]) -> None:
247
+ def random_address(self, address: Union[hci.Address, str]) -> None:
267
248
  if isinstance(address, str):
268
- address = Address(address)
249
+ address = hci.Address(address)
269
250
  self._random_address = address
270
251
  logger.debug(f'new random address: {address}')
271
252
 
@@ -274,9 +255,9 @@ class Controller:
274
255
 
275
256
  # Packet Sink protocol (packets coming from the host via HCI)
276
257
  def on_packet(self, packet: bytes) -> None:
277
- self.on_hci_packet(HCI_Packet.from_bytes(packet))
258
+ self.on_hci_packet(hci.HCI_Packet.from_bytes(packet))
278
259
 
279
- def on_hci_packet(self, packet: HCI_Packet) -> None:
260
+ def on_hci_packet(self, packet: hci.HCI_Packet) -> None:
280
261
  logger.debug(
281
262
  f'{color("<<<", "blue")} [{self.name}] '
282
263
  f'{color("HOST -> CONTROLLER", "blue")}: {packet}'
@@ -298,14 +279,14 @@ class Controller:
298
279
  result: Optional[bytes] = handler(command)
299
280
  if isinstance(result, bytes):
300
281
  self.send_hci_packet(
301
- HCI_Command_Complete_Event(
282
+ hci.HCI_Command_Complete_Event(
302
283
  num_hci_command_packets=1,
303
284
  command_opcode=command.op_code,
304
285
  return_parameters=result,
305
286
  )
306
287
  )
307
288
 
308
- def on_hci_event_packet(self, _event: HCI_Packet) -> None:
289
+ def on_hci_event_packet(self, _event: hci.HCI_Packet) -> None:
309
290
  logger.warning('!!! unexpected event packet')
310
291
 
311
292
  def on_hci_acl_data_packet(self, packet: hci.HCI_AclDataPacket) -> None:
@@ -320,13 +301,13 @@ class Controller:
320
301
  # Pass the packet to the connection
321
302
  connection.on_hci_acl_data_packet(packet)
322
303
 
323
- def send_hci_packet(self, packet: HCI_Packet) -> None:
304
+ def send_hci_packet(self, packet: hci.HCI_Packet) -> None:
324
305
  logger.debug(
325
306
  f'{color(">>>", "green")} [{self.name}] '
326
307
  f'{color("CONTROLLER -> HOST", "green")}: {packet}'
327
308
  )
328
309
  if self.host:
329
- self.host.on_packet(bytes(packet))
310
+ asyncio.get_running_loop().call_soon(self.host.on_packet, bytes(packet))
330
311
 
331
312
  # This method allows the controller to emulate the same API as a transport source
332
313
  async def wait_for_termination(self) -> None:
@@ -336,33 +317,30 @@ class Controller:
336
317
  # Link connections
337
318
  ############################################################
338
319
  def allocate_connection_handle(self) -> int:
339
- handle = 0
340
- max_handle = 0
341
- for connection in itertools.chain(
342
- self.central_connections.values(),
343
- self.peripheral_connections.values(),
344
- self.classic_connections.values(),
345
- ):
346
- max_handle = max(max_handle, connection.handle)
347
- if connection.handle == handle:
348
- # Already used, continue searching after the current max
349
- handle = max_handle + 1
350
- for cis_handle in itertools.chain(
351
- self.central_cis_links.keys(), self.peripheral_cis_links.keys()
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
320
+ current_handles = set(
321
+ cast(Connection | CisLink | ScoLink, link).handle
322
+ for link in itertools.chain(
323
+ self.central_connections.values(),
324
+ self.peripheral_connections.values(),
325
+ self.classic_connections.values(),
326
+ self.sco_links.values(),
327
+ self.central_cis_links.values(),
328
+ self.peripheral_cis_links.values(),
329
+ )
330
+ )
331
+ return next(
332
+ handle for handle in range(0xEFF + 1) if handle not in current_handles
333
+ )
358
334
 
359
- def find_le_connection_by_address(self, address: Address) -> Optional[Connection]:
335
+ def find_le_connection_by_address(
336
+ self, address: hci.Address
337
+ ) -> Optional[Connection]:
360
338
  return self.central_connections.get(address) or self.peripheral_connections.get(
361
339
  address
362
340
  )
363
341
 
364
342
  def find_classic_connection_by_address(
365
- self, address: Address
343
+ self, address: hci.Address
366
344
  ) -> Optional[Connection]:
367
345
  return self.classic_connections.get(address)
368
346
 
@@ -394,12 +372,18 @@ class Controller:
394
372
  return connection
395
373
  return None
396
374
 
375
+ def find_classic_sco_link_by_handle(self, handle: int) -> Optional[ScoLink]:
376
+ for connection in self.sco_links.values():
377
+ if connection.handle == handle:
378
+ return connection
379
+ return None
380
+
397
381
  def find_iso_link_by_handle(self, handle: int) -> Optional[CisLink]:
398
382
  return self.central_cis_links.get(handle) or self.peripheral_cis_links.get(
399
383
  handle
400
384
  )
401
385
 
402
- def on_link_central_connected(self, central_address: Address) -> None:
386
+ def on_link_central_connected(self, central_address: hci.Address) -> None:
403
387
  '''
404
388
  Called when an incoming connection occurs from a central on the link
405
389
  '''
@@ -413,19 +397,19 @@ class Controller:
413
397
  connection = Connection(
414
398
  controller=self,
415
399
  handle=connection_handle,
416
- role=Role.PERIPHERAL,
400
+ role=hci.Role.PERIPHERAL,
417
401
  peer_address=peer_address,
418
402
  link=self.link,
419
403
  transport=PhysicalTransport.LE,
420
- link_type=HCI_Connection_Complete_Event.LinkType.ACL,
404
+ link_type=hci.HCI_Connection_Complete_Event.LinkType.ACL,
421
405
  )
422
406
  self.peripheral_connections[peer_address] = connection
423
407
  logger.debug(f'New PERIPHERAL connection handle: 0x{connection_handle:04X}')
424
408
 
425
409
  # Then say that the connection has completed
426
410
  self.send_hci_packet(
427
- HCI_LE_Connection_Complete_Event(
428
- status=HCI_SUCCESS,
411
+ hci.HCI_LE_Connection_Complete_Event(
412
+ status=hci.HCI_SUCCESS,
429
413
  connection_handle=connection.handle,
430
414
  role=connection.role,
431
415
  peer_address_type=peer_address_type,
@@ -437,7 +421,7 @@ class Controller:
437
421
  )
438
422
  )
439
423
 
440
- def on_link_disconnected(self, peer_address: Address, reason: int) -> None:
424
+ def on_link_disconnected(self, peer_address: hci.Address, reason: int) -> None:
441
425
  '''
442
426
  Called when an active disconnection occurs from a peer
443
427
  '''
@@ -445,8 +429,8 @@ class Controller:
445
429
  # Send a disconnection complete event
446
430
  if connection := self.peripheral_connections.get(peer_address):
447
431
  self.send_hci_packet(
448
- HCI_Disconnection_Complete_Event(
449
- status=HCI_SUCCESS,
432
+ hci.HCI_Disconnection_Complete_Event(
433
+ status=hci.HCI_SUCCESS,
450
434
  connection_handle=connection.handle,
451
435
  reason=reason,
452
436
  )
@@ -456,8 +440,8 @@ class Controller:
456
440
  del self.peripheral_connections[peer_address]
457
441
  elif connection := self.central_connections.get(peer_address):
458
442
  self.send_hci_packet(
459
- HCI_Disconnection_Complete_Event(
460
- status=HCI_SUCCESS,
443
+ hci.HCI_Disconnection_Complete_Event(
444
+ status=hci.HCI_SUCCESS,
461
445
  connection_handle=connection.handle,
462
446
  reason=reason,
463
447
  )
@@ -477,7 +461,7 @@ class Controller:
477
461
  Called by the link when a connection has been made or has failed to be made
478
462
  '''
479
463
 
480
- if status == HCI_SUCCESS:
464
+ if status == hci.HCI_SUCCESS:
481
465
  # Allocate (or reuse) a connection handle
482
466
  peer_address = le_create_connection_command.peer_address
483
467
  connection = self.central_connections.get(peer_address)
@@ -486,11 +470,11 @@ class Controller:
486
470
  connection = Connection(
487
471
  controller=self,
488
472
  handle=connection_handle,
489
- role=Role.CENTRAL,
473
+ role=hci.Role.CENTRAL,
490
474
  peer_address=peer_address,
491
475
  link=self.link,
492
476
  transport=PhysicalTransport.LE,
493
- link_type=HCI_Connection_Complete_Event.LinkType.ACL,
477
+ link_type=hci.HCI_Connection_Complete_Event.LinkType.ACL,
494
478
  )
495
479
  self.central_connections[peer_address] = connection
496
480
  logger.debug(
@@ -502,10 +486,10 @@ class Controller:
502
486
  # Say that the connection has completed
503
487
  self.send_hci_packet(
504
488
  # pylint: disable=line-too-long
505
- HCI_LE_Connection_Complete_Event(
489
+ hci.HCI_LE_Connection_Complete_Event(
506
490
  status=status,
507
491
  connection_handle=connection.handle if connection else 0,
508
- role=Role.CENTRAL,
492
+ role=hci.Role.CENTRAL,
509
493
  peer_address_type=le_create_connection_command.peer_address_type,
510
494
  peer_address=le_create_connection_command.peer_address,
511
495
  connection_interval=le_create_connection_command.connection_interval_min,
@@ -524,7 +508,7 @@ class Controller:
524
508
 
525
509
  # Send a disconnection complete event
526
510
  self.send_hci_packet(
527
- HCI_Disconnection_Complete_Event(
511
+ hci.HCI_Disconnection_Complete_Event(
528
512
  status=status,
529
513
  connection_handle=disconnection_command.connection_handle,
530
514
  reason=disconnection_command.reason,
@@ -544,18 +528,18 @@ class Controller:
544
528
  del self.peripheral_connections[connection.peer_address]
545
529
 
546
530
  def on_link_encrypted(
547
- self, peer_address: Address, _rand: int, _ediv: int, _ltk: bytes
531
+ self, peer_address: hci.Address, _rand: bytes, _ediv: int, _ltk: bytes
548
532
  ) -> None:
549
533
  # For now, just setup the encryption without asking the host
550
534
  if connection := self.find_le_connection_by_address(peer_address):
551
535
  self.send_hci_packet(
552
- HCI_Encryption_Change_Event(
536
+ hci.HCI_Encryption_Change_Event(
553
537
  status=0, connection_handle=connection.handle, encryption_enabled=1
554
538
  )
555
539
  )
556
540
 
557
541
  def on_link_acl_data(
558
- self, sender_address: Address, transport: PhysicalTransport, data: bytes
542
+ self, sender_address: hci.Address, transport: PhysicalTransport, data: bytes
559
543
  ) -> None:
560
544
  # Look for the connection to which this data belongs
561
545
  if transport == PhysicalTransport.LE:
@@ -568,36 +552,38 @@ class Controller:
568
552
 
569
553
  # Send the data to the host
570
554
  # TODO: should fragment
571
- acl_packet = HCI_AclDataPacket(connection.handle, 2, 0, len(data), data)
555
+ acl_packet = hci.HCI_AclDataPacket(connection.handle, 2, 0, len(data), data)
572
556
  self.send_hci_packet(acl_packet)
573
557
 
574
- def on_link_advertising_data(self, sender_address: Address, data: bytes) -> None:
558
+ def on_link_advertising_data(
559
+ self, sender_address: hci.Address, data: bytes
560
+ ) -> None:
575
561
  # Ignore if we're not scanning
576
562
  if self.le_scan_enable == 0:
577
563
  return
578
564
 
579
565
  # Send a scan report
580
- report = HCI_LE_Advertising_Report_Event.Report(
581
- event_type=HCI_LE_Advertising_Report_Event.EventType.ADV_IND,
566
+ report = hci.HCI_LE_Advertising_Report_Event.Report(
567
+ event_type=hci.HCI_LE_Advertising_Report_Event.EventType.ADV_IND,
582
568
  address_type=sender_address.address_type,
583
569
  address=sender_address,
584
570
  data=data,
585
571
  rssi=-50,
586
572
  )
587
- self.send_hci_packet(HCI_LE_Advertising_Report_Event([report]))
573
+ self.send_hci_packet(hci.HCI_LE_Advertising_Report_Event([report]))
588
574
 
589
575
  # Simulate a scan response
590
- report = HCI_LE_Advertising_Report_Event.Report(
591
- event_type=HCI_LE_Advertising_Report_Event.EventType.SCAN_RSP,
576
+ report = hci.HCI_LE_Advertising_Report_Event.Report(
577
+ event_type=hci.HCI_LE_Advertising_Report_Event.EventType.SCAN_RSP,
592
578
  address_type=sender_address.address_type,
593
579
  address=sender_address,
594
580
  data=data,
595
581
  rssi=-50,
596
582
  )
597
- self.send_hci_packet(HCI_LE_Advertising_Report_Event([report]))
583
+ self.send_hci_packet(hci.HCI_LE_Advertising_Report_Event([report]))
598
584
 
599
585
  def on_link_cis_request(
600
- self, central_address: Address, cig_id: int, cis_id: int
586
+ self, central_address: hci.Address, cig_id: int, cis_id: int
601
587
  ) -> None:
602
588
  '''
603
589
  Called when an incoming CIS request occurs from a central on the link
@@ -615,7 +601,7 @@ class Controller:
615
601
  self.peripheral_cis_links[pending_cis_link.handle] = pending_cis_link
616
602
 
617
603
  self.send_hci_packet(
618
- HCI_LE_CIS_Request_Event(
604
+ hci.HCI_LE_CIS_Request_Event(
619
605
  acl_connection_handle=connection.handle,
620
606
  cis_connection_handle=pending_cis_link.handle,
621
607
  cig_id=cig_id,
@@ -637,8 +623,8 @@ class Controller:
637
623
  )
638
624
 
639
625
  self.send_hci_packet(
640
- HCI_LE_CIS_Established_Event(
641
- status=HCI_SUCCESS,
626
+ hci.HCI_LE_CIS_Established_Event(
627
+ status=hci.HCI_SUCCESS,
642
628
  connection_handle=cis_link.handle,
643
629
  # CIS parameters are ignored.
644
630
  cig_sync_delay=0,
@@ -681,16 +667,16 @@ class Controller:
681
667
  ),
682
668
  None,
683
669
  ):
684
- # Keep central CIS on disconnection. They should be removed by HCI_LE_Remove_CIG_Command.
670
+ # Keep central CIS on disconnection. They should be removed by hci.HCI_LE_Remove_CIG_Command.
685
671
  cis_link.acl_connection = None
686
672
  else:
687
673
  return
688
674
 
689
675
  self.send_hci_packet(
690
- HCI_Disconnection_Complete_Event(
691
- status=HCI_SUCCESS,
676
+ hci.HCI_Disconnection_Complete_Event(
677
+ status=hci.HCI_SUCCESS,
692
678
  connection_handle=cis_link.handle,
693
- reason=HCI_REMOTE_USER_TERMINATED_CONNECTION_ERROR,
679
+ reason=hci.HCI_REMOTE_USER_TERMINATED_CONNECTION_ERROR,
694
680
  )
695
681
  )
696
682
 
@@ -698,11 +684,86 @@ class Controller:
698
684
  # Classic link connections
699
685
  ############################################################
700
686
 
687
+ def send_lmp_packet(
688
+ self, receiver_address: hci.Address, packet: lmp.Packet
689
+ ) -> asyncio.Future[int]:
690
+ loop = asyncio.get_running_loop()
691
+ assert self.link
692
+ self.link.send_lmp_packet(self, receiver_address, packet)
693
+ future = self.classic_pending_commands.setdefault(receiver_address, {})[
694
+ packet.opcode
695
+ ] = loop.create_future()
696
+ return future
697
+
698
+ def on_lmp_packet(self, sender_address: hci.Address, packet: lmp.Packet):
699
+ if isinstance(packet, (lmp.LmpAccepted, lmp.LmpAcceptedExt)):
700
+ if future := self.classic_pending_commands.setdefault(
701
+ sender_address, {}
702
+ ).get(packet.response_opcode):
703
+ future.set_result(hci.HCI_SUCCESS)
704
+ else:
705
+ logger.error("!!! Unhandled packet: %s", packet)
706
+ elif isinstance(packet, (lmp.LmpNotAccepted, lmp.LmpNotAcceptedExt)):
707
+ if future := self.classic_pending_commands.setdefault(
708
+ sender_address, {}
709
+ ).get(packet.response_opcode):
710
+ future.set_result(packet.error_code)
711
+ else:
712
+ logger.error("!!! Unhandled packet: %s", packet)
713
+ elif isinstance(packet, (lmp.LmpHostConnectionReq)):
714
+ self.on_classic_connection_request(
715
+ sender_address, hci.HCI_Connection_Complete_Event.LinkType.ACL
716
+ )
717
+ elif isinstance(packet, (lmp.LmpScoLinkReq)):
718
+ self.on_classic_connection_request(
719
+ sender_address, hci.HCI_Connection_Complete_Event.LinkType.SCO
720
+ )
721
+ elif isinstance(packet, (lmp.LmpEscoLinkReq)):
722
+ self.on_classic_connection_request(
723
+ sender_address, hci.HCI_Connection_Complete_Event.LinkType.ESCO
724
+ )
725
+ elif isinstance(packet, (lmp.LmpDetach)):
726
+ self.on_classic_disconnected(
727
+ sender_address, hci.HCI_REMOTE_USER_TERMINATED_CONNECTION_ERROR
728
+ )
729
+ elif isinstance(packet, (lmp.LmpSwitchReq)):
730
+ self.on_classic_role_change_request(sender_address)
731
+ elif isinstance(packet, (lmp.LmpRemoveScoLinkReq, lmp.LmpRemoveEscoLinkReq)):
732
+ self.on_classic_sco_disconnected(sender_address, packet.error_code)
733
+ elif isinstance(packet, lmp.LmpNameReq):
734
+ self.on_classic_remote_name_request(sender_address, packet.name_offset)
735
+ elif isinstance(packet, lmp.LmpNameRes):
736
+ self.on_classic_remote_name_response(
737
+ sender_address,
738
+ packet.name_offset,
739
+ packet.name_length,
740
+ packet.name_fregment,
741
+ )
742
+ else:
743
+ logger.error("!!! Unhandled packet: %s", packet)
744
+
701
745
  def on_classic_connection_request(
702
- self, peer_address: Address, link_type: int
746
+ self, peer_address: hci.Address, link_type: int
703
747
  ) -> None:
748
+ if link_type == hci.HCI_Connection_Complete_Event.LinkType.ACL:
749
+ self.classic_connections[peer_address] = Connection(
750
+ controller=self,
751
+ handle=0,
752
+ role=hci.Role.PERIPHERAL,
753
+ peer_address=peer_address,
754
+ link=self.link,
755
+ transport=PhysicalTransport.BR_EDR,
756
+ link_type=link_type,
757
+ classic_allow_role_switch=self.classic_allow_role_switch,
758
+ )
759
+ else:
760
+ self.sco_links[peer_address] = ScoLink(
761
+ handle=0,
762
+ link_type=link_type,
763
+ peer_address=peer_address,
764
+ )
704
765
  self.send_hci_packet(
705
- HCI_Connection_Request_Event(
766
+ hci.HCI_Connection_Request_Event(
706
767
  bd_addr=peer_address,
707
768
  class_of_device=0,
708
769
  link_type=link_type,
@@ -710,99 +771,126 @@ class Controller:
710
771
  )
711
772
 
712
773
  def on_classic_connection_complete(
713
- self, peer_address: Address, status: int
774
+ self, peer_address: hci.Address, status: int
714
775
  ) -> None:
715
- if status == HCI_SUCCESS:
776
+ if status == hci.HCI_SUCCESS:
716
777
  # Allocate (or reuse) a connection handle
717
778
  peer_address = peer_address
718
- connection = self.classic_connections.get(peer_address)
719
- if connection is None:
720
- connection_handle = self.allocate_connection_handle()
779
+ connection_handle = self.allocate_connection_handle()
780
+ if connection := self.classic_connections.get(peer_address):
781
+ connection.handle = connection_handle
782
+ else:
721
783
  connection = Connection(
722
784
  controller=self,
723
785
  handle=connection_handle,
724
- # Role doesn't matter in Classic because they are managed by HCI_Role_Change and HCI_Role_Discovery
725
- role=Role.CENTRAL,
786
+ role=hci.Role.CENTRAL,
726
787
  peer_address=peer_address,
727
788
  link=self.link,
728
789
  transport=PhysicalTransport.BR_EDR,
729
- link_type=HCI_Connection_Complete_Event.LinkType.ACL,
790
+ link_type=hci.HCI_Connection_Complete_Event.LinkType.ACL,
730
791
  )
731
792
  self.classic_connections[peer_address] = connection
732
793
  logger.debug(
733
794
  f'New CLASSIC connection handle: 0x{connection_handle:04X}'
734
795
  )
735
- else:
736
- connection_handle = connection.handle
737
796
  self.send_hci_packet(
738
- HCI_Connection_Complete_Event(
797
+ hci.HCI_Connection_Complete_Event(
739
798
  status=status,
740
799
  connection_handle=connection_handle,
741
800
  bd_addr=peer_address,
742
801
  encryption_enabled=False,
743
- link_type=HCI_Connection_Complete_Event.LinkType.ACL,
802
+ link_type=hci.HCI_Connection_Complete_Event.LinkType.ACL,
744
803
  )
745
804
  )
746
805
  else:
747
806
  connection = None
748
807
  self.send_hci_packet(
749
- HCI_Connection_Complete_Event(
808
+ hci.HCI_Connection_Complete_Event(
750
809
  status=status,
751
810
  connection_handle=0,
752
811
  bd_addr=peer_address,
753
812
  encryption_enabled=False,
754
- link_type=HCI_Connection_Complete_Event.LinkType.ACL,
813
+ link_type=hci.HCI_Connection_Complete_Event.LinkType.ACL,
755
814
  )
756
815
  )
757
816
 
758
- def on_classic_disconnected(self, peer_address: Address, reason: int) -> None:
817
+ def on_classic_disconnected(self, peer_address: hci.Address, reason: int) -> None:
759
818
  # Send a disconnection complete event
760
- if connection := self.classic_connections.get(peer_address):
819
+ if connection := self.classic_connections.pop(peer_address, None):
761
820
  self.send_hci_packet(
762
- HCI_Disconnection_Complete_Event(
763
- status=HCI_SUCCESS,
821
+ hci.HCI_Disconnection_Complete_Event(
822
+ status=hci.HCI_SUCCESS,
764
823
  connection_handle=connection.handle,
765
824
  reason=reason,
766
825
  )
767
826
  )
827
+ else:
828
+ logger.warning(f'!!! No classic connection found for {peer_address}')
768
829
 
769
- # Remove the connection
770
- del self.classic_connections[peer_address]
830
+ def on_classic_sco_disconnected(
831
+ self, peer_address: hci.Address, reason: int
832
+ ) -> None:
833
+ # Send a disconnection complete event
834
+ if sco_link := self.sco_links.pop(peer_address, None):
835
+ self.send_hci_packet(
836
+ hci.HCI_Disconnection_Complete_Event(
837
+ status=hci.HCI_SUCCESS,
838
+ connection_handle=sco_link.handle,
839
+ reason=reason,
840
+ )
841
+ )
771
842
  else:
772
843
  logger.warning(f'!!! No classic connection found for {peer_address}')
773
844
 
774
- def on_classic_role_change(self, peer_address: Address, new_role: int) -> None:
845
+ def on_classic_role_change_request(self, peer_address: hci.Address) -> None:
846
+ assert (connection := self.classic_connections.get(peer_address))
847
+ if not connection.classic_allow_role_switch:
848
+ self.send_lmp_packet(
849
+ peer_address,
850
+ lmp.LmpNotAccepted(
851
+ lmp.Opcode.LMP_SWITCH_REQ, hci.HCI_ROLE_CHANGE_NOT_ALLOWED_ERROR
852
+ ),
853
+ )
854
+ else:
855
+ self.send_lmp_packet(
856
+ peer_address,
857
+ lmp.LmpAccepted(lmp.Opcode.LMP_SWITCH_REQ),
858
+ )
859
+ self.classic_role_change(connection)
860
+
861
+ def classic_role_change(self, connection: Connection) -> None:
862
+ new_role = (
863
+ hci.Role.CENTRAL
864
+ if connection.role == hci.Role.PERIPHERAL
865
+ else hci.Role.PERIPHERAL
866
+ )
867
+ connection.role = new_role
775
868
  self.send_hci_packet(
776
- HCI_Role_Change_Event(
777
- status=HCI_SUCCESS,
778
- bd_addr=peer_address,
869
+ hci.HCI_Role_Change_Event(
870
+ status=hci.HCI_SUCCESS,
871
+ bd_addr=connection.peer_address,
779
872
  new_role=new_role,
780
873
  )
781
874
  )
782
875
 
783
876
  def on_classic_sco_connection_complete(
784
- self, peer_address: Address, status: int, link_type: int
877
+ self, peer_address: hci.Address, status: int, link_type: int
785
878
  ) -> None:
786
- if status == HCI_SUCCESS:
879
+ if status == hci.HCI_SUCCESS:
787
880
  # Allocate (or reuse) a connection handle
788
881
  connection_handle = self.allocate_connection_handle()
789
- connection = Connection(
790
- controller=self,
882
+ sco_link = ScoLink(
791
883
  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
884
  link_type=link_type,
885
+ peer_address=peer_address,
798
886
  )
799
- self.classic_connections[peer_address] = connection
887
+ self.sco_links[peer_address] = sco_link
800
888
  logger.debug(f'New SCO connection handle: 0x{connection_handle:04X}')
801
889
  else:
802
890
  connection_handle = 0
803
891
 
804
892
  self.send_hci_packet(
805
- HCI_Synchronous_Connection_Complete_Event(
893
+ hci.HCI_Synchronous_Connection_Complete_Event(
806
894
  status=status,
807
895
  connection_handle=connection_handle,
808
896
  bd_addr=peer_address,
@@ -816,6 +904,33 @@ class Controller:
816
904
  )
817
905
  )
818
906
 
907
+ def on_classic_remote_name_request(
908
+ self, peer_address: hci.Address, name_offset: int
909
+ ):
910
+ self.send_lmp_packet(
911
+ peer_address,
912
+ lmp.LmpNameRes(
913
+ name_offset=name_offset,
914
+ name_length=len(self.local_name),
915
+ name_fregment=self.local_name.encode('utf-8'),
916
+ ),
917
+ )
918
+
919
+ def on_classic_remote_name_response(
920
+ self,
921
+ peer_address: hci.Address,
922
+ name_offset: int,
923
+ name_length: int,
924
+ name_fregment: bytes,
925
+ ):
926
+ self.send_hci_packet(
927
+ hci.HCI_Remote_Name_Request_Complete_Event(
928
+ status=hci.HCI_SUCCESS,
929
+ bd_addr=peer_address,
930
+ remote_name=name_fregment,
931
+ )
932
+ )
933
+
819
934
  ############################################################
820
935
  # Advertising support
821
936
  ############################################################
@@ -852,7 +967,7 @@ class Controller:
852
967
  ############################################################
853
968
  def on_hci_command(self, command: hci.HCI_Command) -> Optional[bytes]:
854
969
  logger.warning(color(f'--- Unsupported command {command}', 'red'))
855
- return bytes([HCI_UNKNOWN_HCI_COMMAND_ERROR])
970
+ return bytes([hci.HCI_UNKNOWN_HCI_COMMAND_ERROR])
856
971
 
857
972
  def on_hci_create_connection_command(
858
973
  self, command: hci.HCI_Create_Connection_Command
@@ -868,24 +983,39 @@ class Controller:
868
983
  # Check that we don't already have a pending connection
869
984
  if self.link.get_pending_connection():
870
985
  self.send_hci_packet(
871
- HCI_Command_Status_Event(
872
- status=HCI_CONTROLLER_BUSY_ERROR,
986
+ hci.HCI_Command_Status_Event(
987
+ status=hci.HCI_CONTROLLER_BUSY_ERROR,
873
988
  num_hci_command_packets=1,
874
989
  command_opcode=command.op_code,
875
990
  )
876
991
  )
877
992
  return None
878
993
 
879
- self.link.classic_connect(self, command.bd_addr)
994
+ self.classic_connections[command.bd_addr] = Connection(
995
+ controller=self,
996
+ handle=0,
997
+ role=hci.Role.CENTRAL,
998
+ peer_address=command.bd_addr,
999
+ link=self.link,
1000
+ transport=PhysicalTransport.BR_EDR,
1001
+ link_type=hci.HCI_Connection_Complete_Event.LinkType.ACL,
1002
+ classic_allow_role_switch=bool(command.allow_role_switch),
1003
+ )
880
1004
 
881
1005
  # Say that the connection is pending
882
1006
  self.send_hci_packet(
883
- HCI_Command_Status_Event(
884
- status=HCI_COMMAND_STATUS_PENDING,
1007
+ hci.HCI_Command_Status_Event(
1008
+ status=hci.HCI_COMMAND_STATUS_PENDING,
885
1009
  num_hci_command_packets=1,
886
1010
  command_opcode=command.op_code,
887
1011
  )
888
1012
  )
1013
+ future = self.send_lmp_packet(command.bd_addr, lmp.LmpHostConnectionReq())
1014
+
1015
+ def on_response(future: asyncio.Future[int]):
1016
+ self.on_classic_connection_complete(command.bd_addr, future.result())
1017
+
1018
+ future.add_done_callback(on_response)
889
1019
  return None
890
1020
 
891
1021
  def on_hci_disconnect_command(
@@ -896,8 +1026,8 @@ class Controller:
896
1026
  '''
897
1027
  # First, say that the disconnection is pending
898
1028
  self.send_hci_packet(
899
- HCI_Command_Status_Event(
900
- status=HCI_COMMAND_STATUS_PENDING,
1029
+ hci.HCI_Command_Status_Event(
1030
+ status=hci.HCI_COMMAND_STATUS_PENDING,
901
1031
  num_hci_command_packets=1,
902
1032
  command_opcode=command.op_code,
903
1033
  )
@@ -923,14 +1053,37 @@ class Controller:
923
1053
  del self.peripheral_connections[connection.peer_address]
924
1054
  elif connection := self.find_classic_connection_by_handle(handle):
925
1055
  if self.link:
926
- self.link.classic_disconnect(
927
- self,
1056
+ self.send_lmp_packet(
928
1057
  connection.peer_address,
929
- HCI_REMOTE_USER_TERMINATED_CONNECTION_ERROR,
1058
+ lmp.LmpDetach(command.reason),
930
1059
  )
1060
+ self.on_classic_disconnected(connection.peer_address, command.reason)
931
1061
  else:
932
1062
  # Remove the connection
933
1063
  del self.classic_connections[connection.peer_address]
1064
+ elif sco_link := self.find_classic_sco_link_by_handle(handle):
1065
+ if self.link:
1066
+ if (
1067
+ sco_link.link_type
1068
+ == hci.HCI_Connection_Complete_Event.LinkType.ESCO
1069
+ ):
1070
+ self.send_lmp_packet(
1071
+ sco_link.peer_address,
1072
+ lmp.LmpRemoveScoLinkReq(
1073
+ sco_handle=0, error_code=command.reason
1074
+ ),
1075
+ )
1076
+ else:
1077
+ self.send_lmp_packet(
1078
+ sco_link.peer_address,
1079
+ lmp.LmpRemoveEscoLinkReq(
1080
+ esco_handle=0, error_code=command.reason
1081
+ ),
1082
+ )
1083
+ self.on_classic_sco_disconnected(sco_link.peer_address, command.reason)
1084
+ else:
1085
+ # Remove the connection
1086
+ del self.sco_links[sco_link.peer_address]
934
1087
  elif cis_link := (
935
1088
  self.central_cis_links.get(handle) or self.peripheral_cis_links.get(handle)
936
1089
  ):
@@ -954,14 +1107,71 @@ class Controller:
954
1107
 
955
1108
  if self.link is None:
956
1109
  return None
1110
+
1111
+ if not (connection := self.classic_connections.get(command.bd_addr)):
1112
+ self.send_hci_packet(
1113
+ hci.HCI_Command_Status_Event(
1114
+ status=hci.HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR,
1115
+ num_hci_command_packets=1,
1116
+ command_opcode=command.op_code,
1117
+ )
1118
+ )
1119
+ return None
957
1120
  self.send_hci_packet(
958
- HCI_Command_Status_Event(
959
- status=HCI_SUCCESS,
1121
+ hci.HCI_Command_Status_Event(
1122
+ status=hci.HCI_SUCCESS,
960
1123
  num_hci_command_packets=1,
961
1124
  command_opcode=command.op_code,
962
1125
  )
963
1126
  )
964
- self.link.classic_accept_connection(self, command.bd_addr, command.role)
1127
+
1128
+ if command.role == hci.Role.CENTRAL:
1129
+ # Perform role switching before accept.
1130
+ future = self.send_lmp_packet(command.bd_addr, lmp.LmpSwitchReq())
1131
+
1132
+ def on_response(future: asyncio.Future[int]):
1133
+ if (status := future.result()) == hci.HCI_SUCCESS:
1134
+ self.classic_role_change(connection)
1135
+ # Continue connection setup.
1136
+ self.send_lmp_packet(
1137
+ command.bd_addr,
1138
+ lmp.LmpAccepted(lmp.Opcode.LMP_HOST_CONNECTION_REQ),
1139
+ )
1140
+ else:
1141
+ # Abort connection setup.
1142
+ self.send_lmp_packet(
1143
+ command.bd_addr,
1144
+ lmp.LmpNotAccepted(lmp.Opcode.LMP_HOST_CONNECTION_REQ, status),
1145
+ )
1146
+ self.on_classic_connection_complete(command.bd_addr, status)
1147
+
1148
+ future.add_done_callback(on_response)
1149
+
1150
+ else:
1151
+ # Simply accept connection.
1152
+ self.send_lmp_packet(
1153
+ command.bd_addr,
1154
+ lmp.LmpAccepted(lmp.Opcode.LMP_HOST_CONNECTION_REQ),
1155
+ )
1156
+ self.on_classic_connection_complete(command.bd_addr, hci.HCI_SUCCESS)
1157
+ return None
1158
+
1159
+ def on_hci_remote_name_request_command(
1160
+ self, command: hci.HCI_Remote_Name_Request_Command
1161
+ ) -> Optional[bytes]:
1162
+ '''
1163
+ See Bluetooth spec Vol 4, Part E - 7.1.19 Remote Name Request command
1164
+ '''
1165
+ self.send_hci_packet(
1166
+ hci.HCI_Command_Status_Event(
1167
+ status=hci.HCI_SUCCESS,
1168
+ num_hci_command_packets=1,
1169
+ command_opcode=command.op_code,
1170
+ )
1171
+ )
1172
+
1173
+ self.send_lmp_packet(command.bd_addr, lmp.LmpNameReq(0))
1174
+
965
1175
  return None
966
1176
 
967
1177
  def on_hci_enhanced_setup_synchronous_connection_command(
@@ -980,8 +1190,8 @@ class Controller:
980
1190
  )
981
1191
  ):
982
1192
  self.send_hci_packet(
983
- HCI_Command_Status_Event(
984
- status=HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR,
1193
+ hci.HCI_Command_Status_Event(
1194
+ status=hci.HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR,
985
1195
  num_hci_command_packets=1,
986
1196
  command_opcode=command.op_code,
987
1197
  )
@@ -989,15 +1199,38 @@ class Controller:
989
1199
  return None
990
1200
 
991
1201
  self.send_hci_packet(
992
- HCI_Command_Status_Event(
993
- status=HCI_SUCCESS,
1202
+ hci.HCI_Command_Status_Event(
1203
+ status=hci.HCI_SUCCESS,
994
1204
  num_hci_command_packets=1,
995
1205
  command_opcode=command.op_code,
996
1206
  )
997
1207
  )
998
- self.link.classic_sco_connect(
999
- self, connection.peer_address, HCI_Connection_Complete_Event.LinkType.ESCO
1208
+ future = self.send_lmp_packet(
1209
+ connection.peer_address,
1210
+ lmp.LmpEscoLinkReq(
1211
+ esco_handle=0,
1212
+ esco_lt_addr=0,
1213
+ timing_control_flags=0,
1214
+ d_esco=0,
1215
+ t_esco=0,
1216
+ w_esco=0,
1217
+ esco_packet_type_c_to_p=0,
1218
+ esco_packet_type_p_to_c=0,
1219
+ packet_length_c_to_p=0,
1220
+ packet_length_p_to_c=0,
1221
+ air_mode=0,
1222
+ negotiation_state=0,
1223
+ ),
1000
1224
  )
1225
+
1226
+ def on_response(future: asyncio.Future[int]):
1227
+ self.on_classic_sco_connection_complete(
1228
+ connection.peer_address,
1229
+ future.result(),
1230
+ hci.HCI_Connection_Complete_Event.LinkType.ESCO,
1231
+ )
1232
+
1233
+ future.add_done_callback(on_response)
1001
1234
  return None
1002
1235
 
1003
1236
  def on_hci_enhanced_accept_synchronous_connection_request_command(
@@ -1012,8 +1245,8 @@ class Controller:
1012
1245
 
1013
1246
  if not (connection := self.find_classic_connection_by_address(command.bd_addr)):
1014
1247
  self.send_hci_packet(
1015
- HCI_Command_Status_Event(
1016
- status=HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR,
1248
+ hci.HCI_Command_Status_Event(
1249
+ status=hci.HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR,
1017
1250
  num_hci_command_packets=1,
1018
1251
  command_opcode=command.op_code,
1019
1252
  )
@@ -1021,14 +1254,20 @@ class Controller:
1021
1254
  return None
1022
1255
 
1023
1256
  self.send_hci_packet(
1024
- HCI_Command_Status_Event(
1025
- status=HCI_SUCCESS,
1257
+ hci.HCI_Command_Status_Event(
1258
+ status=hci.HCI_SUCCESS,
1026
1259
  num_hci_command_packets=1,
1027
1260
  command_opcode=command.op_code,
1028
1261
  )
1029
1262
  )
1030
- self.link.classic_accept_sco_connection(
1031
- self, connection.peer_address, HCI_Connection_Complete_Event.LinkType.ESCO
1263
+ self.send_lmp_packet(
1264
+ connection.peer_address,
1265
+ lmp.LmpAcceptedExt(lmp.Opcode.LMP_ESCO_LINK_REQ),
1266
+ )
1267
+ self.on_classic_sco_connection_complete(
1268
+ connection.peer_address,
1269
+ hci.HCI_SUCCESS,
1270
+ hci.HCI_Connection_Complete_Event.LinkType.ESCO,
1032
1271
  )
1033
1272
  return None
1034
1273
 
@@ -1050,14 +1289,14 @@ class Controller:
1050
1289
 
1051
1290
  self.send_hci_packet(
1052
1291
  hci.HCI_Command_Status_Event(
1053
- status=HCI_SUCCESS,
1292
+ status=hci.HCI_SUCCESS,
1054
1293
  num_hci_command_packets=1,
1055
1294
  command_opcode=command.op_code,
1056
1295
  )
1057
1296
  )
1058
1297
  self.send_hci_packet(
1059
1298
  hci.HCI_Mode_Change_Event(
1060
- status=HCI_SUCCESS,
1299
+ status=hci.HCI_SUCCESS,
1061
1300
  connection_handle=command.connection_handle,
1062
1301
  current_mode=hci.HCI_Mode_Change_Event.Mode.SNIFF,
1063
1302
  interval=2,
@@ -1084,14 +1323,14 @@ class Controller:
1084
1323
 
1085
1324
  self.send_hci_packet(
1086
1325
  hci.HCI_Command_Status_Event(
1087
- status=HCI_SUCCESS,
1326
+ status=hci.HCI_SUCCESS,
1088
1327
  num_hci_command_packets=1,
1089
1328
  command_opcode=command.op_code,
1090
1329
  )
1091
1330
  )
1092
1331
  self.send_hci_packet(
1093
1332
  hci.HCI_Mode_Change_Event(
1094
- status=HCI_SUCCESS,
1333
+ status=hci.HCI_SUCCESS,
1095
1334
  connection_handle=command.connection_handle,
1096
1335
  current_mode=hci.HCI_Mode_Change_Event.Mode.ACTIVE,
1097
1336
  interval=2,
@@ -1103,19 +1342,57 @@ class Controller:
1103
1342
  self, command: hci.HCI_Switch_Role_Command
1104
1343
  ) -> Optional[bytes]:
1105
1344
  '''
1106
- See Bluetooth spec Vol 4, Part E - 7.2.8 Switch Role command
1345
+ See Bluetooth spec Vol 4, Part E - 7.2.8 Switch hci.Role command
1107
1346
  '''
1108
1347
 
1109
1348
  if self.link is None:
1110
1349
  return None
1111
- self.send_hci_packet(
1112
- HCI_Command_Status_Event(
1113
- status=HCI_SUCCESS,
1114
- num_hci_command_packets=1,
1115
- command_opcode=command.op_code,
1350
+
1351
+ if connection := self.classic_connections.get(command.bd_addr):
1352
+ current_role = connection.role
1353
+ self.send_hci_packet(
1354
+ hci.HCI_Command_Status_Event(
1355
+ status=hci.HCI_SUCCESS,
1356
+ num_hci_command_packets=1,
1357
+ command_opcode=command.op_code,
1358
+ )
1116
1359
  )
1117
- )
1118
- self.link.classic_switch_role(self, command.bd_addr, command.role)
1360
+ else:
1361
+ # Connection doesn't exist, reject.
1362
+ self.send_hci_packet(
1363
+ hci.HCI_Command_Status_Event(
1364
+ status=hci.HCI_COMMAND_DISALLOWED_ERROR,
1365
+ num_hci_command_packets=1,
1366
+ command_opcode=command.op_code,
1367
+ )
1368
+ )
1369
+ return None
1370
+
1371
+ # If role doesn't change, only send event to local host.
1372
+ if current_role == command.role:
1373
+ self.send_hci_packet(
1374
+ hci.HCI_Role_Change_Event(
1375
+ status=hci.HCI_SUCCESS,
1376
+ bd_addr=command.bd_addr,
1377
+ new_role=current_role,
1378
+ )
1379
+ )
1380
+ else:
1381
+ future = self.send_lmp_packet(command.bd_addr, lmp.LmpSwitchReq())
1382
+
1383
+ def on_response(future: asyncio.Future[int]):
1384
+ if (status := future.result()) == hci.HCI_SUCCESS:
1385
+ connection.role = hci.Role(command.role)
1386
+ self.send_hci_packet(
1387
+ hci.HCI_Role_Change_Event(
1388
+ status=status,
1389
+ bd_addr=command.bd_addr,
1390
+ new_role=connection.role,
1391
+ )
1392
+ )
1393
+
1394
+ future.add_done_callback(on_response)
1395
+
1119
1396
  return None
1120
1397
 
1121
1398
  def on_hci_set_event_mask_command(
@@ -1127,14 +1404,14 @@ class Controller:
1127
1404
  self.event_mask = int.from_bytes(
1128
1405
  command.event_mask, byteorder='little', signed=False
1129
1406
  )
1130
- return bytes([HCI_SUCCESS])
1407
+ return bytes([hci.HCI_SUCCESS])
1131
1408
 
1132
1409
  def on_hci_reset_command(self, _command: hci.HCI_Reset_Command) -> Optional[bytes]:
1133
1410
  '''
1134
1411
  See Bluetooth spec Vol 4, Part E - 7.3.2 Reset Command
1135
1412
  '''
1136
1413
  # TODO: cleanup what needs to be reset
1137
- return bytes([HCI_SUCCESS])
1414
+ return bytes([hci.HCI_SUCCESS])
1138
1415
 
1139
1416
  def on_hci_write_local_name_command(
1140
1417
  self, command: hci.HCI_Write_Local_Name_Command
@@ -1151,7 +1428,7 @@ class Controller:
1151
1428
  self.local_name = str(local_name, 'utf-8')
1152
1429
  except UnicodeDecodeError:
1153
1430
  pass
1154
- return bytes([HCI_SUCCESS])
1431
+ return bytes([hci.HCI_SUCCESS])
1155
1432
 
1156
1433
  def on_hci_read_local_name_command(
1157
1434
  self, _command: hci.HCI_Read_Local_Name_Command
@@ -1163,7 +1440,7 @@ class Controller:
1163
1440
  if len(local_name) < 248:
1164
1441
  local_name = local_name + bytes(248 - len(local_name))
1165
1442
 
1166
- return bytes([HCI_SUCCESS]) + local_name
1443
+ return bytes([hci.HCI_SUCCESS]) + local_name
1167
1444
 
1168
1445
  def on_hci_read_class_of_device_command(
1169
1446
  self, _command: hci.HCI_Read_Class_Of_Device_Command
@@ -1171,7 +1448,7 @@ class Controller:
1171
1448
  '''
1172
1449
  See Bluetooth spec Vol 4, Part E - 7.3.25 Read Class of Device Command
1173
1450
  '''
1174
- return bytes([HCI_SUCCESS, 0, 0, 0])
1451
+ return bytes([hci.HCI_SUCCESS, 0, 0, 0])
1175
1452
 
1176
1453
  def on_hci_write_class_of_device_command(
1177
1454
  self, _command: hci.HCI_Write_Class_Of_Device_Command
@@ -1179,7 +1456,7 @@ class Controller:
1179
1456
  '''
1180
1457
  See Bluetooth spec Vol 4, Part E - 7.3.26 Write Class of Device Command
1181
1458
  '''
1182
- return bytes([HCI_SUCCESS])
1459
+ return bytes([hci.HCI_SUCCESS])
1183
1460
 
1184
1461
  def on_hci_read_synchronous_flow_control_enable_command(
1185
1462
  self, _command: hci.HCI_Read_Synchronous_Flow_Control_Enable_Command
@@ -1192,7 +1469,7 @@ class Controller:
1192
1469
  ret = 1
1193
1470
  else:
1194
1471
  ret = 0
1195
- return bytes([HCI_SUCCESS, ret])
1472
+ return bytes([hci.HCI_SUCCESS, ret])
1196
1473
 
1197
1474
  def on_hci_write_synchronous_flow_control_enable_command(
1198
1475
  self, command: hci.HCI_Write_Synchronous_Flow_Control_Enable_Command
@@ -1201,13 +1478,13 @@ class Controller:
1201
1478
  See Bluetooth spec Vol 4, Part E - 7.3.37 Write Synchronous Flow Control Enable
1202
1479
  Command
1203
1480
  '''
1204
- ret = HCI_SUCCESS
1481
+ ret = hci.HCI_SUCCESS
1205
1482
  if command.synchronous_flow_control_enable == 1:
1206
1483
  self.sync_flow_control = True
1207
1484
  elif command.synchronous_flow_control_enable == 0:
1208
1485
  self.sync_flow_control = False
1209
1486
  else:
1210
- ret = HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR
1487
+ ret = hci.HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR
1211
1488
  return bytes([ret])
1212
1489
 
1213
1490
  def on_hci_set_controller_to_host_flow_control_command(
@@ -1219,7 +1496,7 @@ class Controller:
1219
1496
  '''
1220
1497
  # For now we just accept the command but ignore the values.
1221
1498
  # TODO: respect the passed in values.
1222
- return bytes([HCI_SUCCESS])
1499
+ return bytes([hci.HCI_SUCCESS])
1223
1500
 
1224
1501
  def on_hci_host_buffer_size_command(
1225
1502
  self, _command: hci.HCI_Host_Buffer_Size_Command
@@ -1229,7 +1506,7 @@ class Controller:
1229
1506
  '''
1230
1507
  # For now we just accept the command but ignore the values.
1231
1508
  # TODO: respect the passed in values.
1232
- return bytes([HCI_SUCCESS])
1509
+ return bytes([hci.HCI_SUCCESS])
1233
1510
 
1234
1511
  def on_hci_write_extended_inquiry_response_command(
1235
1512
  self, _command: hci.HCI_Write_Extended_Inquiry_Response_Command
@@ -1238,7 +1515,7 @@ class Controller:
1238
1515
  See Bluetooth spec Vol 4, Part E - 7.3.56 Write Extended Inquiry Response
1239
1516
  Command
1240
1517
  '''
1241
- return bytes([HCI_SUCCESS])
1518
+ return bytes([hci.HCI_SUCCESS])
1242
1519
 
1243
1520
  def on_hci_write_simple_pairing_mode_command(
1244
1521
  self, _command: hci.HCI_Write_Simple_Pairing_Mode_Command
@@ -1246,7 +1523,7 @@ class Controller:
1246
1523
  '''
1247
1524
  See Bluetooth spec Vol 4, Part E - 7.3.59 Write Simple Pairing Mode Command
1248
1525
  '''
1249
- return bytes([HCI_SUCCESS])
1526
+ return bytes([hci.HCI_SUCCESS])
1250
1527
 
1251
1528
  def on_hci_set_event_mask_page_2_command(
1252
1529
  self, command: hci.HCI_Set_Event_Mask_Page_2_Command
@@ -1257,7 +1534,7 @@ class Controller:
1257
1534
  self.event_mask_page_2 = int.from_bytes(
1258
1535
  command.event_mask_page_2, byteorder='little', signed=False
1259
1536
  )
1260
- return bytes([HCI_SUCCESS])
1537
+ return bytes([hci.HCI_SUCCESS])
1261
1538
 
1262
1539
  def on_hci_read_le_host_support_command(
1263
1540
  self, _command: hci.HCI_Read_LE_Host_Support_Command
@@ -1265,7 +1542,7 @@ class Controller:
1265
1542
  '''
1266
1543
  See Bluetooth spec Vol 4, Part E - 7.3.78 Write LE Host Support Command
1267
1544
  '''
1268
- return bytes([HCI_SUCCESS, 1, 0])
1545
+ return bytes([hci.HCI_SUCCESS, 1, 0])
1269
1546
 
1270
1547
  def on_hci_write_le_host_support_command(
1271
1548
  self, _command: hci.HCI_Write_LE_Host_Support_Command
@@ -1274,7 +1551,7 @@ class Controller:
1274
1551
  See Bluetooth spec Vol 4, Part E - 7.3.79 Write LE Host Support Command
1275
1552
  '''
1276
1553
  # TODO / Just ignore for now
1277
- return bytes([HCI_SUCCESS])
1554
+ return bytes([hci.HCI_SUCCESS])
1278
1555
 
1279
1556
  def on_hci_write_authenticated_payload_timeout_command(
1280
1557
  self, command: hci.HCI_Write_Authenticated_Payload_Timeout_Command
@@ -1284,7 +1561,7 @@ class Controller:
1284
1561
  Command
1285
1562
  '''
1286
1563
  # TODO
1287
- return struct.pack('<BH', HCI_SUCCESS, command.connection_handle)
1564
+ return struct.pack('<BH', hci.HCI_SUCCESS, command.connection_handle)
1288
1565
 
1289
1566
  def on_hci_read_local_version_information_command(
1290
1567
  self, _command: hci.HCI_Read_Local_Version_Information_Command
@@ -1294,7 +1571,7 @@ class Controller:
1294
1571
  '''
1295
1572
  return struct.pack(
1296
1573
  '<BBHBHH',
1297
- HCI_SUCCESS,
1574
+ hci.HCI_SUCCESS,
1298
1575
  self.hci_version,
1299
1576
  self.hci_revision,
1300
1577
  self.lmp_version,
@@ -1308,7 +1585,7 @@ class Controller:
1308
1585
  '''
1309
1586
  See Bluetooth spec Vol 4, Part E - 7.4.2 Read Local Supported Commands Command
1310
1587
  '''
1311
- return bytes([HCI_SUCCESS]) + self.supported_commands
1588
+ return bytes([hci.HCI_SUCCESS]) + self.supported_commands
1312
1589
 
1313
1590
  def on_hci_read_local_supported_features_command(
1314
1591
  self, _command: hci.HCI_Read_Local_Supported_Features_Command
@@ -1316,7 +1593,7 @@ class Controller:
1316
1593
  '''
1317
1594
  See Bluetooth spec Vol 4, Part E - 7.4.3 Read Local Supported Features Command
1318
1595
  '''
1319
- return bytes([HCI_SUCCESS]) + self.lmp_features[:8]
1596
+ return bytes([hci.HCI_SUCCESS]) + self.lmp_features[:8]
1320
1597
 
1321
1598
  def on_hci_read_local_extended_features_command(
1322
1599
  self, command: hci.HCI_Read_Local_Extended_Features_Command
@@ -1325,12 +1602,12 @@ class Controller:
1325
1602
  See Bluetooth spec Vol 4, Part E - 7.4.4 Read Local Extended Features Command
1326
1603
  '''
1327
1604
  if command.page_number * 8 > len(self.lmp_features):
1328
- return bytes([HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
1605
+ return bytes([hci.HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
1329
1606
  return (
1330
1607
  bytes(
1331
1608
  [
1332
1609
  # Status
1333
- HCI_SUCCESS,
1610
+ hci.HCI_SUCCESS,
1334
1611
  # Page number
1335
1612
  command.page_number,
1336
1613
  # Max page number
@@ -1349,7 +1626,7 @@ class Controller:
1349
1626
  '''
1350
1627
  return struct.pack(
1351
1628
  '<BHBHH',
1352
- HCI_SUCCESS,
1629
+ hci.HCI_SUCCESS,
1353
1630
  self.acl_data_packet_length,
1354
1631
  0,
1355
1632
  self.total_num_acl_data_packets,
@@ -1367,7 +1644,7 @@ class Controller:
1367
1644
  if self._public_address is not None
1368
1645
  else bytes(6)
1369
1646
  )
1370
- return bytes([HCI_SUCCESS]) + bd_addr
1647
+ return bytes([hci.HCI_SUCCESS]) + bd_addr
1371
1648
 
1372
1649
  def on_hci_le_set_default_subrate_command(
1373
1650
  self, command: hci.HCI_LE_Set_Default_Subrate_Command
@@ -1381,9 +1658,9 @@ class Controller:
1381
1658
  or command.subrate_max < command.subrate_min
1382
1659
  or command.continuation_number >= command.subrate_max
1383
1660
  ):
1384
- return bytes([HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
1661
+ return bytes([hci.HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
1385
1662
 
1386
- return bytes([HCI_SUCCESS])
1663
+ return bytes([hci.HCI_SUCCESS])
1387
1664
 
1388
1665
  def on_hci_le_subrate_request_command(
1389
1666
  self, command: hci.HCI_LE_Subrate_Request_Command
@@ -1397,7 +1674,7 @@ class Controller:
1397
1674
  or command.subrate_max < command.subrate_min
1398
1675
  or command.continuation_number >= command.subrate_max
1399
1676
  ):
1400
- return bytes([HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
1677
+ return bytes([hci.HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
1401
1678
 
1402
1679
  self.send_hci_packet(
1403
1680
  hci.HCI_Command_Status_Event(
@@ -1428,7 +1705,7 @@ class Controller:
1428
1705
  self.le_event_mask = int.from_bytes(
1429
1706
  command.le_event_mask, byteorder='little', signed=False
1430
1707
  )
1431
- return bytes([HCI_SUCCESS])
1708
+ return bytes([hci.HCI_SUCCESS])
1432
1709
 
1433
1710
  def on_hci_le_read_buffer_size_command(
1434
1711
  self, _command: hci.HCI_LE_Read_Buffer_Size_Command
@@ -1438,7 +1715,7 @@ class Controller:
1438
1715
  '''
1439
1716
  return struct.pack(
1440
1717
  '<BHB',
1441
- HCI_SUCCESS,
1718
+ hci.HCI_SUCCESS,
1442
1719
  self.le_acl_data_packet_length,
1443
1720
  self.total_num_le_acl_data_packets,
1444
1721
  )
@@ -1451,7 +1728,7 @@ class Controller:
1451
1728
  '''
1452
1729
  return struct.pack(
1453
1730
  '<BHBHB',
1454
- HCI_SUCCESS,
1731
+ hci.HCI_SUCCESS,
1455
1732
  self.le_acl_data_packet_length,
1456
1733
  self.total_num_le_acl_data_packets,
1457
1734
  self.iso_data_packet_length,
@@ -1465,16 +1742,16 @@ class Controller:
1465
1742
  See Bluetooth spec Vol 4, Part E - 7.8.3 LE Read Local Supported Features
1466
1743
  Command
1467
1744
  '''
1468
- return bytes([HCI_SUCCESS]) + self.le_features
1745
+ return bytes([hci.HCI_SUCCESS]) + self.le_features
1469
1746
 
1470
1747
  def on_hci_le_set_random_address_command(
1471
1748
  self, command: hci.HCI_LE_Set_Random_Address_Command
1472
1749
  ) -> Optional[bytes]:
1473
1750
  '''
1474
- See Bluetooth spec Vol 4, Part E - 7.8.4 LE Set Random Address Command
1751
+ See Bluetooth spec Vol 4, Part E - 7.8.4 LE Set Random hci.Address Command
1475
1752
  '''
1476
1753
  self.random_address = command.random_address
1477
- return bytes([HCI_SUCCESS])
1754
+ return bytes([hci.HCI_SUCCESS])
1478
1755
 
1479
1756
  def on_hci_le_set_advertising_parameters_command(
1480
1757
  self, command: hci.HCI_LE_Set_Advertising_Parameters_Command
@@ -1483,7 +1760,7 @@ class Controller:
1483
1760
  See Bluetooth spec Vol 4, Part E - 7.8.5 LE Set Advertising Parameters Command
1484
1761
  '''
1485
1762
  self.advertising_parameters = command
1486
- return bytes([HCI_SUCCESS])
1763
+ return bytes([hci.HCI_SUCCESS])
1487
1764
 
1488
1765
  def on_hci_le_read_advertising_physical_channel_tx_power_command(
1489
1766
  self, _command: hci.HCI_LE_Read_Advertising_Physical_Channel_Tx_Power_Command
@@ -1492,7 +1769,7 @@ class Controller:
1492
1769
  See Bluetooth spec Vol 4, Part E - 7.8.6 LE Read Advertising Physical Channel
1493
1770
  Tx Power Command
1494
1771
  '''
1495
- return bytes([HCI_SUCCESS, self.advertising_channel_tx_power])
1772
+ return bytes([hci.HCI_SUCCESS, self.advertising_channel_tx_power])
1496
1773
 
1497
1774
  def on_hci_le_set_advertising_data_command(
1498
1775
  self, command: hci.HCI_LE_Set_Advertising_Data_Command
@@ -1501,7 +1778,7 @@ class Controller:
1501
1778
  See Bluetooth spec Vol 4, Part E - 7.8.7 LE Set Advertising Data Command
1502
1779
  '''
1503
1780
  self.advertising_data = command.advertising_data
1504
- return bytes([HCI_SUCCESS])
1781
+ return bytes([hci.HCI_SUCCESS])
1505
1782
 
1506
1783
  def on_hci_le_set_scan_response_data_command(
1507
1784
  self, command: hci.HCI_LE_Set_Scan_Response_Data_Command
@@ -1510,7 +1787,7 @@ class Controller:
1510
1787
  See Bluetooth spec Vol 4, Part E - 7.8.8 LE Set Scan Response Data Command
1511
1788
  '''
1512
1789
  self.le_scan_response_data = command.scan_response_data
1513
- return bytes([HCI_SUCCESS])
1790
+ return bytes([hci.HCI_SUCCESS])
1514
1791
 
1515
1792
  def on_hci_le_set_advertising_enable_command(
1516
1793
  self, command: hci.HCI_LE_Set_Advertising_Enable_Command
@@ -1523,7 +1800,7 @@ class Controller:
1523
1800
  else:
1524
1801
  self.stop_advertising()
1525
1802
 
1526
- return bytes([HCI_SUCCESS])
1803
+ return bytes([hci.HCI_SUCCESS])
1527
1804
 
1528
1805
  def on_hci_le_set_scan_parameters_command(
1529
1806
  self, command: hci.HCI_LE_Set_Scan_Parameters_Command
@@ -1532,14 +1809,14 @@ class Controller:
1532
1809
  See Bluetooth spec Vol 4, Part E - 7.8.10 LE Set Scan Parameters Command
1533
1810
  '''
1534
1811
  if self.le_scan_enable:
1535
- return bytes([HCI_COMMAND_DISALLOWED_ERROR])
1812
+ return bytes([hci.HCI_COMMAND_DISALLOWED_ERROR])
1536
1813
 
1537
1814
  self.le_scan_type = command.le_scan_type
1538
1815
  self.le_scan_interval = command.le_scan_interval
1539
1816
  self.le_scan_window = command.le_scan_window
1540
1817
  self.le_scan_own_address_type = hci.AddressType(command.own_address_type)
1541
1818
  self.le_scanning_filter_policy = command.scanning_filter_policy
1542
- return bytes([HCI_SUCCESS])
1819
+ return bytes([hci.HCI_SUCCESS])
1543
1820
 
1544
1821
  def on_hci_le_set_scan_enable_command(
1545
1822
  self, command: hci.HCI_LE_Set_Scan_Enable_Command
@@ -1549,7 +1826,7 @@ class Controller:
1549
1826
  '''
1550
1827
  self.le_scan_enable = bool(command.le_scan_enable)
1551
1828
  self.filter_duplicates = bool(command.filter_duplicates)
1552
- return bytes([HCI_SUCCESS])
1829
+ return bytes([hci.HCI_SUCCESS])
1553
1830
 
1554
1831
  def on_hci_le_create_connection_command(
1555
1832
  self, command: hci.HCI_LE_Create_Connection_Command
@@ -1566,8 +1843,8 @@ class Controller:
1566
1843
  # Check that we don't already have a pending connection
1567
1844
  if self.link.get_pending_connection():
1568
1845
  self.send_hci_packet(
1569
- HCI_Command_Status_Event(
1570
- status=HCI_COMMAND_DISALLOWED_ERROR,
1846
+ hci.HCI_Command_Status_Event(
1847
+ status=hci.HCI_COMMAND_DISALLOWED_ERROR,
1571
1848
  num_hci_command_packets=1,
1572
1849
  command_opcode=command.op_code,
1573
1850
  )
@@ -1579,8 +1856,8 @@ class Controller:
1579
1856
 
1580
1857
  # Say that the connection is pending
1581
1858
  self.send_hci_packet(
1582
- HCI_Command_Status_Event(
1583
- status=HCI_COMMAND_STATUS_PENDING,
1859
+ hci.HCI_Command_Status_Event(
1860
+ status=hci.HCI_COMMAND_STATUS_PENDING,
1584
1861
  num_hci_command_packets=1,
1585
1862
  command_opcode=command.op_code,
1586
1863
  )
@@ -1593,7 +1870,7 @@ class Controller:
1593
1870
  '''
1594
1871
  See Bluetooth spec Vol 4, Part E - 7.8.13 LE Create Connection Cancel Command
1595
1872
  '''
1596
- return bytes([HCI_SUCCESS])
1873
+ return bytes([hci.HCI_SUCCESS])
1597
1874
 
1598
1875
  def on_hci_le_read_filter_accept_list_size_command(
1599
1876
  self, _command: hci.HCI_LE_Read_Filter_Accept_List_Size_Command
@@ -1602,7 +1879,7 @@ class Controller:
1602
1879
  See Bluetooth spec Vol 4, Part E - 7.8.14 LE Read Filter Accept List Size
1603
1880
  Command
1604
1881
  '''
1605
- return bytes([HCI_SUCCESS, self.filter_accept_list_size])
1882
+ return bytes([hci.HCI_SUCCESS, self.filter_accept_list_size])
1606
1883
 
1607
1884
  def on_hci_le_clear_filter_accept_list_command(
1608
1885
  self, _command: hci.HCI_LE_Clear_Filter_Accept_List_Command
@@ -1610,7 +1887,7 @@ class Controller:
1610
1887
  '''
1611
1888
  See Bluetooth spec Vol 4, Part E - 7.8.15 LE Clear Filter Accept List Command
1612
1889
  '''
1613
- return bytes([HCI_SUCCESS])
1890
+ return bytes([hci.HCI_SUCCESS])
1614
1891
 
1615
1892
  def on_hci_le_add_device_to_filter_accept_list_command(
1616
1893
  self, _command: hci.HCI_LE_Add_Device_To_Filter_Accept_List_Command
@@ -1619,7 +1896,7 @@ class Controller:
1619
1896
  See Bluetooth spec Vol 4, Part E - 7.8.16 LE Add Device To Filter Accept List
1620
1897
  Command
1621
1898
  '''
1622
- return bytes([HCI_SUCCESS])
1899
+ return bytes([hci.HCI_SUCCESS])
1623
1900
 
1624
1901
  def on_hci_le_remove_device_from_filter_accept_list_command(
1625
1902
  self, _command: hci.HCI_LE_Remove_Device_From_Filter_Accept_List_Command
@@ -1628,7 +1905,16 @@ class Controller:
1628
1905
  See Bluetooth spec Vol 4, Part E - 7.8.17 LE Remove Device From Filter Accept
1629
1906
  List Command
1630
1907
  '''
1631
- return bytes([HCI_SUCCESS])
1908
+ return bytes([hci.HCI_SUCCESS])
1909
+
1910
+ def on_hci_write_scan_enable_command(
1911
+ self, command: hci.HCI_Write_Scan_Enable_Command
1912
+ ) -> Optional[bytes]:
1913
+ '''
1914
+ See Bluetooth spec Vol 4, Part E - 7.3.18 Write Scan Enable Command
1915
+ '''
1916
+ self.classic_scan_enable = command.scan_enable
1917
+ return bytes([hci.HCI_SUCCESS])
1632
1918
 
1633
1919
  def on_hci_le_read_remote_features_command(
1634
1920
  self, command: hci.HCI_LE_Read_Remote_Features_Command
@@ -1641,8 +1927,8 @@ class Controller:
1641
1927
 
1642
1928
  if not self.find_connection_by_handle(handle):
1643
1929
  self.send_hci_packet(
1644
- HCI_Command_Status_Event(
1645
- status=HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR,
1930
+ hci.HCI_Command_Status_Event(
1931
+ status=hci.HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR,
1646
1932
  num_hci_command_packets=1,
1647
1933
  command_opcode=command.op_code,
1648
1934
  )
@@ -1651,8 +1937,8 @@ class Controller:
1651
1937
 
1652
1938
  # First, say that the command is pending
1653
1939
  self.send_hci_packet(
1654
- HCI_Command_Status_Event(
1655
- status=HCI_COMMAND_STATUS_PENDING,
1940
+ hci.HCI_Command_Status_Event(
1941
+ status=hci.HCI_COMMAND_STATUS_PENDING,
1656
1942
  num_hci_command_packets=1,
1657
1943
  command_opcode=command.op_code,
1658
1944
  )
@@ -1660,8 +1946,8 @@ class Controller:
1660
1946
 
1661
1947
  # Then send the remote features
1662
1948
  self.send_hci_packet(
1663
- HCI_LE_Read_Remote_Features_Complete_Event(
1664
- status=HCI_SUCCESS,
1949
+ hci.HCI_LE_Read_Remote_Features_Complete_Event(
1950
+ status=hci.HCI_SUCCESS,
1665
1951
  connection_handle=handle,
1666
1952
  le_features=bytes.fromhex('dd40000000000000'),
1667
1953
  )
@@ -1674,7 +1960,7 @@ class Controller:
1674
1960
  '''
1675
1961
  See Bluetooth spec Vol 4, Part E - 7.8.23 LE Rand Command
1676
1962
  '''
1677
- return bytes([HCI_SUCCESS]) + struct.pack('Q', random.randint(0, 1 << 64))
1963
+ return bytes([hci.HCI_SUCCESS]) + struct.pack('Q', random.randint(0, 1 << 64))
1678
1964
 
1679
1965
  def on_hci_le_enable_encryption_command(
1680
1966
  self, command: hci.HCI_LE_Enable_Encryption_Command
@@ -1692,7 +1978,7 @@ class Controller:
1692
1978
  )
1693
1979
  ):
1694
1980
  logger.warning('connection not found')
1695
- return bytes([HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
1981
+ return bytes([hci.HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
1696
1982
 
1697
1983
  # Notify that the connection is now encrypted
1698
1984
  self.link.on_connection_encrypted(
@@ -1704,8 +1990,8 @@ class Controller:
1704
1990
  )
1705
1991
 
1706
1992
  self.send_hci_packet(
1707
- HCI_Command_Status_Event(
1708
- status=HCI_COMMAND_STATUS_PENDING,
1993
+ hci.HCI_Command_Status_Event(
1994
+ status=hci.HCI_COMMAND_STATUS_PENDING,
1709
1995
  num_hci_command_packets=1,
1710
1996
  command_opcode=command.op_code,
1711
1997
  )
@@ -1719,7 +2005,7 @@ class Controller:
1719
2005
  '''
1720
2006
  See Bluetooth spec Vol 4, Part E - 7.8.27 LE Read Supported States Command
1721
2007
  '''
1722
- return bytes([HCI_SUCCESS]) + self.le_states
2008
+ return bytes([hci.HCI_SUCCESS]) + self.le_states
1723
2009
 
1724
2010
  def on_hci_le_read_suggested_default_data_length_command(
1725
2011
  self, _command: hci.HCI_LE_Read_Suggested_Default_Data_Length_Command
@@ -1730,7 +2016,7 @@ class Controller:
1730
2016
  '''
1731
2017
  return struct.pack(
1732
2018
  '<BHH',
1733
- HCI_SUCCESS,
2019
+ hci.HCI_SUCCESS,
1734
2020
  self.suggested_max_tx_octets,
1735
2021
  self.suggested_max_tx_time,
1736
2022
  )
@@ -1745,7 +2031,7 @@ class Controller:
1745
2031
  self.suggested_max_tx_octets, self.suggested_max_tx_time = struct.unpack(
1746
2032
  '<HH', command.parameters[:4]
1747
2033
  )
1748
- return bytes([HCI_SUCCESS])
2034
+ return bytes([hci.HCI_SUCCESS])
1749
2035
 
1750
2036
  def on_hci_le_read_local_p_256_public_key_command(
1751
2037
  self, _command: hci.HCI_LE_Read_Local_P_256_Public_Key_Command
@@ -1753,8 +2039,8 @@ class Controller:
1753
2039
  '''
1754
2040
  See Bluetooth spec Vol 4, Part E - 7.8.36 LE Read P-256 Public Key Command
1755
2041
  '''
1756
- # TODO create key and send HCI_LE_Read_Local_P-256_Public_Key_Complete event
1757
- return bytes([HCI_SUCCESS])
2042
+ # TODO create key and send hci.HCI_LE_Read_Local_P-256_Public_Key_Complete event
2043
+ return bytes([hci.HCI_SUCCESS])
1758
2044
 
1759
2045
  def on_hci_le_add_device_to_resolving_list_command(
1760
2046
  self, _command: hci.HCI_LE_Add_Device_To_Resolving_List_Command
@@ -1763,7 +2049,7 @@ class Controller:
1763
2049
  See Bluetooth spec Vol 4, Part E - 7.8.38 LE Add Device To Resolving List
1764
2050
  Command
1765
2051
  '''
1766
- return bytes([HCI_SUCCESS])
2052
+ return bytes([hci.HCI_SUCCESS])
1767
2053
 
1768
2054
  def on_hci_le_clear_resolving_list_command(
1769
2055
  self, _command: hci.HCI_LE_Clear_Resolving_List_Command
@@ -1771,7 +2057,7 @@ class Controller:
1771
2057
  '''
1772
2058
  See Bluetooth spec Vol 4, Part E - 7.8.40 LE Clear Resolving List Command
1773
2059
  '''
1774
- return bytes([HCI_SUCCESS])
2060
+ return bytes([hci.HCI_SUCCESS])
1775
2061
 
1776
2062
  def on_hci_le_read_resolving_list_size_command(
1777
2063
  self, _command: hci.HCI_LE_Read_Resolving_List_Size_Command
@@ -1779,33 +2065,33 @@ class Controller:
1779
2065
  '''
1780
2066
  See Bluetooth spec Vol 4, Part E - 7.8.41 LE Read Resolving List Size Command
1781
2067
  '''
1782
- return bytes([HCI_SUCCESS, self.resolving_list_size])
2068
+ return bytes([hci.HCI_SUCCESS, self.resolving_list_size])
1783
2069
 
1784
2070
  def on_hci_le_set_address_resolution_enable_command(
1785
2071
  self, command: hci.HCI_LE_Set_Address_Resolution_Enable_Command
1786
2072
  ) -> Optional[bytes]:
1787
2073
  '''
1788
- See Bluetooth spec Vol 4, Part E - 7.8.44 LE Set Address Resolution Enable
2074
+ See Bluetooth spec Vol 4, Part E - 7.8.44 LE Set hci.Address Resolution Enable
1789
2075
  Command
1790
2076
  '''
1791
- ret = HCI_SUCCESS
2077
+ ret = hci.HCI_SUCCESS
1792
2078
  if command.address_resolution_enable == 1:
1793
2079
  self.le_address_resolution = True
1794
2080
  elif command.address_resolution_enable == 0:
1795
2081
  self.le_address_resolution = False
1796
2082
  else:
1797
- ret = HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR
2083
+ ret = hci.HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR
1798
2084
  return bytes([ret])
1799
2085
 
1800
2086
  def on_hci_le_set_resolvable_private_address_timeout_command(
1801
2087
  self, command: hci.HCI_LE_Set_Resolvable_Private_Address_Timeout_Command
1802
2088
  ) -> Optional[bytes]:
1803
2089
  '''
1804
- See Bluetooth spec Vol 4, Part E - 7.8.45 LE Set Resolvable Private Address
2090
+ See Bluetooth spec Vol 4, Part E - 7.8.45 LE Set Resolvable Private hci.Address
1805
2091
  Timeout Command
1806
2092
  '''
1807
2093
  self.le_rpa_timeout = command.rpa_timeout
1808
- return bytes([HCI_SUCCESS])
2094
+ return bytes([hci.HCI_SUCCESS])
1809
2095
 
1810
2096
  def on_hci_le_read_maximum_data_length_command(
1811
2097
  self, _command: hci.HCI_LE_Read_Maximum_Data_Length_Command
@@ -1815,7 +2101,7 @@ class Controller:
1815
2101
  '''
1816
2102
  return struct.pack(
1817
2103
  '<BHHHH',
1818
- HCI_SUCCESS,
2104
+ hci.HCI_SUCCESS,
1819
2105
  self.supported_max_tx_octets,
1820
2106
  self.supported_max_tx_time,
1821
2107
  self.supported_max_rx_octets,
@@ -1830,10 +2116,10 @@ class Controller:
1830
2116
  '''
1831
2117
  return struct.pack(
1832
2118
  '<BHBB',
1833
- HCI_SUCCESS,
2119
+ hci.HCI_SUCCESS,
1834
2120
  command.connection_handle,
1835
- HCI_LE_1M_PHY,
1836
- HCI_LE_1M_PHY,
2121
+ hci.HCI_LE_1M_PHY,
2122
+ hci.HCI_LE_1M_PHY,
1837
2123
  )
1838
2124
 
1839
2125
  def on_hci_le_set_default_phy_command(
@@ -1845,16 +2131,16 @@ class Controller:
1845
2131
  self.default_phy['all_phys'] = command.all_phys
1846
2132
  self.default_phy['tx_phys'] = command.tx_phys
1847
2133
  self.default_phy['rx_phys'] = command.rx_phys
1848
- return bytes([HCI_SUCCESS])
2134
+ return bytes([hci.HCI_SUCCESS])
1849
2135
 
1850
2136
  def on_hci_le_set_advertising_set_random_address_command(
1851
2137
  self, _command: hci.HCI_LE_Set_Advertising_Set_Random_Address_Command
1852
2138
  ) -> Optional[bytes]:
1853
2139
  '''
1854
- See Bluetooth spec Vol 4, Part E - 7.8.52 LE Set Advertising Set Random Address
2140
+ See Bluetooth spec Vol 4, Part E - 7.8.52 LE Set Advertising Set Random hci.Address
1855
2141
  Command
1856
2142
  '''
1857
- return bytes([HCI_SUCCESS])
2143
+ return bytes([hci.HCI_SUCCESS])
1858
2144
 
1859
2145
  def on_hci_le_set_extended_advertising_parameters_command(
1860
2146
  self, _command: hci.HCI_LE_Set_Extended_Advertising_Parameters_Command
@@ -1863,7 +2149,7 @@ class Controller:
1863
2149
  See Bluetooth spec Vol 4, Part E - 7.8.53 LE Set Extended Advertising Parameters
1864
2150
  Command
1865
2151
  '''
1866
- return bytes([HCI_SUCCESS, 0])
2152
+ return bytes([hci.HCI_SUCCESS, 0])
1867
2153
 
1868
2154
  def on_hci_le_set_extended_advertising_data_command(
1869
2155
  self, _command: hci.HCI_LE_Set_Extended_Advertising_Data_Command
@@ -1872,7 +2158,7 @@ class Controller:
1872
2158
  See Bluetooth spec Vol 4, Part E - 7.8.54 LE Set Extended Advertising Data
1873
2159
  Command
1874
2160
  '''
1875
- return bytes([HCI_SUCCESS])
2161
+ return bytes([hci.HCI_SUCCESS])
1876
2162
 
1877
2163
  def on_hci_le_set_extended_scan_response_data_command(
1878
2164
  self, _command: hci.HCI_LE_Set_Extended_Scan_Response_Data_Command
@@ -1881,7 +2167,7 @@ class Controller:
1881
2167
  See Bluetooth spec Vol 4, Part E - 7.8.55 LE Set Extended Scan Response Data
1882
2168
  Command
1883
2169
  '''
1884
- return bytes([HCI_SUCCESS])
2170
+ return bytes([hci.HCI_SUCCESS])
1885
2171
 
1886
2172
  def on_hci_le_set_extended_advertising_enable_command(
1887
2173
  self, _command: hci.HCI_LE_Set_Extended_Advertising_Enable_Command
@@ -1890,7 +2176,7 @@ class Controller:
1890
2176
  See Bluetooth spec Vol 4, Part E - 7.8.56 LE Set Extended Advertising Enable
1891
2177
  Command
1892
2178
  '''
1893
- return bytes([HCI_SUCCESS])
2179
+ return bytes([hci.HCI_SUCCESS])
1894
2180
 
1895
2181
  def on_hci_le_read_maximum_advertising_data_length_command(
1896
2182
  self, _command: hci.HCI_LE_Read_Maximum_Advertising_Data_Length_Command
@@ -1899,7 +2185,7 @@ class Controller:
1899
2185
  See Bluetooth spec Vol 4, Part E - 7.8.57 LE Read Maximum Advertising Data
1900
2186
  Length Command
1901
2187
  '''
1902
- return struct.pack('<BH', HCI_SUCCESS, 0x0672)
2188
+ return struct.pack('<BH', hci.HCI_SUCCESS, 0x0672)
1903
2189
 
1904
2190
  def on_hci_le_read_number_of_supported_advertising_sets_command(
1905
2191
  self, _command: hci.HCI_LE_Read_Number_Of_Supported_Advertising_Sets_Command
@@ -1908,7 +2194,7 @@ class Controller:
1908
2194
  See Bluetooth spec Vol 4, Part E - 7.8.58 LE Read Number of Supported
1909
2195
  Advertising Set Command
1910
2196
  '''
1911
- return struct.pack('<BB', HCI_SUCCESS, 0xF0)
2197
+ return struct.pack('<BB', hci.HCI_SUCCESS, 0xF0)
1912
2198
 
1913
2199
  def on_hci_le_set_periodic_advertising_parameters_command(
1914
2200
  self, _command: hci.HCI_LE_Set_Periodic_Advertising_Parameters_Command
@@ -1917,7 +2203,7 @@ class Controller:
1917
2203
  See Bluetooth spec Vol 4, Part E - 7.8.61 LE Set Periodic Advertising Parameters
1918
2204
  Command
1919
2205
  '''
1920
- return bytes([HCI_SUCCESS])
2206
+ return bytes([hci.HCI_SUCCESS])
1921
2207
 
1922
2208
  def on_hci_le_set_periodic_advertising_data_command(
1923
2209
  self, _command: hci.HCI_LE_Set_Periodic_Advertising_Data_Command
@@ -1926,7 +2212,7 @@ class Controller:
1926
2212
  See Bluetooth spec Vol 4, Part E - 7.8.62 LE Set Periodic Advertising Data
1927
2213
  Command
1928
2214
  '''
1929
- return bytes([HCI_SUCCESS])
2215
+ return bytes([hci.HCI_SUCCESS])
1930
2216
 
1931
2217
  def on_hci_le_set_periodic_advertising_enable_command(
1932
2218
  self, _command: hci.HCI_LE_Set_Periodic_Advertising_Enable_Command
@@ -1935,7 +2221,7 @@ class Controller:
1935
2221
  See Bluetooth spec Vol 4, Part E - 7.8.63 LE Set Periodic Advertising Enable
1936
2222
  Command
1937
2223
  '''
1938
- return bytes([HCI_SUCCESS])
2224
+ return bytes([hci.HCI_SUCCESS])
1939
2225
 
1940
2226
  def on_hci_le_read_transmit_power_command(
1941
2227
  self, _command: hci.HCI_LE_Read_Transmit_Power_Command
@@ -1943,7 +2229,7 @@ class Controller:
1943
2229
  '''
1944
2230
  See Bluetooth spec Vol 4, Part E - 7.8.74 LE Read Transmit Power Command
1945
2231
  '''
1946
- return struct.pack('<BBB', HCI_SUCCESS, 0, 0)
2232
+ return struct.pack('<BBB', hci.HCI_SUCCESS, 0, 0)
1947
2233
 
1948
2234
  def on_hci_le_set_cig_parameters_command(
1949
2235
  self, command: hci.HCI_LE_Set_CIG_Parameters_Command
@@ -1968,7 +2254,7 @@ class Controller:
1968
2254
  handle=handle,
1969
2255
  )
1970
2256
  return struct.pack(
1971
- '<BBB', HCI_SUCCESS, command.cig_id, len(handles)
2257
+ '<BBB', hci.HCI_SUCCESS, command.cig_id, len(handles)
1972
2258
  ) + b''.join([struct.pack('<H', handle) for handle in handles])
1973
2259
 
1974
2260
  def on_hci_le_create_cis_command(
@@ -1985,11 +2271,11 @@ class Controller:
1985
2271
  ):
1986
2272
  if not (connection := self.find_connection_by_handle(acl_handle)):
1987
2273
  logger.error(f'Cannot find connection with handle={acl_handle}')
1988
- return bytes([HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
2274
+ return bytes([hci.HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
1989
2275
 
1990
2276
  if not (cis_link := self.central_cis_links.get(cis_handle)):
1991
2277
  logger.error(f'Cannot find CIS with handle={cis_handle}')
1992
- return bytes([HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
2278
+ return bytes([hci.HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
1993
2279
 
1994
2280
  cis_link.acl_connection = connection
1995
2281
 
@@ -2001,8 +2287,8 @@ class Controller:
2001
2287
  )
2002
2288
 
2003
2289
  self.send_hci_packet(
2004
- HCI_Command_Status_Event(
2005
- status=HCI_COMMAND_STATUS_PENDING,
2290
+ hci.HCI_Command_Status_Event(
2291
+ status=hci.HCI_COMMAND_STATUS_PENDING,
2006
2292
  num_hci_command_packets=1,
2007
2293
  command_opcode=command.op_code,
2008
2294
  )
@@ -2016,13 +2302,13 @@ class Controller:
2016
2302
  See Bluetooth spec Vol 4, Part E - 7.8.100 LE Remove CIG Command
2017
2303
  '''
2018
2304
 
2019
- status = HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR
2305
+ status = hci.HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR
2020
2306
 
2021
2307
  cis_links = list(self.central_cis_links.items())
2022
2308
  for cis_handle, cis_link in cis_links:
2023
2309
  if cis_link.cig_id == command.cig_id:
2024
2310
  self.central_cis_links.pop(cis_handle)
2025
- status = HCI_SUCCESS
2311
+ status = hci.HCI_SUCCESS
2026
2312
 
2027
2313
  return struct.pack('<BH', status, command.cig_id)
2028
2314
 
@@ -2039,7 +2325,7 @@ class Controller:
2039
2325
  pending_cis_link := self.peripheral_cis_links.get(command.connection_handle)
2040
2326
  ):
2041
2327
  logger.error(f'Cannot find CIS with handle={command.connection_handle}')
2042
- return bytes([HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
2328
+ return bytes([hci.HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
2043
2329
 
2044
2330
  assert pending_cis_link.acl_connection
2045
2331
  self.link.accept_cis(
@@ -2050,8 +2336,8 @@ class Controller:
2050
2336
  )
2051
2337
 
2052
2338
  self.send_hci_packet(
2053
- HCI_Command_Status_Event(
2054
- status=HCI_COMMAND_STATUS_PENDING,
2339
+ hci.HCI_Command_Status_Event(
2340
+ status=hci.HCI_COMMAND_STATUS_PENDING,
2055
2341
  num_hci_command_packets=1,
2056
2342
  command_opcode=command.op_code,
2057
2343
  )
@@ -2067,17 +2353,17 @@ class Controller:
2067
2353
  if not (iso_link := self.find_iso_link_by_handle(command.connection_handle)):
2068
2354
  return struct.pack(
2069
2355
  '<BH',
2070
- HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR,
2356
+ hci.HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR,
2071
2357
  command.connection_handle,
2072
2358
  )
2073
2359
  if command.data_path_direction in iso_link.data_paths:
2074
2360
  return struct.pack(
2075
2361
  '<BH',
2076
- HCI_COMMAND_DISALLOWED_ERROR,
2362
+ hci.HCI_COMMAND_DISALLOWED_ERROR,
2077
2363
  command.connection_handle,
2078
2364
  )
2079
2365
  iso_link.data_paths.add(command.data_path_direction)
2080
- return struct.pack('<BH', HCI_SUCCESS, command.connection_handle)
2366
+ return struct.pack('<BH', hci.HCI_SUCCESS, command.connection_handle)
2081
2367
 
2082
2368
  def on_hci_le_remove_iso_data_path_command(
2083
2369
  self, command: hci.HCI_LE_Remove_ISO_Data_Path_Command
@@ -2088,7 +2374,7 @@ class Controller:
2088
2374
  if not (iso_link := self.find_iso_link_by_handle(command.connection_handle)):
2089
2375
  return struct.pack(
2090
2376
  '<BH',
2091
- HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR,
2377
+ hci.HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR,
2092
2378
  command.connection_handle,
2093
2379
  )
2094
2380
  data_paths: set[int] = set(
@@ -2099,11 +2385,11 @@ class Controller:
2099
2385
  if not data_paths.issubset(iso_link.data_paths):
2100
2386
  return struct.pack(
2101
2387
  '<BH',
2102
- HCI_COMMAND_DISALLOWED_ERROR,
2388
+ hci.HCI_COMMAND_DISALLOWED_ERROR,
2103
2389
  command.connection_handle,
2104
2390
  )
2105
2391
  iso_link.data_paths.difference_update(data_paths)
2106
- return struct.pack('<BH', HCI_SUCCESS, command.connection_handle)
2392
+ return struct.pack('<BH', hci.HCI_SUCCESS, command.connection_handle)
2107
2393
 
2108
2394
  def on_hci_le_set_host_feature_command(
2109
2395
  self, _command: hci.HCI_LE_Set_Host_Feature_Command
@@ -2111,4 +2397,4 @@ class Controller:
2111
2397
  '''
2112
2398
  See Bluetooth spec Vol 4, Part E - 7.8.115 LE Set Host Feature command
2113
2399
  '''
2114
- return bytes([HCI_SUCCESS])
2400
+ return bytes([hci.HCI_SUCCESS])