diff --git a/recipes-bsp/mac-address-set/files/mac-address-set.sh b/recipes-bsp/mac-address-set/files/mac-address-set.sh index 3b6a51d..e46c1f3 100755 --- a/recipes-bsp/mac-address-set/files/mac-address-set.sh +++ b/recipes-bsp/mac-address-set/files/mac-address-set.sh @@ -1,25 +1,313 @@ #!/usr/bin/env bash -eth_mac=$(ip addr show eth0 | awk '$1 == "link/ether" {gsub(/\/.*$/, "", $2); print $2}') -wlan_mac=$(echo $eth_mac | sed -r "s/^(.{9})50(.{6})/\170\2/") -bt_addr=$(echo $eth_mac | sed -r "s/^(.{9})50(.{6})/\180\2/") +help_text=' +This script configures bluetooth and wifi mac addresses +It is using the eth0 mac address as reference and then applying +a logical operation based on the mac address range. + +Since the handling of wifi and bluetooth devices may be different +on different devices, this script is doing several attempts with +different approaches to be compatible with all devices. + +Currently supported devices: HW21 and HW23 + +It currently supports two schemes: + +* VCU1 scheme, starts with 7C:97:63: and ends with: + eth0: :50:XX:YY + wlan0: :70:XX:YY + bt0: :80:XX:YY + +* VCU2 scheme, starts with 00:11:2B: and ends with: + eth0: :XX:YY:ZZ + wlan0: :XX:YY:ZZ+3 + bt0: :XX:YY:ZZ+4 + +This script is NOT setting eth0 mac address, this must be done +before (usually bootloader). +' + +level_error=0 +level_warning=1 +level_info=2 + +log_level="$level_info" + +log () { + msg_level="$1" + level_string="$2" + msg="$3" + + if [ "$log_level" -ge "$msg_level" ]; then + echo "$0: $level_string: $msg" + fi +} + +log_info() { + msg="$1" + log "$level_info" "info" "$msg" +} + +log_warning() { + msg="$1" + log "$level_warning" "warning" "$msg" +} + +log_error() { + msg="$1" + log "$level_error" "error" "$msg" +} + +wait_on() { + cmd=$1 + device=$2 + if $cmd "$device" > /dev/null 2>/dev/null; then + return + fi + log_info "$device not ready" + log_info "Waiting...." + while ! $cmd "$device" > /dev/null 2>/dev/null; do + sleep 1 + done + log_info "$device ready" +} + +wait_on_wlan0() { + wait_on ifconfig wlan0 +} + +wait_on_hci0() { + wait_on hciconfig hci0 +} + +is_wlan0_up() { + if ifconfig wlan0 | grep UP > /dev/null; + then + return "1" + else + return "0" + fi +} + +set_wlan_mac_address() { + address=$1 + log_info "Setting wlan0 mac address to $address" + ip link set wlan0 address "$address" + ret=$? + if [ $ret -ne 0 ]; then + log_warning "Setting wlan address failed $ret" + fi + return $ret +} + +set_and_check_wlan_mac_address() { + address=$1 + + set_wlan_mac_address "$address" + ret=$? + + if [ $ret -ne 0 ]; then + log_warning "Setting wlan address failed: $ret" + return $ret + fi + + log_info "Checking success" + # Setting the mac may fail without error + # Checking MAC to be sure it worked + if ifconfig wlan0 | grep -i "$address" > /dev/null; then + log_info "wlan mac address successfully set" + return 0 + else + log_warning "Setting wlan address failed without throwing an error" + return 1 + fi +} + +prepare_wlan() { + is_wlan0_up + wlan_iface_was_up=$? + + if [[ "$wlan_iface_was_up" -eq "1" ]]; then + log_info "Taking wlan0 down" + ifconfig wlan0 down + fi + return "$wlan_iface_was_up" +} + +unprepare_wlan() { + wlan_iface_was_up=$1 + + if [[ "$wlan_iface_was_up" -eq "1" ]]; then + log_info "Taking wlan0 back up" + ifconfig wlan0 up + else + log_info "Making sure wlan0 is down" + ifconfig wlan0 down + fi +} + +prepare_and_set_wlan_mac_address() { + address="$1" + + wait_on_wlan0 + prepare_wlan + wlan_iface_was_up=$? + + set_and_check_wlan_mac_address "$address" + ret=$? + if [[ "$ret" -ne 0 ]]; then + # On some devices the interface must be up to set the address + log_warning "Setting wlan address failed, trying with interface up" + ifconfig wlan0 up + set_and_check_wlan_mac_address "$address" + ret=$? + fi + + unprepare_wlan "$wlan_iface_was_up" + + return $ret +} -# Set WLAN address -ifconfig wlan0 | grep UP > /dev/null -up=$? -if [[ $up == 0 ]]; then - ifconfig wlan0 down -fi -ip link set wlan0 address $wlan_mac +set_and_check_bt_mac_address() { + address="$1" + addr_to_set="$address" # Because of some bug the address to set may be inverted + invert="$2" + if [[ "$invert" -eq "1" ]]; then + addr_to_set=$(echo "$address" | sed -r "s/^(.{2}):(.{2}):(.{2}):(.{2}):(.{2}):(.{2})/\\6:\\5:\\4:\\3:\\2:\\1/") + fi -if [[ $up == 0 ]]; then - ifconfig wlan0 up + bdaddr "$addr_to_set" > /dev/null + ret=$? + if [ $ret -ne 0 ]; then + log_warning "Setting bluetooth address failed: $ret" + fi + + log_info "Restarting bluetooth service" + hciconfig hci0 reset + systemctl restart bluetooth + sleep 1 + wait_on_hci0 + hciconfig hci0 up + + log_info "Checking success" + if hciconfig hci0 | grep -i "$address" > /dev/null; then + log_info "Bluetooth address successfully set" + ret=0 + else + log_warning "Setting bluetooth address failed without error" + ret=1 + fi + return $ret +} + +prepare_and_set_bt_mac_address() { + address=$1 + + wait_on_hci0 + + hciconfig hci0 up + + log_info "Setting bluetooth mac address to $address" + set_and_check_bt_mac_address "$address" 0 + ret=$? + if [ $ret -ne 0 ]; then + log_info "Trying with reversed address" # This is a bug in some systems + set_and_check_bt_mac_address "$address" 1 + ret=$? + fi + + return $ret +} + +# VCU1 scheme, starts with 7C:97:63: +# eth0: 50:XX:YY +# wlan0: 70:XX:YY +# bt0: 80:XX:YY +is_vcu1_mac() { + [[ $1 == "7C:97:63:"* ]] +} + +vcu1_eth_to_wlan() { + echo "$1" | sed -r "s/^(.{9})50(.{6})/\\170\\2/" +} + +vcu1_eth_to_bt() { + echo "$1" | sed -r "s/^(.{9})50(.{6})/\\180\\2/" +} + +# VCU2 scheme, starts with 00:11:2B: +# eth0: XX:YY:ZZ +# wlan0: XX:YY:ZZ+3 +# bt0: XX:YY:ZZ+4 +is_vcu2_mac() { + [[ $1 == "00:11:2B:"* ]] +} + +vcu2_eth_to_wlan_and_bt() { + IFS=':' read -r -a digits <<< "$1" + + digits[5]=$((digits[5] + 3)) + wlan_mac=$(printf ":%s" "${digits[@]}") + wlan_mac=${wlan_mac:1} # Remove first ":" + + digits[5]=$((digits[5] + 1)) + bt_mac=$(printf ":%s" "${digits[@]}") + bt_mac=${bt_mac:1} # Remove first ":" + + + echo "$wlan_mac" + echo "$bt_mac" +} + + + +main() { + ret=0 + + eth_mac=$(ip addr show eth0 | awk '$1 == "link/ether" {gsub(/\/.*$/, "", $2); print $2}') + eth_mac=${eth_mac^^} # UPPER case + if is_vcu1_mac "$eth_mac"; then + log_info "VCU1 mac address scheme" + wlan_mac=$(vcu1_eth_to_wlan "$eth_mac") + bt_addr=$(vcu1_eth_to_bt "$eth_mac") + elif is_vcu2_mac "$eth_mac"; then + log_info "VCU2 mac address scheme" + wlan_and_bt_macs=$(vcu2_eth_to_wlan_and_bt "$eth_mac") + wlan_mac=$(echo "$wlan_and_bt_macs" | head -n 1) + bt_addr=$(echo "$wlan_and_bt_macs" | tail -n 1) + else + log_error "Unknown mac address scheme for: $eth_mac" + exit 1 + fi + + prepare_and_set_wlan_mac_address "$wlan_mac" + ret_wlan=$? + if [ $ret_wlan -ne 0 ]; then + log_error "Failed to set wlan mac address" + ret="$ret_wlan" + fi + + prepare_and_set_bt_mac_address "$bt_addr" + ret_bt=$? + if [ $ret_bt -ne 0 ]; then + log_error "Failed to set bluetooth mac address" + ret="$ret_bt" + fi + + exit "$ret" +} + + + +if [ "$1" = "-h" ]; then + echo "$help_text" + echo "Usage:" + echo " $0" + echo " $0 -l # loglevel being between 0 (errors) and 2 (info)" + exit 0 +elif [ "$1" = "-l" ]; then + log_level="$2" fi - -# Set BT address -bt_addr_rev=$(echo $bt_addr | sed -r "s/^(.{2}):(.{2}):(.{2}):(.{2}):(.{2}):(.{2})/\6:\5:\4:\3:\2:\1/") -bdaddr $bt_addr_rev -hciconfig hci0 reset -systemctl restart bluetooth +main