Skip to content

Commit c91520d

Browse files
bluetooth: Add version and company identifiers to local version commands (#4716)
* bluetooth: Add version and company identifiers to local version commands * Use base85 storage * Use company id in EIR_Manufacturer_Specific_Data * bluetoothids: Fix format. --------- Co-authored-by: gpotter2 <[email protected]>
1 parent c445534 commit c91520d

File tree

7 files changed

+856
-14
lines changed

7 files changed

+856
-14
lines changed

scapy/contrib/ibeacon.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,5 +102,5 @@ class IBeacon_Data(Packet):
102102

103103

104104
bind_layers(EIR_Manufacturer_Specific_Data, Apple_BLE_Frame,
105-
company_id=APPLE_MFG)
105+
company_identifier=APPLE_MFG)
106106
bind_layers(Apple_BLE_Submessage, IBeacon_Data, subtype=2)

scapy/data.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,14 @@ def _process_data(fdesc):
574574
return manufdb
575575

576576

577+
@scapy_data_cache("bluetoothids")
578+
def load_bluetoothids(filename=None):
579+
# type: (Optional[str]) -> Dict[int, str]
580+
"""Load Bluetooth IDs into the cache"""
581+
from scapy.libs.bluetoothids import DATA
582+
return cast(Dict[int, str], DATA)
583+
584+
577585
def select_path(directories, filename):
578586
# type: (List[str], str) -> Optional[str]
579587
"""Find filename among several directories"""
@@ -613,6 +621,8 @@ def select_path(directories, filename):
613621
)
614622
)
615623

624+
BLUETOOTH_CORE_COMPANY_IDENTIFIERS = load_bluetoothids()
625+
616626

617627
#####################
618628
# knowledge bases #

scapy/layers/bluetooth.py

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
from scapy.data import (
2222
DLT_BLUETOOTH_HCI_H4,
2323
DLT_BLUETOOTH_HCI_H4_WITH_PHDR,
24-
DLT_BLUETOOTH_LINUX_MONITOR
24+
DLT_BLUETOOTH_LINUX_MONITOR,
25+
BLUETOOTH_CORE_COMPANY_IDENTIFIERS
2526
)
2627
from scapy.packet import bind_layers, Packet
2728
from scapy.fields import (
@@ -266,6 +267,24 @@ class HCI_PHDR_Hdr(Packet):
266267
'extended_features',
267268
]
268269

270+
_bluetooth_core_specification_versions = {
271+
0x00: '1.0b',
272+
0x01: '1.1',
273+
0x02: '1.2',
274+
0x03: '2.0+EDR',
275+
0x04: '2.1+EDR',
276+
0x05: '3.0+HS',
277+
0x06: '4.0',
278+
0x07: '4.1',
279+
0x08: '4.2',
280+
0x09: '5.0',
281+
0x0a: '5.1',
282+
0x0b: '5.2',
283+
0x0c: '5.3',
284+
0x0d: '5.4',
285+
0x0e: '6.0',
286+
}
287+
269288

270289
class HCI_Hdr(Packet):
271290
name = "HCI header"
@@ -1153,9 +1172,13 @@ class EIR_PeripheralConnectionIntervalRange(EIR_Element):
11531172

11541173
class EIR_Manufacturer_Specific_Data(EIR_Element):
11551174
name = "EIR Manufacturer Specific Data"
1175+
deprecated_fields = {
1176+
"company_id": ("company_identifier", "2.6.2"),
1177+
}
11561178
fields_desc = [
11571179
# https://www.bluetooth.com/specifications/assigned-numbers/company-identifiers
1158-
XLEShortField("company_id", None),
1180+
LEShortEnumField("company_identifier", None,
1181+
BLUETOOTH_CORE_COMPANY_IDENTIFIERS),
11591182
]
11601183

