fix: Use identity-based keying for fragmenters/reassemblers (MAC rotation immunity)

Critical fix for message delivery and Android MAC rotation support.

**Problem:**
- Fragmenters keyed by MAC address
- Failed with "dev:" prefix mismatch
- Would break on Android MAC rotation

**Solution:**
Use identity_hash for fragmenter/reassembler keys (with Protocol v1 MAC fallback).

**Changes:**
1. Added _get_fragmenter_key() helper - returns identity_hash or normalized MAC
2. Updated _connect_to_peer() - creates fragmenters with identity keys
3. Updated BLEPeerInterface.processOutgoing() - looks up fragmenters with identity keys

**Benefits:**
-  Fixes immediate "No fragmenter" bug
-  Survives Android MAC address rotation
-  Consistent with unified interface architecture
-  One fragmenter per peer identity (not per ephemeral MAC)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
torlando-tech 2025-10-31 21:06:58 -04:00
commit 123bdc9200

View file

@ -1517,9 +1517,12 @@ class BLEInterface(Interface):
self.peers[peer.address] = (client, time.time(), mtu)
# Create fragmenter for this peer's MTU
# KEY CHANGE: Use identity_hash for keying (survives MAC rotation, fixes dev: prefix issue)
frag_key = self._get_fragmenter_key(peer_identity, peer.address)
with self.frag_lock:
self.fragmenters[peer.address] = BLEFragmenter(mtu=mtu)
self.reassemblers[peer.address] = BLEReassembler(timeout=self.connection_timeout)
self.fragmenters[frag_key] = BLEFragmenter(mtu=mtu)
self.reassemblers[frag_key] = BLEReassembler(timeout=self.connection_timeout)
RNS.log(f"{self} created fragmenter/reassembler for peer (key: {frag_key[:16]})", RNS.LOG_DEBUG)
# Create or update unified peer interface with central connection
self._spawn_or_update_peer_interface(
@ -1633,6 +1636,27 @@ class BLEInterface(Interface):
RNS.log(f"{self} failed to connect to {peer.name} ({peer.address}): "
f"{error_type}: {e}, failures={peer.failed_connections}", RNS.LOG_WARNING)
def _get_fragmenter_key(self, peer_identity, peer_address):
"""
Compute fragmenter/reassembler dictionary key.
Uses identity_hash for Protocol v2 devices (survives MAC rotation),
falls back to normalized MAC for Protocol v1 legacy devices.
Args:
peer_identity: 16-byte peer identity (None for Protocol v1)
peer_address: BLE MAC address (may have "dev:" prefix)
Returns:
str: Identity hash (16 hex chars) or normalized MAC address
"""
if peer_identity:
# Protocol v2: Use identity hash (immune to MAC rotation)
return RNS.Identity.full_hash(peer_identity)[:16].hex()[:16]
else:
# Protocol v1 fallback: Use normalized MAC address
return peer_address.replace("dev:", "")
def _spawn_or_update_peer_interface(self, address, name, peer_identity=None, client=None, mtu=None, connection_type="central"):
"""
Create or update a unified peer interface that can handle both central and peripheral connections.
@ -2314,13 +2338,15 @@ class BLEPeerInterface(Interface):
# Log packet transmission
RNS.log(f"{self} TX: {len(data)} bytes to {self.peer_name}", RNS.LOG_DEBUG)
# Get fragmenter for this peer
# Get fragmenter for this peer (using identity-based key for MAC rotation immunity)
frag_key = self.parent_interface._get_fragmenter_key(self.peer_identity, self.peer_address)
with self.parent_interface.frag_lock:
if self.peer_address not in self.parent_interface.fragmenters:
RNS.log(f"No fragmenter for peer {self.peer_address}", RNS.LOG_WARNING)
if frag_key not in self.parent_interface.fragmenters:
RNS.log(f"No fragmenter for peer {self.peer_name} (key: {frag_key})", RNS.LOG_WARNING)
return
fragmenter = self.parent_interface.fragmenters[self.peer_address]
fragmenter = self.parent_interface.fragmenters[frag_key]
# Fragment the data
try: