From 2ff9ddc4f10d9f0eae32be72143b81a7b48b8183 Mon Sep 17 00:00:00 2001 From: torlando-tech Date: Tue, 25 Nov 2025 18:18:22 -0500 Subject: [PATCH] fix: HW_MTU instance attribute and MTU/identity race condition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two critical fixes ported from Android testing: 1. HW_MTU instance attribute fix: - Base Interface.__init__() sets self.HW_MTU = None - BLEInterface.HW_MTU = 500 is a CLASS attribute, not instance - After super().__init__(), self.HW_MTU is None (instance shadows class) - BLEPeerInterface copies: self.HW_MTU = parent.HW_MTU (gets None) - When HW_MTU is None, Transport.py truncates packet.data incorrectly - Result: Link establishment fails with mismatched link_id - Fix: Explicitly set self.HW_MTU = BLEInterface.HW_MTU after super().__init__() 2. MTU/identity race condition fix: - MTU negotiation can complete before identity is received - Previously: Warning logged, fragmenter not created - Now: Store pending MTU, create fragmenter when identity arrives - Adds pending_mtu dict to track deferred MTU values - _device_connected_callback checks for pending MTU after storing identity 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/RNS/Interfaces/BLEInterface.py | 41 +++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/src/RNS/Interfaces/BLEInterface.py b/src/RNS/Interfaces/BLEInterface.py index b89dd69..bcc551b 100644 --- a/src/RNS/Interfaces/BLEInterface.py +++ b/src/RNS/Interfaces/BLEInterface.py @@ -284,6 +284,26 @@ class BLEInterface(Interface): super().__init__() + # CRITICAL: Set HW_MTU as instance attribute after super().__init__() + # + # Bug explanation: + # - Base Interface.__init__() sets self.HW_MTU = None + # - BLEInterface.HW_MTU = 500 is a CLASS attribute, not instance + # - After super().__init__(), self.HW_MTU is None (instance shadows class) + # - BLEPeerInterface copies: self.HW_MTU = parent.HW_MTU (gets None) + # + # Impact when HW_MTU is None: + # - Transport.py line ~1855 checks: if packet.receiving_interface.HW_MTU == None + # - If true, it TRUNCATES packet.data by 3 bytes (LINK_MTU_SIZE) before + # passing to Link.validate_request() + # - Link.link_id_from_lr_packet() uses len(packet.data) to compute truncation + # - Since packet.data was pre-truncated, it computes WRONG link_id + # - Link proof's destination_hash won't match pending link's link_id + # - Result: Links time out despite proof arriving correctly + # + # This bug ONLY affects BLE because other interfaces set HW_MTU in __init__ + self.HW_MTU = BLEInterface.HW_MTU + # Parse configuration c = Interface.get_config_obj(configuration) @@ -364,6 +384,7 @@ class BLEInterface(Interface): self.fragmenters = {} # address -> BLEFragmenter (per MTU) self.reassemblers = {} # address -> BLEReassembler self.frag_lock = threading.Lock() + self.pending_mtu = {} # address -> mtu (for MTU/identity race condition) # Discovery state with prioritization @@ -751,7 +772,7 @@ class BLEInterface(Interface): role = self.driver.get_peer_role(address) if peer_identity is not None: - # Central mode: identity provided by driver + # Identity provided by driver (central mode direct, peripheral mode via late callback) if len(peer_identity) == 16: identity_hash = self._compute_identity_hash(peer_identity) @@ -759,8 +780,15 @@ class BLEInterface(Interface): self.address_to_identity[address] = peer_identity self.identity_to_address[identity_hash] = address - RNS.log(f"{self} connected to {address} as CENTRAL, received identity: {identity_hash}", RNS.LOG_INFO) + role_str = role.upper() if role else "UNKNOWN" + RNS.log(f"{self} connected to {address} as {role_str}, received identity: {identity_hash}", RNS.LOG_INFO) self._record_connection_success(address) + + # Check for pending MTU (race condition: MTU negotiated before identity) + if address in self.pending_mtu: + pending_mtu = self.pending_mtu.pop(address) + RNS.log(f"{self} creating deferred fragmenter for {address} (MTU={pending_mtu})", RNS.LOG_DEBUG) + self._mtu_negotiated_callback(address, pending_mtu) else: RNS.log(f"{self} invalid identity from {address} (wrong length), disconnecting", RNS.LOG_WARNING) self.driver.disconnect(address) @@ -819,7 +847,10 @@ class BLEInterface(Interface): # Get peer identity peer_identity = self.address_to_identity.get(address) if not peer_identity: - RNS.log(f"{self} no identity for {address}, cannot create fragmenter", RNS.LOG_WARNING) + # Race condition: MTU negotiated before identity received + # Store pending MTU and create fragmenter when identity arrives + RNS.log(f"{self} no identity for {address}, storing pending MTU {mtu}", RNS.LOG_DEBUG) + self.pending_mtu[address] = mtu return # Create or update fragmenter @@ -980,6 +1011,10 @@ class BLEInterface(Interface): if frag_key in self.reassemblers: del self.reassemblers[frag_key] + # Clean up pending MTU (from MTU/identity race condition) + if address in self.pending_mtu: + del self.pending_mtu[address] + def _error_callback(self, severity: str, message: str, exc: Exception = None): """ Driver callback: Handle driver errors.