blob: 83b2c39df3bb5e1abe133716b3fedb8e0355dc79 [file] [log] [blame]
#!/usr/bin/python
'''This script generates the wifi and bluetooth MAC addresses assigned to a
board, given the MAC address of it's primary ethernet interface. It's primary
purpose is to store the MAC addresses in files on the root filesystem after
system first start because we cannot burn these addresses into the peripherals,
other than the ethernet PHY.
This script only works in the case where the MAC addresses have been allocated
in a monotonically adjacent style for all devices, and that wifi/bluetooth
follows the ethernet MAC in series.
'''
import struct
import sys
MAC_VENDOR_PREFIX_STR = '70:20:84'
BD_ADDR_PATH = '/etc/bluetooth/.bt_nv.bin'
WIFI_ADDR_PATH = '/lib/firmware/wlan/wlan_mac.bin'
BD_NVITEM = 0x02
BD_RDWR_PROT = 0x00
BD_NVITEM_SIZE = 0x06
BD_ADDR_HEADER_STRUCT = r'BBB'
BD_ADDR_MAC_STRUCT = r'BBBBBB'
WIFI_CONFIG_TEMPLATE = '''\
Intf0MacAddress={0}
END
'''
ETHERNET_DEVICE = 'eth0'
def GenerateNextMac(mac_address_str):
'''Given a MAC address string, generate the next MAC address in sequence.
Note: this strips off the vendor prefix and increments as though the suffix
was an integer. If the device suffix rolls over, there is no error thrown or
any other checking done.
Parameters:
mac_address_str: string. Colon-separated six-octet hexidecimal MAC address.
Returns:
string. The next MAC address in the sequence.
'''
device_suffix = GetMacDeviceSuffixString(mac_address_str)
suffix_number = MacDeviceSuffixToNumber(device_suffix)
suffix_string = MacDeviceSuffixNumberToString(suffix_number + 1)
next_mac = MAC_VENDOR_PREFIX_STR + ':' + suffix_string
return next_mac
def MacDeviceSuffixNumberToString(device_suffix_number):
'''Given a device suffix number, generate a colon-separated hexidecimal
representation.
Parameters:
device_suffix_number: integer. The number to convert into a MAC suffix.
Returns:
string. The colon-separated hexidecimal version of the number passed in.
'''
suffix_string = '%06x' % device_suffix_number
suffix_array = []
for idx in range(0, len(suffix_string), 2):
suffix_array.append(suffix_string[idx] + suffix_string[idx + 1])
return ':'.join(suffix_array)
def MacDeviceSuffixToNumber(mac_suffix):
'''Converts a given a three-octet colon separated hexidecimal MAC device suffix
into an integer.'''
mac_array = mac_suffix.split(':')
flatmac = ''.join(mac_array)
return int(flatmac, 16)
def GetMacDeviceSuffixString(mac_address):
'''Strip the vendor prefix from a given a full six-octet colon separated
hexidecimal MAC.'''
mac_array = mac_address.split(':')
return ':'.join(mac_array[3:])
def FindEthernetMacString(device):
'''Returns the MAC address string for a given network device from sysfs.
If an error occurs attempting to read from sysfs, or runs into an EOF
prematurely, returns None.
'''
sysfs_path = '/sys/class/net/%s/address' % (device)
try:
with open(sysfs_path, 'r') as fp:
address = fp.readline()
if len(address) == 0:
return None
address = address[:-1]
return address
except Exception as e:
print('Error reading %s: %s' % (sysfs_path, e))
return None
def WriteWifiMacAddress(next_mac):
'''Writes the given MAC address string to the wifi configuration files.'''
try:
with open(WIFI_ADDR_PATH, 'w') as fp:
fp.write(WIFI_CONFIG_TEMPLATE.format(next_mac.translate(None, ':')))
return True
except Exception as e:
print('Error writing wifi configuration to %s: %s' % (WIFI_ADDR_PATH, e))
return False
def WriteBluetoothMacAddress(next_mac):
'''Writes the given MAC address string to a binary file readable by Bluez.'''
mac_bytes = [int(x, 16) for x in next_mac.split(':')]
try:
with open(BD_ADDR_PATH, 'w') as fp:
fp.write(struct.pack(BD_ADDR_HEADER_STRUCT, BD_NVITEM, BD_RDWR_PROT,
BD_NVITEM_SIZE))
fp.write(struct.pack(BD_ADDR_MAC_STRUCT, *mac_bytes))
return True
except Exception as e:
print('Error writing bluetooth configuration to %s: %s' % (BD_ADDR_PATH, e))
def IsDVTMacAddress(base_mac_address):
'''Checks to see if the given MAC address is within the allocated DVT range.'''
dvt_mac_start = MacDeviceSuffixToNumber('51:F7:6E')
dvt_mac_end = MacDeviceSuffixToNumber('51:FA:1B')
mac_suffix = MacDeviceSuffixToNumber(GetMacDeviceSuffixString(base_mac_address))
if mac_suffix >= dvt_mac_start and mac_suffix <= dvt_mac_end:
return True
return False
def Main():
base_mac_address = FindEthernetMacString(ETHERNET_DEVICE)
if base_mac_address == None:
sys.stderr.write('Unable to find MAC address for device %s\n' % (ETHERNET_DEVICE))
sys.exit(1)
if IsDVTMacAddress(base_mac_address):
sys.stderr.write('Detected DVT MAC address for device %s\n' % (ETHERNET_DEVICE))
sys.stderr.write('Cowardly refusing to set the MAC addresses\n')
sys.exit(0)
next_mac = GenerateNextMac(base_mac_address)
print('Wifi/Bt MAC address will be %s' % next_mac)
WriteWifiMacAddress(next_mac)
WriteBluetoothMacAddress(next_mac)
if __name__ == '__main__':
Main()