mac-address: Migrate mac-address setting script to correct package

This is specific to enterprise boards, so it should go in the BSP.

Change-Id: I09b9f5047618dd31e75fc3e76d82b81b1cdbe245
diff --git a/etc/runonce.d/10-set-mac-addresses b/etc/runonce.d/10-set-mac-addresses
new file mode 100755
index 0000000..893ebd4
--- /dev/null
+++ b/etc/runonce.d/10-set-mac-addresses
@@ -0,0 +1,152 @@
+#!/usr/bin/python2.7
+
+'''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 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)
+
+    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()