feat: auth-failure bond recovery + BlueZ bond import for dual-boot BT
- On Authentication Failure (Auth Complete status!=0 -- previously swallowed silently -- or disconnect reason 0x05), drop the stale local link key so the next connect falls back to fresh SSP pairing instead of failing identically forever (BlueZ behavior). Log the link-key exchange. - scripts/import-bluez-bond.sh: copy a BlueZ link key into the MontaukOS key store on the installed root. Root cause: the AX211 BD_ADDR override (0xFC31) is cosmetic -- the baseband answers pages on the FACTORY address, so peers see Linux and MontaukOS as ONE device with ONE key slot, and each OS's pairing clobbers the other's key. Sharing identity + key ends the fight: both OSes reconnect (incl. autoconnect) without re-pairing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Executable
+96
@@ -0,0 +1,96 @@
|
||||
#!/bin/bash
|
||||
# import-bluez-bond.sh — share a BlueZ (Linux) Bluetooth pairing with MontaukOS.
|
||||
#
|
||||
# Dual-boot problem: the AX211's BD_ADDR override (0xFC31) is cosmetic — the
|
||||
# baseband keeps answering pages on the FACTORY address, so a peer (headset)
|
||||
# sees Linux and MontaukOS as ONE device with ONE link-key slot. Each OS
|
||||
# pairing clobbers the key the other OS depends on, and every reconnect from
|
||||
# the other OS then dies with Authentication Failure (reason 0x05).
|
||||
#
|
||||
# Fix: both OSes share the SAME identity and the SAME link key. This script
|
||||
# copies a BlueZ link key into MontaukOS's key store (os/btkeys.bin on the
|
||||
# installed root) and pins MontaukOS's configured MAC to the adapter's factory
|
||||
# address so the app reports the identity actually used on air.
|
||||
#
|
||||
# Usage:
|
||||
# sudo ./scripts/import-bluez-bond.sh <montauk-root-mount> <device-mac> [adapter-mac] [--reverse-key]
|
||||
#
|
||||
# Example:
|
||||
# sudo ./scripts/import-bluez-bond.sh /run/media/$USER/<uuid> E4:58:BC:5F:E0:30
|
||||
#
|
||||
# --reverse-key: byte-swap the key (fallback if authentication still fails).
|
||||
#
|
||||
# NOTE: replaces the MontaukOS key store with this single bond. Re-pair other
|
||||
# devices from MontaukOS afterwards if you had more.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
echo "error: must run as root (reads /var/lib/bluetooth)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TARGET="${1:?usage: import-bluez-bond.sh <montauk-root-mount> <device-mac> [adapter-mac] [--reverse-key]}"
|
||||
DEVICE="${2:?missing device MAC}"
|
||||
ADAPTER="${3:-}"
|
||||
REVERSE=0
|
||||
for arg in "$@"; do [ "$arg" = "--reverse-key" ] && REVERSE=1; done
|
||||
[ "$ADAPTER" = "--reverse-key" ] && ADAPTER=""
|
||||
|
||||
DEVICE="${DEVICE^^}"
|
||||
|
||||
# Auto-detect the adapter: the directory under /var/lib/bluetooth that holds
|
||||
# this device, preferring a factory (not locally-administered "x2:") address.
|
||||
if [ -z "$ADAPTER" ]; then
|
||||
for dir in /var/lib/bluetooth/*/; do
|
||||
a="$(basename "$dir")"
|
||||
[ -f "/var/lib/bluetooth/$a/$DEVICE/info" ] || continue
|
||||
if [ -z "$ADAPTER" ] || [[ "${ADAPTER:1:1}" == "2" && "${a:1:1}" != "2" ]]; then
|
||||
ADAPTER="$a"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
[ -n "$ADAPTER" ] || { echo "error: no adapter dir holds a bond for $DEVICE" >&2; exit 1; }
|
||||
|
||||
INFO="/var/lib/bluetooth/$ADAPTER/$DEVICE/info"
|
||||
[ -f "$INFO" ] || { echo "error: $INFO not found" >&2; exit 1; }
|
||||
KEY="$(sed -n '/^\[LinkKey\]/,/^\[/{s/^Key=//p}' "$INFO" | head -1)"
|
||||
[ -n "$KEY" ] || { echo "error: no [LinkKey] Key= in $INFO" >&2; exit 1; }
|
||||
|
||||
[ -d "$TARGET/os" ] || { echo "error: $TARGET/os missing — is the MontaukOS root mounted there?" >&2; exit 1; }
|
||||
|
||||
echo "adapter (factory identity): $ADAPTER"
|
||||
echo "device: $DEVICE"
|
||||
echo "key: ${KEY:0:4}... (${#KEY} hex chars)"
|
||||
|
||||
python3 - "$TARGET/os/btkeys.bin" "$DEVICE" "$KEY" "$REVERSE" <<'EOF'
|
||||
import sys
|
||||
path, device, keyhex, reverse = sys.argv[1], sys.argv[2], sys.argv[3], int(sys.argv[4])
|
||||
|
||||
# MontaukOS on-disk layout (kernel Hci.cpp): 'BTK1' + 8 x { addr[6], key[16], valid[1] }.
|
||||
# addr is stored LSB-first (HCI wire order); BlueZ's hex key is already in HCI order.
|
||||
addr = bytes(int(b, 16) for b in reversed(device.split(":")))
|
||||
key = bytes.fromhex(keyhex)
|
||||
assert len(key) == 16, "link key must be 16 bytes"
|
||||
if reverse:
|
||||
key = key[::-1]
|
||||
|
||||
blob = bytearray(b"BTK1")
|
||||
blob += addr + key + b"\x01" # slot 0: the imported bond
|
||||
blob += b"\x00" * 23 * 7 # slots 1..7 empty
|
||||
with open(path, "wb") as f:
|
||||
f.write(blob)
|
||||
print(f"wrote {path} ({len(blob)} bytes, 1 bond)")
|
||||
EOF
|
||||
|
||||
# Pin the configured MAC to the factory address (truthful display; the 0xFC31
|
||||
# override is cosmetic on this hardware anyway).
|
||||
CONF="$TARGET/config/bluetooth.toml"
|
||||
mkdir -p "$TARGET/config"
|
||||
if [ -f "$CONF" ] && grep -q '^ *mac *=' "$CONF"; then
|
||||
sed -i "s/^ *mac *=.*/mac = \"$ADAPTER\"/" "$CONF"
|
||||
else
|
||||
printf 'mac = "%s"\n' "$ADAPTER" >> "$CONF"
|
||||
fi
|
||||
echo "set $CONF mac = $ADAPTER"
|
||||
echo "done — boot MontaukOS; the device should reconnect without re-pairing."
|
||||
Reference in New Issue
Block a user