Merge main into release/v0.2.2
Resolved conflicts: - BLEInterface.py, test_v2_2_mac_sorting.py, CLAUDE.md: Keep release (HW_MTU fix, pending_mtu, MAC rotation recovery/bypass, corrected tests) - install.sh, README.md: Keep main (JustWorksRepairing auto-configuration) - CHANGELOG.md: Consolidated detailed notes from main into [0.2.2] section - Added FUNDING.yml from main 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
commit
bee68879af
4 changed files with 202 additions and 8 deletions
56
CHANGELOG.md
56
CHANGELOG.md
|
|
@ -17,10 +17,56 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- Pre-built wheel support for Pi Zero W Python 3.13 (saves 20+ min install time)
|
||||
|
||||
### Fixed
|
||||
- Connection race conditions from concurrent connection attempts to the same peer
|
||||
- BlueZ D-Bus state corruption after connection timeouts/failures - devices can now reconnect after blacklist period
|
||||
- Scanner interference causing "Operation already in progress" during connections
|
||||
- GATT server race where services weren't available on D-Bus before first connection attempt
|
||||
- **Connection race condition causing "Operation already in progress" errors**
|
||||
- Added `_connecting_peers` state tracking in `linux_bluetooth_driver.py` to prevent concurrent connection attempts to the same peer
|
||||
- Implemented 5-second connection attempt rate limiting per peer in `BLEInterface.py`
|
||||
- Added pending connection check in peer selection logic
|
||||
- Downgraded expected race condition errors from ERROR to DEBUG level to reduce log noise
|
||||
- Prevents false-positive peer blacklisting from benign concurrent connection attempts
|
||||
- Improves connection success rate by approximately 15-20% in high-density environments
|
||||
- Files: `src/RNS/Interfaces/linux_bluetooth_driver.py`, `src/RNS/Interfaces/BLEInterface.py`
|
||||
|
||||
- **BlueZ state corruption causing persistent "Operation already in progress" errors**
|
||||
- Added explicit `client.disconnect()` in timeout and failure exception handlers
|
||||
- Implemented `_remove_bluez_device()` method to remove stale D-Bus device objects via BlueZ `RemoveDevice()` API
|
||||
- Integrated BlueZ device cleanup after connection timeouts, failures, and peer blacklisting
|
||||
- Prevents BlueZ from maintaining stale connection state after abandoned connection attempts
|
||||
- Enables successful reconnection after blacklist period expires
|
||||
- Fixes issue where devices could not reconnect after multiple failed attempts due to corrupted BlueZ state
|
||||
- Files: `src/RNS/Interfaces/linux_bluetooth_driver.py`, `src/RNS/Interfaces/BLEInterface.py`
|
||||
|
||||
- **Scanner interference causing "Operation already in progress" errors during connection attempts**
|
||||
- Added `_should_pause_scanning()` method to check for active connections before starting scanner
|
||||
- Modified `_perform_scan()` to skip scan cycle when connections are in progress
|
||||
- Scanner automatically pauses when `_connecting_peers` is not empty
|
||||
- Scanner automatically resumes when connections complete
|
||||
- Prevents BlueZ "InProgress" errors from scanner.start() conflicting with connection operations
|
||||
- Improves connection reliability by eliminating scan-induced connection failures
|
||||
- Reduces BlueZ error log spam from scan loop
|
||||
- Files: `src/RNS/Interfaces/linux_bluetooth_driver.py`
|
||||
- Tests: `tests/test_scanner_connection_coordination.py`
|
||||
|
||||
- **BR/EDR fallback - clarify ConnectDevice() object path return as success**
|
||||
- Modified `_connect_via_dbus_le()` to capture and log object path returned by ConnectDevice()
|
||||
- Object path (D-Bus signature 'o') indicates successful LE connection initiation
|
||||
- Prevents confusion from "br-connection-profile-unavailable" error messages
|
||||
- Some BlueZ versions report BR/EDR profile unavailable while LE connection succeeds - this is expected
|
||||
- Improved logging shows object path for debugging visibility
|
||||
- Clarifies that object path return means success, not error
|
||||
- Files: `src/RNS/Interfaces/linux_bluetooth_driver.py`
|
||||
- Tests: `tests/test_breddr_fallback_prevention.py`
|
||||
|
||||
- **GATT server initialization race causing "Reticulum service not found" errors**
|
||||
- Added `_verify_services_on_dbus()` method to poll D-Bus for service availability after server start
|
||||
- Fixed race condition where `started_event` fires before `peripheral.publish()` exports services to D-Bus
|
||||
- Polls D-Bus adapter introspection every 200ms with 5-second timeout
|
||||
- Ensures services are actually exported before accepting central connections
|
||||
- Eliminates "service not found" errors during server startup window (typically 50-200ms)
|
||||
- Graceful degradation: warns if verification times out but doesn't fail startup
|
||||
- Typical verification time: 100-300ms, no runtime performance impact
|
||||
- Files: `src/RNS/Interfaces/linux_bluetooth_driver.py`
|
||||
- Tests: `tests/test_gatt_server_readiness.py`
|
||||
|
||||
- D-Bus disconnect monitoring switched to ObjectManager with polling fallback
|
||||
- Peripheral disconnect cleanup preventing new connections after hitting peer limit
|
||||
- Identity mapping cleanup on disconnect (prevents stale peer tracking)
|
||||
|
|
@ -117,7 +163,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
### Known Issues
|
||||
- MAC address randomization can cause connection issues (fixed in v2.2.0)
|
||||
- Race condition from concurrent connection attempts (fixed in unreleased)
|
||||
- Race condition from concurrent connection attempts (fixed in v0.2.2)
|
||||
- BR/EDR fallback on dual-mode devices (fixed in v2.2.0)
|
||||
|
||||
---
|
||||
|
|
|
|||
1
FUNDING.yml
Normal file
1
FUNDING.yml
Normal file
|
|
@ -0,0 +1 @@
|
|||
ko_fi: torlandotech
|
||||
54
README.md
54
README.md
|
|
@ -209,9 +209,11 @@ ls ~/.local/pipx/venvs/
|
|||
sudo setcap 'cap_net_raw,cap_net_admin+eip' ~/.local/pipx/venvs/rns/bin/python3
|
||||
```
|
||||
|
||||
#### 5. Enable BlueZ Experimental Mode
|
||||
#### 5. Configure BlueZ
|
||||
|
||||
The BLE interface requires BlueZ experimental features for proper BLE connectivity:
|
||||
The BLE interface requires BlueZ experimental features and automatic pairing configuration:
|
||||
|
||||
**Enable Experimental Mode:**
|
||||
|
||||
```bash
|
||||
# Edit BlueZ service configuration
|
||||
|
|
@ -225,13 +227,28 @@ ExecStart=
|
|||
ExecStart=/usr/lib/bluetooth/bluetoothd --experimental
|
||||
```
|
||||
|
||||
Then reload and restart:
|
||||
**Enable JustWorksRepairing for Automatic Pairing:**
|
||||
|
||||
Edit `/etc/bluetooth/main.conf` and add to the `[General]` section:
|
||||
|
||||
```ini
|
||||
[General]
|
||||
JustWorksRepairing = always
|
||||
```
|
||||
|
||||
This enables automatic pairing for peer-initiated connections, which is required for zero-touch mesh networking. Reticulum provides its own cryptographic security on top of the BLE transport.
|
||||
|
||||
**Apply Changes:**
|
||||
|
||||
```bash
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl restart bluetooth.service
|
||||
|
||||
# Verify experimental mode is enabled
|
||||
systemctl status bluetooth.service | grep -i experimental
|
||||
|
||||
# Verify JustWorksRepairing is set
|
||||
grep JustWorksRepairing /etc/bluetooth/main.conf
|
||||
```
|
||||
|
||||
#### Why pipx Requires Special Handling
|
||||
|
|
@ -346,6 +363,37 @@ These errors occur when BlueZ attempts Classic Bluetooth (BR/EDR) connections in
|
|||
**Solution:**
|
||||
Enable BlueZ experimental mode (see Installation → Manual Installation → step 4). If you used the automated installer, re-run it without `--skip-experimental`.
|
||||
|
||||
### BLE pairing failures / "JustWorksRepairing: never" warning
|
||||
The BLE interface logs a warning that BlueZ's JustWorksRepairing is set to "never", which may cause pairing failures in the mesh network.
|
||||
|
||||
**Symptoms:**
|
||||
- Warning: `BlueZ JustWorksRepairing: never (default - may cause pairing failures)`
|
||||
- Recommendation message: `Set JustWorksRepairing=always in /etc/bluetooth/main.conf`
|
||||
- Intermittent connection failures with peer devices
|
||||
- Pairing requests rejected by BlueZ
|
||||
|
||||
**Cause:**
|
||||
BlueZ's default `JustWorksRepairing` setting is "never", which blocks automatic pairing for peer-initiated connections. This breaks zero-touch mesh networking.
|
||||
|
||||
**Solution:**
|
||||
Enable JustWorksRepairing in BlueZ configuration (see Installation → Manual Installation → step 5). If you used the automated installer, this is configured automatically. To verify or fix manually:
|
||||
|
||||
```bash
|
||||
# Edit BlueZ configuration
|
||||
sudo nano /etc/bluetooth/main.conf
|
||||
|
||||
# Add to [General] section:
|
||||
JustWorksRepairing = always
|
||||
|
||||
# Restart Bluetooth service
|
||||
sudo systemctl restart bluetooth
|
||||
|
||||
# Verify the setting
|
||||
grep JustWorksRepairing /etc/bluetooth/main.conf
|
||||
```
|
||||
|
||||
**Note:** Just Works pairing provides unauthenticated BLE encryption. This is acceptable because Reticulum provides its own cryptographic security on top of the BLE transport layer.
|
||||
|
||||
### Bluetooth adapter not powered / "No powered Bluetooth adapters found"
|
||||
The Bluetooth adapter exists but is powered off, preventing BLE operations.
|
||||
|
||||
|
|
|
|||
99
install.sh
99
install.sh
|
|
@ -920,6 +920,105 @@ fi
|
|||
|
||||
echo
|
||||
|
||||
# Step 5D: BlueZ JustWorksRepairing Configuration
|
||||
print_header "BlueZ JustWorksRepairing Configuration"
|
||||
|
||||
BLUEZ_CONF="/etc/bluetooth/main.conf"
|
||||
|
||||
if [ -f "$BLUEZ_CONF" ]; then
|
||||
print_info "Checking JustWorksRepairing setting in $BLUEZ_CONF..."
|
||||
|
||||
# Extract current JustWorksRepairing setting (handle commented lines)
|
||||
CURRENT_SETTING=$(grep -E "^#?\s*JustWorksRepairing\s*=" "$BLUEZ_CONF" 2>/dev/null | tail -1 | sed 's/.*=\s*//' | tr -d '[:space:]')
|
||||
|
||||
if [ "$CURRENT_SETTING" = "always" ]; then
|
||||
print_success "JustWorksRepairing is already set to 'always'"
|
||||
else
|
||||
if [ -z "$CURRENT_SETTING" ]; then
|
||||
print_info "JustWorksRepairing not found in config (using BlueZ default: never)"
|
||||
else
|
||||
print_info "JustWorksRepairing is currently set to: $CURRENT_SETTING"
|
||||
fi
|
||||
|
||||
print_info "Setting JustWorksRepairing to 'always' for automatic BLE mesh pairing..."
|
||||
echo
|
||||
print_info "Background: BlueZ's JustWorksRepairing controls automatic pairing"
|
||||
print_info "for peer-initiated connections. Setting to 'always' enables zero-touch"
|
||||
print_info "mesh networking. Reticulum provides its own cryptographic security."
|
||||
echo
|
||||
|
||||
# Modify the configuration file
|
||||
if [ "$EUID" -eq 0 ]; then
|
||||
# Running as root - no sudo needed
|
||||
# First, comment out any existing JustWorksRepairing lines
|
||||
sed -i 's/^\s*JustWorksRepairing\s*=.*/#&/' "$BLUEZ_CONF"
|
||||
|
||||
# Add our setting to the [General] section or append if no section exists
|
||||
if grep -q "^\[General\]" "$BLUEZ_CONF"; then
|
||||
# Insert after [General] section header
|
||||
sed -i '/^\[General\]/a JustWorksRepairing = always' "$BLUEZ_CONF"
|
||||
else
|
||||
# No [General] section, append at end
|
||||
echo "" >> "$BLUEZ_CONF"
|
||||
echo "[General]" >> "$BLUEZ_CONF"
|
||||
echo "JustWorksRepairing = always" >> "$BLUEZ_CONF"
|
||||
fi
|
||||
|
||||
# Restart bluetooth service (non-fatal in container/CI environments)
|
||||
print_info "Restarting bluetooth service to apply changes..."
|
||||
systemctl daemon-reload 2>/dev/null || true
|
||||
systemctl restart bluetooth 2>/dev/null || true
|
||||
else
|
||||
# Not root - use sudo
|
||||
# First, comment out any existing JustWorksRepairing lines
|
||||
sudo sed -i 's/^\s*JustWorksRepairing\s*=.*/#&/' "$BLUEZ_CONF"
|
||||
|
||||
# Add our setting to the [General] section or append if no section exists
|
||||
if grep -q "^\[General\]" "$BLUEZ_CONF"; then
|
||||
# Insert after [General] section header
|
||||
sudo sed -i '/^\[General\]/a JustWorksRepairing = always' "$BLUEZ_CONF"
|
||||
else
|
||||
# No [General] section, append at end
|
||||
echo "" | sudo tee -a "$BLUEZ_CONF" > /dev/null
|
||||
echo "[General]" | sudo tee -a "$BLUEZ_CONF" > /dev/null
|
||||
echo "JustWorksRepairing = always" | sudo tee -a "$BLUEZ_CONF" > /dev/null
|
||||
fi
|
||||
|
||||
# Restart bluetooth service (non-fatal in container/CI environments)
|
||||
print_info "Restarting bluetooth service to apply changes..."
|
||||
sudo systemctl daemon-reload 2>/dev/null || true
|
||||
sudo systemctl restart bluetooth 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Verify the setting was applied
|
||||
sleep 1
|
||||
VERIFY_SETTING=$(grep -E "^JustWorksRepairing\s*=\s*always" "$BLUEZ_CONF" 2>/dev/null)
|
||||
if [ -n "$VERIFY_SETTING" ]; then
|
||||
print_success "JustWorksRepairing set to 'always' successfully"
|
||||
|
||||
# Verify bluetooth service is running (skip in container environments)
|
||||
if systemctl is-active --quiet bluetooth 2>/dev/null; then
|
||||
print_success "Bluetooth service restarted successfully"
|
||||
elif command -v systemctl &> /dev/null && [ ! -f /.dockerenv ]; then
|
||||
# Only show warning if systemctl exists and we're not in a container
|
||||
print_warning "Bluetooth service may need manual restart"
|
||||
print_info "Check status with: sudo systemctl status bluetooth"
|
||||
else
|
||||
# Container environment or systemd not available
|
||||
print_info "Configuration updated (service restart skipped in container environment)"
|
||||
fi
|
||||
else
|
||||
print_error "Failed to set JustWorksRepairing in $BLUEZ_CONF"
|
||||
print_warning "You may need to manually add 'JustWorksRepairing = always' to [General] section"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
print_warning "$BLUEZ_CONF not found"
|
||||
print_info "JustWorksRepairing configuration skipped (BlueZ may not be installed)"
|
||||
fi
|
||||
|
||||
echo
|
||||
|
||||
# Step 6: Configuration
|
||||
print_header "Configuration"
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue