Python Mesh


Pykonik 2019
czyli zdalnie sterowane żarówki

Agenda
- Słówko o topologii sieci
- Stos BT Mesh
- Adresowanie i subskrypcje
- Połączenie z BT Mesh
- Demo!

Gwiazda
- Ethernet (10BaseT)
- IP
rozszerzona

Magistrala
- Ethernet (10Base2)
- CAN, I2C, RS-485

Siatka
Pobożne życzenia
Smutna rzeczywistość

Siatka
Retransmisje
Relay
Bezpieczeństwo
Idempotentność
listonosz nie
czyta poczty
powtórzenie komendy
nie ma skutków ubocznych
BT Mesh

Stos
Network
Transport
Application
Bearer
IP
TCP
HTTP
Ethernet
BT Mesh


Rozgłoszenia
Połączenia
Bearer
BT Mesh

Preamble | Access Address | Header | MAC Address | Payload | CRC |
---|---|---|---|---|---|
1 byte | 4 bytes | 2 bytes | 6 bytes | 0-31 bytes | 3 bytes |
Bearer
Length | Type | Data | ... | Length | Type | Data |
---|---|---|---|---|---|---|
1 byte | 1 byte | 0-29 bytes | ... | 1 byte | 1 byte | 0-29 bytes |
Losowy adres
0x2a
BT Mesh

Network
IVI | NID | CTL | TTL | SEQ | SRC | DST | PDU | MIC |
---|---|---|---|---|---|---|---|---|
1 bit | 7 bits | 1 bit | 7 bits | 24 bits | 16 bits | 16 bits | 8-128 bits | 32-64 bits |
Adresy
Podpis
Numer pakietu
Ramka
transportowa
Ukryte
Tajne
Jawne
Jawne
Identyfikator klucza
BT Mesh

Szyfrowanie
Plaintext
Nonce
Key
AES
Ciphertext
MIC
IV Index | SEQ | SRC | ... |
---|---|---|---|
32bit | 24bit | 16 bit |
Ogólnie znane
Część pakietu
Numer pakietu jest niepowtarzalny!
DST | PDU |
---|
BT Mesh

Network
from bitstring import pack
from crypto import aes_ccm, aes_ecb
network_nonce = pack('uint:8, uint:1, uint:7, '
'uintbe:24, uintbe:16, pad:16, uintbe:32',
0x00, ctl, ttl, seq, src, iv_index)
encrypted_pdu = aes_ccm(encryption_key, nonce,
bitstring.pack('uintbe:16, bytes', dst, transport_pdu))
network_header = pack('uint:1, uint:7, uintbe:24, uintbe:16',
ctl, ttl, seq, src)
# nie całkiem prawda ;-)
privacy_nonce = pack('pad:40, uintbe:32, bytes:7',
iv_index, encrypted_pdu[:7])
obfuscated_header = aes_ecb(privacy_key, privacy_nonce,
network_header)
network_pdu = pack('uint:1, uint:7, bits, bytes',
iv_index & 1, nid, obfuscated_header, network_pdu)
BT Mesh

Transport
SEG | AKF | AID | PDU | MIC |
---|---|---|---|---|
1 bit | 1 bit | 6 bits | 0-88 bits | 32-64 bits |
Identyfikator klucza
Fragmentacja
Podpis
Ramka aplikacyjna
Tajne
Jawne
Jawne
BT Mesh

Transport
from bitstring import pack
from crypto import aes_ccm
transport_nonce = pack('uint:8, uint:1, pad:7, '
'uintbe:24, uintbe:16, pad:16, uintbe:32',
0x01, long_mic, seq, src, dst, iv_index)
encrypted_pdu = aes_ccm(application_key, application_nonce,
application_pdu)
seg = len(encrypted_pdu) > 15
if not seg:
transport_pdu = pack('uint:1, uint:1, uint:6, bytes',
seg, akf, aid, encrypted_pdu)
else:
raise NotImplementedError # ;-)
BT Mesh

Application
OPCODE | PARAMETERS |
---|---|
1-3 bytes | 0-379 bytes |
'Assigned
Numbers'
- 0x00: Config Application Key Add
- 0x80 0x00: Config Application Key Delete
- 0x80 0x01: Config Application Key Get
- 0x80 0x31: Health Fault Get
- 0x05: Health Fault Status
- ...
BT Mesh

Application
application_pdu = pack('bits, bits',
opcode, parameters)
opcode = '\x80\x05' # "health: attention set"
parameters = pack('uint:8', timeout)
opcode = '\x82\x03' # "generic on-off: set unacknowledged"
parameters = pack('uint:8, uint:8, uint:2, uint:6, uint:8',
trigger, transaction, resolution, steps, delay)
opcode = '\x80\x1b' # "config: subscription add"
parameters = ...
BT Mesh

