mac-address-set: adding vcu2 support (hw23)

After an overall refactoring this script now does:

 * Wait on devices being ready before changing the address
 * Handle errors when setting wlan or bluetooth mac address
 * Handle different MAC address schemes
 * Handle different behaviors when setting wlan mac:

On HW21, the address must be set while the interface is down, but on
HW23 it must be set while the interface is up and if it is down, no
error is thrown, so the modified address is checked.

 * Handle different behaviors while setting BT mac:

On HW21, the address must be given with the bytes in reverse order.
We therefore first try with the right order and check the address and
retry with the reversed address if it failed.

BugzID: 77171

Signed-off-by: Patrick Zysset <patrick.zysset@netmodule.com>
This commit is contained in:
Alexandre Bard 2021-12-28 14:44:10 +01:00 committed by Patrick Zysset
parent 54d559d706
commit da62ee6786
1 changed files with 306 additions and 18 deletions

View File

@ -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.
# Set WLAN address
ifconfig wlan0 | grep UP > /dev/null
up=$?
if [[ $up == 0 ]]; then
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
ip link set wlan0 address $wlan_mac
return "$wlan_iface_was_up"
}
if [[ $up == 0 ]]; then
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"
# 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
return $ret
}
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
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> # loglevel being between 0 (errors) and 2 (info)"
exit 0
elif [ "$1" = "-l" ]; then
log_level="$2"
fi
main