From 1ac151a813deebcc3c98e67f2ea5f0397fcd5c40 Mon Sep 17 00:00:00 2001
From: Clayton Craft <clayton@craftyguy.net>
Date: Fri, 17 Jan 2025 10:01:56 -0800
Subject: [PATCH] Add retry mechnism for setting BT and wlan MAC addr

This replaces 3bfb183fc506 with a retry mechanism, where the BT and wlan
mac is (re)tried every 1 second for up to 5 seconds (configurable).

If this doesn't play nicely with udev rules when using RUN, then
BT_TIMEOUT and/or WLAN_TIMEOUT can be set in the env.
---
 bootmac | 44 ++++++++++++++++++++++++++++++++++++++------
 1 file changed, 38 insertions(+), 6 deletions(-)

diff --git a/bootmac b/bootmac
index c21290d..eda09a7 100755
--- a/bootmac
+++ b/bootmac
@@ -16,6 +16,8 @@ WLAN_INTERFACE="wlan0"
 BT_INTERFACE="hci0"
 # Default MAC prefix
 MAC_PREFIX="0200"
+BT_TIMEOUT=${BT_TIMEOUT:-5} # seconds
+WLAN_TIMEOUT=${WLAN_TIMEOUT:-5} # seconds
 
 log() {
     echo "$@" | logger -t "bootmac"
@@ -141,9 +143,6 @@ mac_generate() {
 }
 
 mac_bluetooth() {
-    # Some Bluetooth adapters take time before they can be configured
-    sleep 1
-
     log "setting Bluetooth MAC to $BT_MAC"
 
     # Check if the Bluetooth interface is up
@@ -162,7 +161,24 @@ mac_bluetooth() {
     # The 'yes | btmgmt xxx' workaround is needed for proper working of btmgmt
     # as noted in https://gitlab.com/postmarketOS/bootmac/-/issues/3
     yes | btmgmt -i "$BT_INTERFACE" power off
-    yes | btmgmt -i "$BT_INTERFACE" public-addr "$BT_MAC"
+
+    # Setting the mac addr might fail if the device/driver hasn't finished
+    # initializing, so retry
+    timeout=0
+    while [ $timeout -lt "$BT_TIMEOUT" ]; do
+        if yes | btmgmt -i "$BT_INTERFACE" public-addr "$BT_MAC"; then
+            break
+        fi
+        log "Unable to set Bluetooth MAC, retrying after 1 second..."
+        sleep 1
+        timeout=$((timeout + 1))
+    done
+
+    if [ $timeout -ge "$BT_TIMEOUT" ]; then
+        log "Failed to set Bluetooth MAC address, command timed out after $BT_TIMEOUT seconds"
+        return 1
+    fi
+
     if [ -n "$BT_RFKILL_UNBLOCKED" ]; then
         log "restoring Bluetooth rfkill state to unblocked"
         rfkill unblock bluetooth
@@ -180,8 +196,24 @@ mac_wlan() {
     set -e
 
     # Bring WLAN down, set the extracted MAC and bring it up again
-    ip link set dev "$WLAN_INTERFACE" down
-    ip link set dev "$WLAN_INTERFACE" address "$WLAN_MAC"
+    # Setting the mac addr might fail if the device/driver hasn't finished
+    # initializing, so retry
+    timeout=0
+    while [ $timeout -lt "$WLAN_TIMEOUT" ]; do
+        if ip link set dev "$WLAN_INTERFACE" down \
+                && ip link set dev "$WLAN_INTERFACE" address "$WLAN_MAC" ; then
+            break
+        fi
+        log "Unable to set wlan MAC, retrying after 1 second..."
+        sleep 1
+        timeout=$((timeout + 1))
+    done
+
+    if [ $timeout -ge "$WLAN_TIMEOUT" ]; then
+        log "Failed to set wlan MAC address, command timed out after $WLAN_TIMEOUT seconds"
+        return 1
+    fi
+
     if [ -n "$WLAN_RFKILL_UNBLOCKED" ]; then
       log "restoring WLAN rfkill state to unblocked"
       rfkill unblock wlan
-- 
GitLab