Adresowanie
0 | 15 bits |
1 | 0 | 14 bits |
1 | 1 | 14 bits |
0 | 0 |
---|
Unassigned
Unicast
Virtual
Group
BT Mesh

Elementy i modele
Adres | Element | Modele |
---|---|---|
0x0010 | #0 | Health Config Scene Server Presence Sensor |
0x0011 | #1 | Lightness Controller Ambient Light Sensor |
0x0012 | #2 | Scene Translator |

#0 | #1 | #2 | #3 |
---|---|---|---|
OnOff | OnOff | OnOff | OnOff |
0x0010 | 0x0011 | 0x0012 | 0x0013 |



Element
Adres unicast
Model
BT Mesh

Subskrypcje
0x8000
0x8001
0x0010
0x0020
0x0030
0x0040
0x8000
0x8001
0x8000
0x0050
0x8001
0x8002
BT Mesh

Subskrypcje + relay
0x8000
0x8001
0x0010
0x0030
0x8001
0x0050
0x8001
relay
BT Mesh

Retransmisje
włącz się
za 90ms
włącz się
za 30ms
włącz się
za 60ms
czas


Wszystko pięknie, ale jak się do tego podłączyć?

Mesh Proxy
Ogólnie
Proxy
GATT
0x0050
PC

Mesh Proxy
GATT
BlueZ
DBus
Python
Linux
BlueZ

Mesh Proxy
Usługi
Profil
Usługa
Charakterystyka
Charakterystyka
Usługa
Charakterystyka
Charakterystyka
BLUETOOTH_SIG = \
'0000-1000-8000-00805f9b34fb'
proxy_service = \
'00001828-' + BLUETOOTH_SIG
write_char = \
'00002add-' + BLUETOOTH_SIG
read_char = \
'00002ade-' + BLUETOOTH_SIG

Mesh Proxy
Rozgłoszenia
Preamble | Access Address | Header | MAC Address | Payload | CRC |
---|---|---|---|---|---|
1 byte | 4 bytes | 2 bytes | 6 bytes | 0-31 bytes | 3 bytes |
Length | Type | Data | ... | Length | Type | Data |
---|---|---|---|---|---|---|
1 byte | 1 byte | 0-29 bytes | ... | 1 byte | 1 byte | 0-29 bytes |
Prawdziwy adres
0x03
0x16

Mesh Proxy
Rozgłoszenia
from pydbus import SystemBus
bus = SystemBus()
adapter = bus.get('org.bluez',
'/org/bluez/hci0')
adapter.StartDiscovery()
...
def device_discovered(device):
network_id = device.ServiceData.get(ServiceId.MESH_PROXY)
proxy_mac = device.Address
Mesh Proxy

from pydbus import SystemBus
bus = SystemBus()
adapter = bus.get('org.bluez',
'/org/bluez/hci0')
adapter.StartDiscovery()
device = bus.get('org.bluez',
'/org/bluez/hci0/dev_%s' % proxy_mac)
device.Connect()
service = bus.get('org.bluez',
'/org/bluez/hci0/dev_%s/service_%s' % (proxy_mac,
proxy_service))
send = bus.get('org.bluez',
'/org/bluez/hci0/dev_%s/char_%s' % (proxy_mac,
write_char))
recv = bus.get('org.bluez',
'/org/bluez/hci0/dev_%s/char_%s' % (proxy_mac,
read_char))
Usługi
Mesh Proxy

send = bus.get('org.bluez',
'/org/bluez/hci0/dev_%s/char_%s' % (proxy_mac,
write_char))
recv = bus.get('org.bluez',
'/org/bluez/hci0/dev_%s/char_%s' % (proxy_mac,
read_char))
def packet_send(packet):
send.WriteValue(bytes(....))
def properties_changed(properties):
value = properties.get('Value')
if value is not None:
packet_receive(bytes(value))
recv.PropertiesChanged.connect(packet_received)
recv.StartNotify()
GATT Bearer
Mesh Proxy

Szczegółowo
GATT
BlueZ
DBus
Python
Linux
Relay
Proxy

pip install bluetooth-mesh
SilvairGit/python-bluetooth-mesh


GPL 2.0
Dziękuję za uwagę!


Pytania?
Bluetooth Mesh
By Michał Lowas-Rzechonek
Bluetooth Mesh
Remote controlled bulbs
- 627