Merge Official Source
Signed-off-by: Tianling Shen <cnsztl@immortalwrt.org>
This commit is contained in:
Executable
+225
@@ -0,0 +1,225 @@
|
||||
#!/usr/bin/python3
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#
|
||||
# Copyright (C) 2025 Lukas Stockner <lukas@lukasstockner.de>
|
||||
#
|
||||
# ./aruba-header.py <input file> <output file> <build string> <version string> <oem string> <image type> <machine type>
|
||||
#
|
||||
# Generates a header for use with the APBoot bootloader on (some?) Aruba APs.
|
||||
|
||||
import argparse
|
||||
|
||||
LEN_BUILD = 256
|
||||
LEN_VERSION = 24
|
||||
LEN_OEM = 32
|
||||
|
||||
HEADER_MAGIC = b'ARUBA\0\0\0'
|
||||
|
||||
|
||||
class ValidFlag:
|
||||
YES = 1
|
||||
|
||||
|
||||
class FormatVersion:
|
||||
CURRENT = 2
|
||||
|
||||
|
||||
class ImageType:
|
||||
ELF = 0
|
||||
FPGA_BINARY = 1
|
||||
CPBOOT_BINARY = 2
|
||||
APBOOT_BINARY = 3
|
||||
TPMINFO = 4
|
||||
APBOOT_STAGE1_BINARY = 5
|
||||
APBOOT_STAGE2_BINARY = 6
|
||||
APBOOT_COMBINED_BINARY = 7
|
||||
OS_ANCILLARY_IMAGE = 8
|
||||
XLOADER_BINARY = 9
|
||||
GRUB_BIN = 10
|
||||
LSM_PACKAGE = 11
|
||||
|
||||
|
||||
class CompressionType:
|
||||
NONE = 0
|
||||
BZIP2 = 1
|
||||
GZIP = 2
|
||||
|
||||
|
||||
MACHINE_TYPES = {
|
||||
'MSWITCH': 0,
|
||||
'CABERNET': 1,
|
||||
'SYRAH': 2,
|
||||
'MERLOT': 3,
|
||||
'MUSCAT': 4,
|
||||
'NEBBIOLO': 5,
|
||||
'MALBEC': 6,
|
||||
'PALOMINO': 7,
|
||||
'GRENACHE': 8,
|
||||
'MOSCATO': 9,
|
||||
'TALISKER': 10,
|
||||
'JURA_R': 11,
|
||||
'SCAPA': 12,
|
||||
'JURA_O': 13,
|
||||
'CORVINA': 14,
|
||||
'ARRAN': 15,
|
||||
'BLUEBLOOD': 16,
|
||||
'MSR2K': 17,
|
||||
'PORFIDIO': 18,
|
||||
'CAZULO': 19,
|
||||
'SCAPA_H': 20,
|
||||
'CARDHU': 21,
|
||||
'BOWMORE': 22,
|
||||
'TAMDHU': 23,
|
||||
'ARDBEG': 24,
|
||||
'ARDMORE': 25,
|
||||
'DALMORE': 26,
|
||||
'K2': 27,
|
||||
'GRAPPA': 28,
|
||||
'SHUMWAY': 29,
|
||||
'SPRINGBANK': 30,
|
||||
'OUZO': 31,
|
||||
'AMARULA': 32,
|
||||
'GROZDOVA': 33,
|
||||
'PALINKA': 34,
|
||||
'HAZELBURN': 35,
|
||||
'TOMATIN': 36,
|
||||
'HAZELBURN_H': 37,
|
||||
'TOMATIN_16': 38,
|
||||
'SPRINGBANK_16': 39,
|
||||
'OCTOMORE': 40,
|
||||
'BALVENIE': 41,
|
||||
'OUZO_PLUS': 42,
|
||||
'X4': 43,
|
||||
'EINAR': 44,
|
||||
'GLENFARCLAS': 45,
|
||||
'GLENFIDDICH': 46,
|
||||
'EIGER': 47,
|
||||
'GLENMORANGIE': 48,
|
||||
'MILAGRO': 49,
|
||||
'OPUSONE': 50,
|
||||
'ABERLOUR': 51,
|
||||
'MILLSTONE': 52,
|
||||
'DEWARS': 53,
|
||||
'BUNKER': 54,
|
||||
'MASTERSON': 55,
|
||||
'SIERRA': 56,
|
||||
'KILCHOMAN': 57,
|
||||
'SPEYBURN': 58,
|
||||
'LAGAVULIN': 59,
|
||||
'LAPHROAIG': 60,
|
||||
'TOBA': 61,
|
||||
'ARRANTA': 62,
|
||||
}
|
||||
|
||||
|
||||
class NextHeader:
|
||||
NONE = 0x00000000
|
||||
SIGN = 0x01111111
|
||||
|
||||
|
||||
class Flags:
|
||||
C_TEST_BUILD = 0x00000001
|
||||
SWATCH = 0x00000002
|
||||
# Preserves the image with "clear all"
|
||||
DONT_CLEAR_ON_PURGE = 0x00000004
|
||||
SECURE_BOOTLOADER = 0x00000008
|
||||
FACTORY_IMAGE = 0x00000010
|
||||
FIPS_CERTIFIED = 0x00000020
|
||||
|
||||
|
||||
def make_header(data: bytes, build: str, version: str, oem: str, imageType: int, machine: int) -> bytes:
|
||||
buildBytes = build.encode(encoding='ascii')
|
||||
assert len(buildBytes) < LEN_BUILD
|
||||
buildBytes += b'\0' * (LEN_BUILD - len(buildBytes))
|
||||
|
||||
versionBytes = version.encode(encoding='ascii')
|
||||
assert len(versionBytes) < LEN_VERSION
|
||||
versionBytes += b'\0' * (LEN_VERSION - len(versionBytes))
|
||||
|
||||
oemBytes = oem.encode(encoding='ascii')
|
||||
assert len(oemBytes) < LEN_OEM
|
||||
oemBytes += b'\0' * (LEN_OEM - len(oemBytes))
|
||||
|
||||
header = b''
|
||||
# Payload size, image plus optional signature (which we don't use)
|
||||
header += len(data).to_bytes(4, 'big')
|
||||
# Use what appears to be the current version
|
||||
header += FormatVersion.CURRENT.to_bytes(4, 'big')
|
||||
# Checksum is computed later
|
||||
header += b'\0\0\0\0'
|
||||
# Vendor magic number
|
||||
header += HEADER_MAGIC
|
||||
# Long build information string
|
||||
header += buildBytes
|
||||
# Short version information string
|
||||
header += versionBytes
|
||||
# Image is valid
|
||||
header += ValidFlag.YES.to_bytes(1, 'big')
|
||||
# Image type
|
||||
header += imageType.to_bytes(1, 'big')
|
||||
# APBoot doesn't appear to actually support compression
|
||||
header += CompressionType.NONE.to_bytes(1, 'big')
|
||||
# Machine type
|
||||
header += machine.to_bytes(1, 'big')
|
||||
# Image size
|
||||
header += len(data).to_bytes(4, 'big')
|
||||
# Next header (we don't support signing)
|
||||
header += NextHeader.NONE.to_bytes(4, 'big')
|
||||
# MD5 checksum plus fudge factor (to ensure non-zero hash), appears unused
|
||||
header += b'\0' * 16
|
||||
header += b'\0' * 4
|
||||
# No flags are set
|
||||
header += int(0).to_bytes(4, 'big')
|
||||
# No next header is used
|
||||
header += b'\0' * 12
|
||||
# Padding
|
||||
header += b'\0' * 36
|
||||
# OEM string
|
||||
header += oemBytes
|
||||
# Padding
|
||||
header += b'\0' * 96
|
||||
|
||||
assert len(header) == 512
|
||||
assert len(data) % 4 == 0
|
||||
|
||||
# Compute checksum such that the big-endian sum of all 32-bit integers becomes zero.
|
||||
curSum = sum(int.from_bytes(header[i : i + 4], 'big') for i in range(0, 512, 4))
|
||||
curSum += sum(int.from_bytes(data[i : i + 4], 'big') for i in range(0, len(data), 4))
|
||||
|
||||
# Set checksum
|
||||
checksum = 0x100000000 - (curSum % 0x100000000)
|
||||
header = header[:8] + checksum.to_bytes(4, 'big') + header[12:]
|
||||
|
||||
return header
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description='Generate Aruba header.')
|
||||
parser.add_argument('source')
|
||||
parser.add_argument('dest')
|
||||
parser.add_argument('build')
|
||||
parser.add_argument('version')
|
||||
parser.add_argument('oem')
|
||||
parser.add_argument('type', choices=['os', 'boot'])
|
||||
parser.add_argument('machine', choices=MACHINE_TYPES.keys(), type=str.upper)
|
||||
args = parser.parse_args()
|
||||
|
||||
# Parse image type.
|
||||
# The OS image must be type "ELF" even though it's not an ELF file...
|
||||
imageType = {'os': ImageType.ELF, 'boot': ImageType.APBOOT_BINARY}[args.type]
|
||||
# Parse machine type.
|
||||
machineType = MACHINE_TYPES[args.machine]
|
||||
|
||||
source = open(args.source, 'rb')
|
||||
image = source.read()
|
||||
# Pad image.
|
||||
if len(image) % 4 != 0:
|
||||
image += b'\0' * (4 - len(image) % 4)
|
||||
|
||||
# Generate header.
|
||||
header = make_header(image, args.build, args.version, args.oem, imageType, machineType)
|
||||
|
||||
# Write output.
|
||||
dest = open(args.dest, 'wb')
|
||||
dest.write(header)
|
||||
dest.write(image)
|
||||
Reference in New Issue
Block a user