11611184
registered_magic_payloads = {}
@@ -2445,10 +2468,10 @@ class HCI_Cmd_Complete_Read_Local_Version_Information(Packet):
24452468
"""
24462469
name = 'Read Local Version Information'
24472470
fields_desc = [
2448-
ByteField('hci_version', 0),
2471+
ByteEnumField('hci_version', 0, _bluetooth_core_specification_versions),
24492472
LEShortField('hci_subversion', 0),
2450-
ByteField('lmp_version', 0),
2451-
LEShortField('company_identifier', 0),
2473+
ByteEnumField('lmp_version', 0, _bluetooth_core_specification_versions),
2474+
LEShortEnumField('company_identifier', 0, BLUETOOTH_CORE_COMPANY_IDENTIFIERS),
24522475
LEShortField('lmp_subversion', 0)]
24532476

24542477

scapy/libs/bluetoothids.py

Lines changed: 767 additions & 0 deletions
Large diffs are not rendered by default.

scapy/tools/generate_bluetooth.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# SPDX-License-Identifier: GPL-2.0-or-later
2+
# This file is part of Scapy
3+
# See https://scapy.net/ for more information
4+
# Copyright (C) Gabriel Potter <gabriel[]potter[]fr>
5+
6+
"""
7+
Generate the bluetoothids.py file based on blueooth_sig's public listing
8+
"""
9+
10+
import yaml
11+
import json
12+
import gzip
13+
import urllib.request
14+
15+
from base64 import b85encode
16+
17+
URL = "https://bitbucket.org/bluetooth-SIG/public/raw/main/assigned_numbers/company_identifiers/company_identifiers.yaml" # noqa: E501
18+
19+
with urllib.request.urlopen(URL) as stream:
20+
DATA = yaml.safe_load(stream.read())
21+
22+
COMPILED = {}
23+
24+
for company in DATA["company_identifiers"]:
25+
COMPILED[company["value"]] = company["name"]
26+
27+
# Compress properly
28+
COMPILED = gzip.compress(json.dumps(COMPILED).encode())
29+
# Encode in Base85
30+
COMPILED = b85encode(COMPILED).decode()
31+
# Split
32+
COMPILED = "\n".join(COMPILED[i : i + 79] for i in range(0, len(COMPILED), 79)) + "\n"
33+
34+
35+
with open("../libs/bluetoothids.py", "r") as inp:
36+
data = inp.read()
37+
38+
with open("../libs/bluetoothids.py", "w") as out:
39+
ini, sep, _ = data.partition("DATA = _d(\"\"\"")
40+
COMPILED = ini + sep + "\n" + COMPILED + "\"\"\")\n"
41+
print("Written: %s" % out.write(COMPILED))

test/scapy/layers/bluetooth.uts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,8 @@ scan_resp_raw_data = \
538538
scapy_packet = HCI_Hdr(scan_resp_raw_data)
539539

540540
assert raw(scapy_packet[EIR_Manufacturer_Specific_Data].payload) == b'\x00_B31147D2461\xfc\x00\x03\x0c\x00\x00'
541-
assert scapy_packet[EIR_Manufacturer_Specific_Data].company_id == 0x154
541+
assert scapy_packet[EIR_Manufacturer_Specific_Data].company_identifier == 0x154
542+
assert scapy_packet[EIR_Manufacturer_Specific_Data].sprintf("%company_identifier%") == "Pebble Technology"
542543

543544
= Parse EIR_Manufacturer_Specific_Data with magic
544545

@@ -567,13 +568,13 @@ EIR_Manufacturer_Specific_Data.register_magic_payload(ScapyManufacturerPacket2)
567568
p = EIR_Hdr(b'\x0b\xff\xff\xffSCAPY!\xab\x12')
568569

569570
p.show()
570-
assert p[EIR_Manufacturer_Specific_Data].company_id == 0xffff
571+
assert p[EIR_Manufacturer_Specific_Data].company_identifier == 0xffff
571572
assert p[ScapyManufacturerPacket].x == 0xab12
572573

573574
p = EIR_Hdr(b'\x0b\xff\xff\xff!SCAPY\x12\x34')
574575

575576
p.show()
576-
assert p[EIR_Manufacturer_Specific_Data].company_id == 0xffff
577+
assert p[EIR_Manufacturer_Specific_Data].company_identifier == 0xffff
577578
assert p[ScapyManufacturerPacket2].y == 0x1234
578579

579580
# Test encode
@@ -709,7 +710,7 @@ b.show()
709710
assert b[HCI_Event_Hdr].len > 0
710711
assert b[EIR_CompleteLocalName].local_name == b"scapy"
711712
assert b[HCI_LE_Meta_Advertising_Report].addr == "a1:b2:c3:d4:e5:f6"
712-
assert b[EIR_Manufacturer_Specific_Data].company_id == 0xffff
713+
assert b[EIR_Manufacturer_Specific_Data].company_identifier == 0xffff
713714
assert raw(b[EIR_Manufacturer_Specific_Data].payload) == b"ypacs"
714715
assert b[EIR_TX_Power_Level].level == 10
715716
assert b[EIR_CompleteList128BitServiceUUIDs].svc_uuids[0] == UUID("01234567-89ab-cdef-1023-456789abcdfe")
@@ -746,7 +747,7 @@ a = HCI_Hdr()/HCI_Event_Hdr()/HCI_Event_LE_Meta()/HCI_LE_Meta_Extended_Advertisi
746747
rssi = -85,
747748
data=[
748749
EIR_Hdr()/EIR_Manufacturer_Specific_Data(
749-
company_id = 0xffff,
750+
company_identifier = 0xffff,
750751
) / Raw(b"scapy\x00\x01\x02\x03\x04")
751752
]
752753
),
@@ -765,7 +766,7 @@ assert b[HCI_LE_Meta_Extended_Advertising_Report][0].data_length > 0
765766
assert b[EIR_CompleteList16BitServiceUUIDs].svc_uuids == [0xffff]
766767
assert b[EIR_ServiceData16BitUUID].svc_uuid == 0xffff
767768
assert raw(b[EIR_ServiceData16BitUUID].payload) == b"scapy\x00\x00\x00"
768-
assert b[EIR_Manufacturer_Specific_Data].company_id == 0xffff
769+
assert b[EIR_Manufacturer_Specific_Data].company_identifier == 0xffff
769770
assert raw(b[EIR_Manufacturer_Specific_Data].payload) == b"scapy\x00\x01\x02\x03\x04"
770771

771772

tox.ini

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ changedir = {toxinidir}/doc/scapy
9696
deps = sphinx
9797
cryptography
9898
commands =
99-
sphinx-apidoc -f --no-toc -d 1 --separate --module-first --templatedir=_templates --output-dir api ../../scapy ../../scapy/modules/voip.py ../../scapy/modules/krack/ ../../scapy/libs/winpcapy.py ../../scapy/libs/ethertypes.py ../../scapy/libs/m*.py ../../scapy/libs/structures.py ../../scapy/libs/test_pyx.py ../../scapy/tools/ ../../scapy/arch/ ../../scapy/contrib/scada/* ../../scapy/layers/msrpce/raw/ ../../scapy/layers/msrpce/all.py ../../scapy/all.py ../../scapy/layers/all.py ../../scapy/compat.py
99+
sphinx-apidoc -f --no-toc -d 1 --separate --module-first --templatedir=_templates --output-dir api ../../scapy ../../scapy/modules/voip.py ../../scapy/modules/krack/ ../../scapy/libs/winpcapy.py ../../scapy/libs/ethertypes.py ../../scapy/libs/bluetoothids.py ../../scapy/libs/m*.py ../../scapy/libs/structures.py ../../scapy/libs/test_pyx.py ../../scapy/tools/ ../../scapy/arch/ ../../scapy/contrib/scada/* ../../scapy/layers/msrpce/raw/ ../../scapy/layers/msrpce/all.py ../../scapy/all.py ../../scapy/layers/all.py ../../scapy/compat.py
100100

101101

102102
[testenv:mypy]
@@ -136,7 +136,7 @@ description = "Check code for Grammar mistakes"
136136
skip_install = true
137137
deps = codespell
138138
# inet6, dhcp6 and the ipynb files contains french: ignore them
139-
commands = codespell --ignore-words=.config/codespell_ignore.txt --skip="*.pyc,*.png,*.jpg,*.ods,*.raw,*.pdf,*.pcap,*.js,*.html,*.der,*_build*,*inet6.py,*dhcp6.py,*manuf.py,*tcpros.py,*.ipynb,*.svg,*.gif,*.obs,*.gz" scapy/ doc/ test/ .github/
139+
commands = codespell --ignore-words=.config/codespell_ignore.txt --skip="*.pyc,*.png,*.jpg,*.ods,*.raw,*.pdf,*.pcap,*.js,*.html,*.der,*_build*,*inet6.py,*dhcp6.py,*manuf.py,*tcpros.py,*bluetoothids.py,*.ipynb,*.svg,*.gif,*.obs,*.gz" scapy/ doc/ test/ .github/
140140

141141

142142
[testenv:twine]

0 commit comments

Comments
 (0)