bumble 0.0.214__py3-none-any.whl → 0.0.215__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 +16 -3
- bumble/a2dp.py +15 -16
- bumble/apps/auracast.py +13 -38
- bumble/apps/bench.py +9 -10
- bumble/apps/ble_rpa_tool.py +1 -0
- bumble/apps/console.py +22 -25
- bumble/apps/controller_info.py +19 -19
- bumble/apps/controller_loopback.py +2 -2
- bumble/apps/controllers.py +1 -1
- bumble/apps/device_info.py +3 -3
- bumble/apps/gatt_dump.py +1 -1
- bumble/apps/gg_bridge.py +5 -6
- bumble/apps/hci_bridge.py +3 -3
- bumble/apps/l2cap_bridge.py +3 -3
- bumble/apps/lea_unicast/app.py +15 -25
- bumble/apps/pair.py +30 -43
- bumble/apps/pandora_server.py +5 -4
- bumble/apps/player/player.py +19 -22
- bumble/apps/rfcomm_bridge.py +3 -8
- bumble/apps/scan.py +16 -6
- bumble/apps/show.py +3 -4
- bumble/apps/speaker/speaker.py +22 -22
- bumble/apps/unbond.py +2 -1
- bumble/apps/usb_probe.py +1 -2
- bumble/att.py +241 -246
- bumble/audio/io.py +5 -9
- bumble/avc.py +2 -2
- bumble/avctp.py +6 -7
- bumble/avdtp.py +19 -22
- bumble/avrcp.py +1096 -588
- bumble/codecs.py +2 -0
- bumble/controller.py +52 -13
- bumble/core.py +567 -248
- bumble/crypto/__init__.py +2 -2
- bumble/crypto/builtin.py +1 -1
- bumble/crypto/cryptography.py +2 -4
- bumble/data_types.py +1025 -0
- bumble/device.py +280 -278
- bumble/drivers/__init__.py +3 -2
- bumble/drivers/intel.py +3 -4
- bumble/drivers/rtk.py +26 -9
- bumble/gap.py +4 -4
- bumble/gatt.py +3 -2
- bumble/gatt_adapters.py +3 -11
- bumble/gatt_client.py +69 -81
- bumble/gatt_server.py +124 -124
- bumble/hci.py +67 -18
- bumble/helpers.py +19 -26
- bumble/hfp.py +10 -21
- bumble/hid.py +22 -16
- bumble/host.py +181 -103
- bumble/keys.py +5 -3
- bumble/l2cap.py +121 -74
- bumble/link.py +8 -9
- bumble/pairing.py +7 -6
- bumble/pandora/__init__.py +8 -7
- bumble/pandora/config.py +3 -1
- bumble/pandora/device.py +3 -2
- bumble/pandora/host.py +38 -36
- bumble/pandora/l2cap.py +22 -21
- bumble/pandora/security.py +15 -15
- bumble/pandora/utils.py +5 -3
- bumble/profiles/aics.py +11 -11
- bumble/profiles/ams.py +7 -8
- bumble/profiles/ancs.py +6 -7
- bumble/profiles/ascs.py +4 -9
- bumble/profiles/asha.py +8 -12
- bumble/profiles/bap.py +11 -23
- bumble/profiles/bass.py +2 -7
- bumble/profiles/battery_service.py +3 -4
- bumble/profiles/cap.py +1 -2
- bumble/profiles/csip.py +2 -6
- bumble/profiles/device_information_service.py +2 -2
- bumble/profiles/gap.py +4 -4
- bumble/profiles/gatt_service.py +1 -4
- bumble/profiles/gmap.py +5 -5
- bumble/profiles/hap.py +62 -59
- bumble/profiles/heart_rate_service.py +5 -4
- bumble/profiles/le_audio.py +3 -1
- bumble/profiles/mcp.py +3 -7
- bumble/profiles/pacs.py +3 -6
- bumble/profiles/pbp.py +2 -0
- bumble/profiles/tmap.py +2 -3
- bumble/profiles/vcs.py +2 -8
- bumble/profiles/vocs.py +8 -8
- bumble/rfcomm.py +11 -14
- bumble/rtp.py +1 -0
- bumble/sdp.py +10 -8
- bumble/smp.py +142 -153
- bumble/snoop.py +5 -5
- bumble/tools/generate_company_id_list.py +1 -0
- bumble/tools/intel_fw_download.py +3 -3
- bumble/tools/intel_util.py +4 -4
- bumble/tools/rtk_fw_download.py +6 -3
- bumble/tools/rtk_util.py +24 -7
- bumble/transport/__init__.py +19 -15
- bumble/transport/android_emulator.py +8 -13
- bumble/transport/android_netsim.py +19 -18
- bumble/transport/common.py +12 -15
- bumble/transport/file.py +1 -1
- bumble/transport/hci_socket.py +4 -6
- bumble/transport/pty.py +5 -6
- bumble/transport/pyusb.py +7 -10
- bumble/transport/serial.py +2 -1
- bumble/transport/tcp_client.py +2 -2
- bumble/transport/tcp_server.py +11 -14
- bumble/transport/udp.py +3 -3
- bumble/transport/unix.py +67 -1
- bumble/transport/usb.py +6 -6
- bumble/transport/vhci.py +0 -1
- bumble/transport/ws_client.py +2 -1
- bumble/transport/ws_server.py +3 -2
- bumble/utils.py +20 -5
- bumble/vendor/android/hci.py +1 -2
- bumble/vendor/zephyr/hci.py +0 -1
- {bumble-0.0.214.dist-info → bumble-0.0.215.dist-info}/METADATA +2 -1
- bumble-0.0.215.dist-info/RECORD +183 -0
- bumble-0.0.214.dist-info/RECORD +0 -182
- {bumble-0.0.214.dist-info → bumble-0.0.215.dist-info}/WHEEL +0 -0
- {bumble-0.0.214.dist-info → bumble-0.0.215.dist-info}/entry_points.txt +0 -0
- {bumble-0.0.214.dist-info → bumble-0.0.215.dist-info}/licenses/LICENSE +0 -0
- {bumble-0.0.214.dist-info → bumble-0.0.215.dist-info}/top_level.txt +0 -0
bumble/smp.py
CHANGED
|
@@ -23,38 +23,41 @@
|
|
|
23
23
|
# Imports
|
|
24
24
|
# -----------------------------------------------------------------------------
|
|
25
25
|
from __future__ import annotations
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
import asyncio
|
|
28
28
|
import enum
|
|
29
|
-
|
|
29
|
+
import logging
|
|
30
|
+
from dataclasses import dataclass, field
|
|
30
31
|
from typing import (
|
|
31
32
|
TYPE_CHECKING,
|
|
32
33
|
Any,
|
|
33
34
|
Awaitable,
|
|
34
35
|
Callable,
|
|
36
|
+
ClassVar,
|
|
35
37
|
Optional,
|
|
38
|
+
TypeVar,
|
|
36
39
|
cast,
|
|
37
40
|
)
|
|
38
41
|
|
|
39
|
-
|
|
42
|
+
from bumble import crypto, utils
|
|
40
43
|
from bumble.colors import color
|
|
41
|
-
from bumble.hci import (
|
|
42
|
-
Address,
|
|
43
|
-
Role,
|
|
44
|
-
HCI_LE_Enable_Encryption_Command,
|
|
45
|
-
HCI_Object,
|
|
46
|
-
key_with_value,
|
|
47
|
-
)
|
|
48
44
|
from bumble.core import (
|
|
49
|
-
PhysicalTransport,
|
|
50
45
|
AdvertisingData,
|
|
51
46
|
InvalidArgumentError,
|
|
47
|
+
PhysicalTransport,
|
|
52
48
|
ProtocolError,
|
|
53
49
|
name_or_number,
|
|
54
50
|
)
|
|
51
|
+
from bumble.hci import (
|
|
52
|
+
Address,
|
|
53
|
+
Fields,
|
|
54
|
+
HCI_LE_Enable_Encryption_Command,
|
|
55
|
+
HCI_Object,
|
|
56
|
+
Role,
|
|
57
|
+
key_with_value,
|
|
58
|
+
metadata,
|
|
59
|
+
)
|
|
55
60
|
from bumble.keys import PairingKeys
|
|
56
|
-
from bumble import crypto
|
|
57
|
-
from bumble import utils
|
|
58
61
|
|
|
59
62
|
if TYPE_CHECKING:
|
|
60
63
|
from bumble.device import Connection, Device
|
|
@@ -200,31 +203,32 @@ def error_name(error_code: int) -> str:
|
|
|
200
203
|
# -----------------------------------------------------------------------------
|
|
201
204
|
# Classes
|
|
202
205
|
# -----------------------------------------------------------------------------
|
|
206
|
+
@dataclass
|
|
203
207
|
class SMP_Command:
|
|
204
208
|
'''
|
|
205
209
|
See Bluetooth spec @ Vol 3, Part H - 3 SECURITY MANAGER PROTOCOL
|
|
206
210
|
'''
|
|
207
211
|
|
|
208
|
-
smp_classes: dict[int, type[SMP_Command]] = {}
|
|
209
|
-
fields:
|
|
210
|
-
code = 0
|
|
211
|
-
name = ''
|
|
212
|
+
smp_classes: ClassVar[dict[int, type[SMP_Command]]] = {}
|
|
213
|
+
fields: ClassVar[Fields]
|
|
214
|
+
code: int = field(default=0, init=False)
|
|
215
|
+
name: str = field(default='', init=False)
|
|
216
|
+
_payload: Optional[bytes] = field(default=None, init=False)
|
|
212
217
|
|
|
213
|
-
@
|
|
214
|
-
def from_bytes(pdu: bytes) -> "SMP_Command":
|
|
218
|
+
@classmethod
|
|
219
|
+
def from_bytes(cls, pdu: bytes) -> "SMP_Command":
|
|
215
220
|
code = pdu[0]
|
|
216
221
|
|
|
217
|
-
|
|
218
|
-
if
|
|
219
|
-
instance = SMP_Command(
|
|
222
|
+
subclass = SMP_Command.smp_classes.get(code)
|
|
223
|
+
if subclass is None:
|
|
224
|
+
instance = SMP_Command()
|
|
220
225
|
instance.name = SMP_Command.command_name(code)
|
|
221
226
|
instance.code = code
|
|
227
|
+
instance.payload = pdu
|
|
222
228
|
return instance
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
self.init_from_bytes(pdu, 1)
|
|
227
|
-
return self
|
|
229
|
+
instance = subclass(**HCI_Object.dict_from_bytes(pdu, 1, subclass.fields))
|
|
230
|
+
instance.payload = pdu[1:]
|
|
231
|
+
return instance
|
|
228
232
|
|
|
229
233
|
@staticmethod
|
|
230
234
|
def command_name(code: int) -> str:
|
|
@@ -264,36 +268,35 @@ class SMP_Command:
|
|
|
264
268
|
def keypress_notification_type_name(notification_type: int) -> str:
|
|
265
269
|
return name_or_number(SMP_KEYPRESS_NOTIFICATION_TYPE_NAMES, notification_type)
|
|
266
270
|
|
|
267
|
-
|
|
268
|
-
def subclass(fields):
|
|
269
|
-
def inner(cls):
|
|
270
|
-
cls.name = cls.__name__.upper()
|
|
271
|
-
cls.code = key_with_value(SMP_COMMAND_NAMES, cls.name)
|
|
272
|
-
if cls.code is None:
|
|
273
|
-
raise KeyError(
|
|
274
|
-
f'Command name {cls.name} not found in SMP_COMMAND_NAMES'
|
|
275
|
-
)
|
|
276
|
-
cls.fields = fields
|
|
271
|
+
_Command = TypeVar("_Command", bound="SMP_Command")
|
|
277
272
|
|
|
278
|
-
|
|
279
|
-
|
|
273
|
+
@classmethod
|
|
274
|
+
def subclass(cls, subclass: type[_Command]) -> type[_Command]:
|
|
275
|
+
subclass.name = subclass.__name__.upper()
|
|
276
|
+
subclass.code = key_with_value(SMP_COMMAND_NAMES, subclass.name)
|
|
277
|
+
if subclass.code is None:
|
|
278
|
+
raise KeyError(
|
|
279
|
+
f'Command name {subclass.name} not found in SMP_COMMAND_NAMES'
|
|
280
|
+
)
|
|
281
|
+
subclass.fields = HCI_Object.fields_from_dataclass(subclass)
|
|
280
282
|
|
|
281
|
-
|
|
283
|
+
# Register a factory for this class
|
|
284
|
+
SMP_Command.smp_classes[subclass.code] = subclass
|
|
282
285
|
|
|
283
|
-
return
|
|
286
|
+
return subclass
|
|
284
287
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
self.pdu = pdu
|
|
288
|
+
@property
|
|
289
|
+
def payload(self) -> bytes:
|
|
290
|
+
if self._payload is None:
|
|
291
|
+
self._payload = HCI_Object.dict_to_bytes(self.__dict__, self.fields)
|
|
292
|
+
return self._payload
|
|
291
293
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
+
@payload.setter
|
|
295
|
+
def payload(self, value: bytes) -> None:
|
|
296
|
+
self._payload = value
|
|
294
297
|
|
|
295
298
|
def __bytes__(self):
|
|
296
|
-
return self.
|
|
299
|
+
return bytes([self.code]) + self.payload
|
|
297
300
|
|
|
298
301
|
def __str__(self):
|
|
299
302
|
result = color(self.name, 'yellow')
|
|
@@ -306,206 +309,192 @@ class SMP_Command:
|
|
|
306
309
|
|
|
307
310
|
|
|
308
311
|
# -----------------------------------------------------------------------------
|
|
309
|
-
@SMP_Command.subclass
|
|
310
|
-
|
|
311
|
-
('io_capability', {'size': 1, 'mapper': SMP_Command.io_capability_name}),
|
|
312
|
-
('oob_data_flag', 1),
|
|
313
|
-
('auth_req', {'size': 1, 'mapper': SMP_Command.auth_req_str}),
|
|
314
|
-
('maximum_encryption_key_size', 1),
|
|
315
|
-
(
|
|
316
|
-
'initiator_key_distribution',
|
|
317
|
-
{'size': 1, 'mapper': SMP_Command.key_distribution_str},
|
|
318
|
-
),
|
|
319
|
-
(
|
|
320
|
-
'responder_key_distribution',
|
|
321
|
-
{'size': 1, 'mapper': SMP_Command.key_distribution_str},
|
|
322
|
-
),
|
|
323
|
-
]
|
|
324
|
-
)
|
|
312
|
+
@SMP_Command.subclass
|
|
313
|
+
@dataclass
|
|
325
314
|
class SMP_Pairing_Request_Command(SMP_Command):
|
|
326
315
|
'''
|
|
327
316
|
See Bluetooth spec @ Vol 3, Part H - 3.5.1 Pairing Request
|
|
328
317
|
'''
|
|
329
318
|
|
|
330
|
-
io_capability: int
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
319
|
+
io_capability: int = field(
|
|
320
|
+
metadata=metadata({'size': 1, 'mapper': SMP_Command.io_capability_name})
|
|
321
|
+
)
|
|
322
|
+
oob_data_flag: int = field(metadata=metadata(1))
|
|
323
|
+
auth_req: int = field(
|
|
324
|
+
metadata=metadata({'size': 1, 'mapper': SMP_Command.auth_req_str})
|
|
325
|
+
)
|
|
326
|
+
maximum_encryption_key_size: int = field(metadata=metadata(1))
|
|
327
|
+
initiator_key_distribution: int = field(
|
|
328
|
+
metadata=metadata({'size': 1, 'mapper': SMP_Command.key_distribution_str})
|
|
329
|
+
)
|
|
330
|
+
responder_key_distribution: int = field(
|
|
331
|
+
metadata=metadata({'size': 1, 'mapper': SMP_Command.key_distribution_str})
|
|
332
|
+
)
|
|
336
333
|
|
|
337
334
|
|
|
338
335
|
# -----------------------------------------------------------------------------
|
|
339
|
-
@SMP_Command.subclass
|
|
340
|
-
|
|
341
|
-
('io_capability', {'size': 1, 'mapper': SMP_Command.io_capability_name}),
|
|
342
|
-
('oob_data_flag', 1),
|
|
343
|
-
('auth_req', {'size': 1, 'mapper': SMP_Command.auth_req_str}),
|
|
344
|
-
('maximum_encryption_key_size', 1),
|
|
345
|
-
(
|
|
346
|
-
'initiator_key_distribution',
|
|
347
|
-
{'size': 1, 'mapper': SMP_Command.key_distribution_str},
|
|
348
|
-
),
|
|
349
|
-
(
|
|
350
|
-
'responder_key_distribution',
|
|
351
|
-
{'size': 1, 'mapper': SMP_Command.key_distribution_str},
|
|
352
|
-
),
|
|
353
|
-
]
|
|
354
|
-
)
|
|
336
|
+
@SMP_Command.subclass
|
|
337
|
+
@dataclass
|
|
355
338
|
class SMP_Pairing_Response_Command(SMP_Command):
|
|
356
339
|
'''
|
|
357
340
|
See Bluetooth spec @ Vol 3, Part H - 3.5.2 Pairing Response
|
|
358
341
|
'''
|
|
359
342
|
|
|
360
|
-
io_capability: int
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
343
|
+
io_capability: int = field(
|
|
344
|
+
metadata=metadata({'size': 1, 'mapper': SMP_Command.io_capability_name})
|
|
345
|
+
)
|
|
346
|
+
oob_data_flag: int = field(metadata=metadata(1))
|
|
347
|
+
auth_req: int = field(
|
|
348
|
+
metadata=metadata({'size': 1, 'mapper': SMP_Command.auth_req_str})
|
|
349
|
+
)
|
|
350
|
+
maximum_encryption_key_size: int = field(metadata=metadata(1))
|
|
351
|
+
initiator_key_distribution: int = field(
|
|
352
|
+
metadata=metadata({'size': 1, 'mapper': SMP_Command.key_distribution_str})
|
|
353
|
+
)
|
|
354
|
+
responder_key_distribution: int = field(
|
|
355
|
+
metadata=metadata({'size': 1, 'mapper': SMP_Command.key_distribution_str})
|
|
356
|
+
)
|
|
366
357
|
|
|
367
358
|
|
|
368
359
|
# -----------------------------------------------------------------------------
|
|
369
|
-
@SMP_Command.subclass
|
|
360
|
+
@SMP_Command.subclass
|
|
361
|
+
@dataclass
|
|
370
362
|
class SMP_Pairing_Confirm_Command(SMP_Command):
|
|
371
363
|
'''
|
|
372
364
|
See Bluetooth spec @ Vol 3, Part H - 3.5.3 Pairing Confirm
|
|
373
365
|
'''
|
|
374
366
|
|
|
375
|
-
confirm_value: bytes
|
|
367
|
+
confirm_value: bytes = field(metadata=metadata(16))
|
|
376
368
|
|
|
377
369
|
|
|
378
370
|
# -----------------------------------------------------------------------------
|
|
379
|
-
@SMP_Command.subclass
|
|
371
|
+
@SMP_Command.subclass
|
|
372
|
+
@dataclass
|
|
380
373
|
class SMP_Pairing_Random_Command(SMP_Command):
|
|
381
374
|
'''
|
|
382
375
|
See Bluetooth spec @ Vol 3, Part H - 3.5.4 Pairing Random
|
|
383
376
|
'''
|
|
384
377
|
|
|
385
|
-
random_value: bytes
|
|
378
|
+
random_value: bytes = field(metadata=metadata(16))
|
|
386
379
|
|
|
387
380
|
|
|
388
381
|
# -----------------------------------------------------------------------------
|
|
389
|
-
@SMP_Command.subclass
|
|
382
|
+
@SMP_Command.subclass
|
|
383
|
+
@dataclass
|
|
390
384
|
class SMP_Pairing_Failed_Command(SMP_Command):
|
|
391
385
|
'''
|
|
392
386
|
See Bluetooth spec @ Vol 3, Part H - 3.5.5 Pairing Failed
|
|
393
387
|
'''
|
|
394
388
|
|
|
395
|
-
reason: int
|
|
389
|
+
reason: int = field(metadata=metadata({'size': 1, 'mapper': error_name}))
|
|
396
390
|
|
|
397
391
|
|
|
398
392
|
# -----------------------------------------------------------------------------
|
|
399
|
-
@SMP_Command.subclass
|
|
393
|
+
@SMP_Command.subclass
|
|
394
|
+
@dataclass
|
|
400
395
|
class SMP_Pairing_Public_Key_Command(SMP_Command):
|
|
401
396
|
'''
|
|
402
397
|
See Bluetooth spec @ Vol 3, Part H - 3.5.6 Pairing Public Key
|
|
403
398
|
'''
|
|
404
399
|
|
|
405
|
-
public_key_x: bytes
|
|
406
|
-
public_key_y: bytes
|
|
400
|
+
public_key_x: bytes = field(metadata=metadata(32))
|
|
401
|
+
public_key_y: bytes = field(metadata=metadata(32))
|
|
407
402
|
|
|
408
403
|
|
|
409
404
|
# -----------------------------------------------------------------------------
|
|
410
|
-
@SMP_Command.subclass
|
|
411
|
-
|
|
412
|
-
('dhkey_check', 16),
|
|
413
|
-
]
|
|
414
|
-
)
|
|
405
|
+
@SMP_Command.subclass
|
|
406
|
+
@dataclass
|
|
415
407
|
class SMP_Pairing_DHKey_Check_Command(SMP_Command):
|
|
416
408
|
'''
|
|
417
409
|
See Bluetooth spec @ Vol 3, Part H - 3.5.7 Pairing DHKey Check
|
|
418
410
|
'''
|
|
419
411
|
|
|
420
|
-
dhkey_check: bytes
|
|
412
|
+
dhkey_check: bytes = field(metadata=metadata(16))
|
|
421
413
|
|
|
422
414
|
|
|
423
415
|
# -----------------------------------------------------------------------------
|
|
424
|
-
@SMP_Command.subclass
|
|
425
|
-
|
|
426
|
-
(
|
|
427
|
-
'notification_type',
|
|
428
|
-
{'size': 1, 'mapper': SMP_Command.keypress_notification_type_name},
|
|
429
|
-
),
|
|
430
|
-
]
|
|
431
|
-
)
|
|
416
|
+
@SMP_Command.subclass
|
|
417
|
+
@dataclass
|
|
432
418
|
class SMP_Pairing_Keypress_Notification_Command(SMP_Command):
|
|
433
419
|
'''
|
|
434
420
|
See Bluetooth spec @ Vol 3, Part H - 3.5.8 Keypress Notification
|
|
435
421
|
'''
|
|
436
422
|
|
|
437
|
-
notification_type: int
|
|
423
|
+
notification_type: int = field(
|
|
424
|
+
metadata=metadata(
|
|
425
|
+
{'size': 1, 'mapper': SMP_Command.keypress_notification_type_name}
|
|
426
|
+
)
|
|
427
|
+
)
|
|
438
428
|
|
|
439
429
|
|
|
440
430
|
# -----------------------------------------------------------------------------
|
|
441
|
-
@SMP_Command.subclass
|
|
431
|
+
@SMP_Command.subclass
|
|
432
|
+
@dataclass
|
|
442
433
|
class SMP_Encryption_Information_Command(SMP_Command):
|
|
443
434
|
'''
|
|
444
435
|
See Bluetooth spec @ Vol 3, Part H - 3.6.2 Encryption Information
|
|
445
436
|
'''
|
|
446
437
|
|
|
447
|
-
long_term_key: bytes
|
|
438
|
+
long_term_key: bytes = field(metadata=metadata(16))
|
|
448
439
|
|
|
449
440
|
|
|
450
441
|
# -----------------------------------------------------------------------------
|
|
451
|
-
@SMP_Command.subclass
|
|
442
|
+
@SMP_Command.subclass
|
|
443
|
+
@dataclass
|
|
452
444
|
class SMP_Master_Identification_Command(SMP_Command):
|
|
453
445
|
'''
|
|
454
446
|
See Bluetooth spec @ Vol 3, Part H - 3.6.3 Master Identification
|
|
455
447
|
'''
|
|
456
448
|
|
|
457
|
-
ediv: int
|
|
458
|
-
rand: bytes
|
|
449
|
+
ediv: int = field(metadata=metadata(2))
|
|
450
|
+
rand: bytes = field(metadata=metadata(8))
|
|
459
451
|
|
|
460
452
|
|
|
461
453
|
# -----------------------------------------------------------------------------
|
|
462
|
-
@SMP_Command.subclass
|
|
454
|
+
@SMP_Command.subclass
|
|
455
|
+
@dataclass
|
|
463
456
|
class SMP_Identity_Information_Command(SMP_Command):
|
|
464
457
|
'''
|
|
465
458
|
See Bluetooth spec @ Vol 3, Part H - 3.6.4 Identity Information
|
|
466
459
|
'''
|
|
467
460
|
|
|
468
|
-
identity_resolving_key: bytes
|
|
461
|
+
identity_resolving_key: bytes = field(metadata=metadata(16))
|
|
469
462
|
|
|
470
463
|
|
|
471
464
|
# -----------------------------------------------------------------------------
|
|
472
|
-
@SMP_Command.subclass
|
|
473
|
-
|
|
474
|
-
('addr_type', Address.ADDRESS_TYPE_SPEC),
|
|
475
|
-
('bd_addr', Address.parse_address_preceded_by_type),
|
|
476
|
-
]
|
|
477
|
-
)
|
|
465
|
+
@SMP_Command.subclass
|
|
466
|
+
@dataclass
|
|
478
467
|
class SMP_Identity_Address_Information_Command(SMP_Command):
|
|
479
468
|
'''
|
|
480
469
|
See Bluetooth spec @ Vol 3, Part H - 3.6.5 Identity Address Information
|
|
481
470
|
'''
|
|
482
471
|
|
|
483
|
-
addr_type: int
|
|
484
|
-
bd_addr: Address
|
|
472
|
+
addr_type: int = field(metadata=metadata(Address.ADDRESS_TYPE_SPEC))
|
|
473
|
+
bd_addr: Address = field(metadata=metadata(Address.parse_address_preceded_by_type))
|
|
485
474
|
|
|
486
475
|
|
|
487
476
|
# -----------------------------------------------------------------------------
|
|
488
|
-
@SMP_Command.subclass
|
|
477
|
+
@SMP_Command.subclass
|
|
478
|
+
@dataclass
|
|
489
479
|
class SMP_Signing_Information_Command(SMP_Command):
|
|
490
480
|
'''
|
|
491
481
|
See Bluetooth spec @ Vol 3, Part H - 3.6.6 Signing Information
|
|
492
482
|
'''
|
|
493
483
|
|
|
494
|
-
signature_key: bytes
|
|
484
|
+
signature_key: bytes = field(metadata=metadata(16))
|
|
495
485
|
|
|
496
486
|
|
|
497
487
|
# -----------------------------------------------------------------------------
|
|
498
|
-
@SMP_Command.subclass
|
|
499
|
-
|
|
500
|
-
('auth_req', {'size': 1, 'mapper': SMP_Command.auth_req_str}),
|
|
501
|
-
]
|
|
502
|
-
)
|
|
488
|
+
@SMP_Command.subclass
|
|
489
|
+
@dataclass
|
|
503
490
|
class SMP_Security_Request_Command(SMP_Command):
|
|
504
491
|
'''
|
|
505
492
|
See Bluetooth spec @ Vol 3, Part H - 3.6.7 Security Request
|
|
506
493
|
'''
|
|
507
494
|
|
|
508
|
-
auth_req: int
|
|
495
|
+
auth_req: int = field(
|
|
496
|
+
metadata=metadata({'size': 1, 'mapper': SMP_Command.auth_req_str})
|
|
497
|
+
)
|
|
509
498
|
|
|
510
499
|
|
|
511
500
|
# -----------------------------------------------------------------------------
|
|
@@ -892,8 +881,8 @@ class Session:
|
|
|
892
881
|
if response:
|
|
893
882
|
next_steps()
|
|
894
883
|
return
|
|
895
|
-
except Exception
|
|
896
|
-
logger.
|
|
884
|
+
except Exception:
|
|
885
|
+
logger.exception('exception while confirm')
|
|
897
886
|
|
|
898
887
|
self.send_pairing_failed(SMP_CONFIRM_VALUE_FAILED_ERROR)
|
|
899
888
|
|
|
@@ -911,8 +900,8 @@ class Session:
|
|
|
911
900
|
if response:
|
|
912
901
|
next_steps()
|
|
913
902
|
return
|
|
914
|
-
except Exception
|
|
915
|
-
logger.
|
|
903
|
+
except Exception:
|
|
904
|
+
logger.exception('exception while prompting')
|
|
916
905
|
|
|
917
906
|
self.send_pairing_failed(SMP_CONFIRM_VALUE_FAILED_ERROR)
|
|
918
907
|
|
|
@@ -929,8 +918,8 @@ class Session:
|
|
|
929
918
|
return
|
|
930
919
|
logger.debug(f'user input: {passkey}')
|
|
931
920
|
next_steps(passkey)
|
|
932
|
-
except Exception
|
|
933
|
-
logger.
|
|
921
|
+
except Exception:
|
|
922
|
+
logger.exception('exception while prompting')
|
|
934
923
|
self.send_pairing_failed(SMP_PASSKEY_ENTRY_FAILED_ERROR)
|
|
935
924
|
|
|
936
925
|
self.connection.cancel_on_disconnection(prompt())
|
|
@@ -978,8 +967,8 @@ class Session:
|
|
|
978
967
|
|
|
979
968
|
try:
|
|
980
969
|
self.connection.cancel_on_disconnection(display_passkey())
|
|
981
|
-
except Exception
|
|
982
|
-
logger.
|
|
970
|
+
except Exception:
|
|
971
|
+
logger.exception('exception while displaying passkey')
|
|
983
972
|
else:
|
|
984
973
|
self.input_passkey(next_steps)
|
|
985
974
|
|
|
@@ -1424,8 +1413,8 @@ class Session:
|
|
|
1424
1413
|
if handler is not None:
|
|
1425
1414
|
try:
|
|
1426
1415
|
handler(command)
|
|
1427
|
-
except Exception
|
|
1428
|
-
logger.exception(
|
|
1416
|
+
except Exception:
|
|
1417
|
+
logger.exception(color("!!! Exception in handler:", "red"))
|
|
1429
1418
|
response = SMP_Pairing_Failed_Command(
|
|
1430
1419
|
reason=SMP_UNSPECIFIED_REASON_ERROR
|
|
1431
1420
|
)
|
|
@@ -1446,8 +1435,8 @@ class Session:
|
|
|
1446
1435
|
# Check if the request should proceed
|
|
1447
1436
|
try:
|
|
1448
1437
|
accepted = await self.pairing_config.delegate.accept()
|
|
1449
|
-
except Exception
|
|
1450
|
-
logger.
|
|
1438
|
+
except Exception:
|
|
1439
|
+
logger.exception('exception while accepting')
|
|
1451
1440
|
accepted = False
|
|
1452
1441
|
if not accepted:
|
|
1453
1442
|
logger.debug('pairing rejected by delegate')
|
bumble/snoop.py
CHANGED
|
@@ -12,21 +12,21 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
+
import datetime
|
|
16
|
+
import logging
|
|
17
|
+
import os
|
|
18
|
+
import struct
|
|
19
|
+
|
|
15
20
|
# -----------------------------------------------------------------------------
|
|
16
21
|
# Imports
|
|
17
22
|
# -----------------------------------------------------------------------------
|
|
18
23
|
from contextlib import contextmanager
|
|
19
24
|
from enum import IntEnum
|
|
20
|
-
import logging
|
|
21
|
-
import struct
|
|
22
|
-
import datetime
|
|
23
25
|
from typing import BinaryIO, Generator
|
|
24
|
-
import os
|
|
25
26
|
|
|
26
27
|
from bumble import core
|
|
27
28
|
from bumble.hci import HCI_COMMAND_PACKET, HCI_EVENT_PACKET
|
|
28
29
|
|
|
29
|
-
|
|
30
30
|
# -----------------------------------------------------------------------------
|
|
31
31
|
# Logging
|
|
32
32
|
# -----------------------------------------------------------------------------
|
|
@@ -17,15 +17,14 @@
|
|
|
17
17
|
# -----------------------------------------------------------------------------
|
|
18
18
|
import logging
|
|
19
19
|
import pathlib
|
|
20
|
-
import urllib.request
|
|
21
20
|
import urllib.error
|
|
21
|
+
import urllib.request
|
|
22
22
|
|
|
23
23
|
import click
|
|
24
24
|
|
|
25
25
|
from bumble.colors import color
|
|
26
26
|
from bumble.drivers import intel
|
|
27
27
|
|
|
28
|
-
|
|
29
28
|
# -----------------------------------------------------------------------------
|
|
30
29
|
# Logging
|
|
31
30
|
# -----------------------------------------------------------------------------
|
|
@@ -43,7 +42,8 @@ LINUX_KERNEL_GIT_SOURCE = "https://git.kernel.org/pub/scm/linux/kernel/git/firmw
|
|
|
43
42
|
# -----------------------------------------------------------------------------
|
|
44
43
|
def download_file(base_url, name):
|
|
45
44
|
url = f"{base_url}/{name}"
|
|
46
|
-
|
|
45
|
+
request = urllib.request.Request(url, data=None, headers={"User-Agent": "Bumble"})
|
|
46
|
+
with urllib.request.urlopen(request) as file:
|
|
47
47
|
data = file.read()
|
|
48
48
|
print(f"Downloaded {name}: {len(data)} bytes")
|
|
49
49
|
return data
|
bumble/tools/intel_util.py
CHANGED
|
@@ -12,21 +12,21 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
+
import asyncio
|
|
16
|
+
|
|
15
17
|
# -----------------------------------------------------------------------------
|
|
16
18
|
# Imports
|
|
17
19
|
# -----------------------------------------------------------------------------
|
|
18
20
|
import logging
|
|
19
|
-
import asyncio
|
|
20
21
|
from typing import Any, Optional
|
|
21
22
|
|
|
22
23
|
import click
|
|
23
24
|
|
|
24
|
-
|
|
25
|
+
import bumble.logging
|
|
25
26
|
from bumble import transport
|
|
27
|
+
from bumble.colors import color
|
|
26
28
|
from bumble.drivers import intel
|
|
27
29
|
from bumble.host import Host
|
|
28
|
-
import bumble.logging
|
|
29
|
-
|
|
30
30
|
|
|
31
31
|
# -----------------------------------------------------------------------------
|
|
32
32
|
# Logging
|
bumble/tools/rtk_fw_download.py
CHANGED
|
@@ -17,16 +17,16 @@
|
|
|
17
17
|
# -----------------------------------------------------------------------------
|
|
18
18
|
import logging
|
|
19
19
|
import pathlib
|
|
20
|
-
import urllib.request
|
|
21
20
|
import urllib.error
|
|
21
|
+
import urllib.request
|
|
22
22
|
|
|
23
23
|
import click
|
|
24
24
|
|
|
25
|
+
import bumble.logging
|
|
25
26
|
from bumble.colors import color
|
|
26
27
|
from bumble.drivers import rtk
|
|
27
28
|
from bumble.tools import rtk_util
|
|
28
29
|
|
|
29
|
-
|
|
30
30
|
# -----------------------------------------------------------------------------
|
|
31
31
|
# Logging
|
|
32
32
|
# -----------------------------------------------------------------------------
|
|
@@ -58,7 +58,9 @@ def download_file(base_url, name, remove_suffix):
|
|
|
58
58
|
name = name.replace(".bin", "")
|
|
59
59
|
|
|
60
60
|
url = f"{base_url}/{name}"
|
|
61
|
-
|
|
61
|
+
logger.debug(f"downloading {url}")
|
|
62
|
+
request = urllib.request.Request(url, data=None, headers={"User-Agent": "Bumble"})
|
|
63
|
+
with urllib.request.urlopen(request) as file:
|
|
62
64
|
data = file.read()
|
|
63
65
|
print(f"Downloaded {name}: {len(data)} bytes")
|
|
64
66
|
return data
|
|
@@ -84,6 +86,7 @@ def download_file(base_url, name, remove_suffix):
|
|
|
84
86
|
@click.option("--parse", is_flag=True, help="Parse the FW image after saving")
|
|
85
87
|
def main(output_dir, source, single, force, parse):
|
|
86
88
|
"""Download RTK firmware images and configs."""
|
|
89
|
+
bumble.logging.setup_basic_logging()
|
|
87
90
|
|
|
88
91
|
# Check that the output dir exists
|
|
89
92
|
if output_dir == '':
|