openwrt/scripts/belkin-header.py

95 lines
2.7 KiB
Python
Executable File

#!/usr/bin/python3
# SPDX-License-Identifier: GPL-2.0-or-later
#
# Copyright (C) 2024 OpenWrt.org
#
# ./belkin-header.py <ImageFileIn> <ImageFileOut> <BelkinHeader> <BelkinModel>
#
# This script adds an image header for Belkin devices. As of now only Realtek
# based switches of the Linksys LGS3xxC/LGS3xxMPC series are known to use this
# format. It resembles a U-Boot legacy format image header, all data in network
# byte order (aka natural aka big endian).
#
# Known values for BelkinHeader are
#
# 0x07800001 : RTL838x based switch
# 0x07600001 : RTL93xx based switch
#
# Known values for BelkinModel are
#
# BKS-RTL83xx : RTL838x based switch
# BKS-RTL93xx : RTL93xx based switch
import argparse
import os
import zlib
import array
import sys
import time
VERSION1 = 1
VERSION2 = 1
VERSION3 = 2
VERSION4 = 2
COMPANY = "belkin"
MODULE = "IMG"
def xcrc32(buf):
return (0xffffffff - zlib.crc32(buf, 0xffffffff)).to_bytes(4, byteorder='big')
def encode_model(model):
map = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-"
code = bytearray()
code.append(map.index(model[:1]))
model = model[1:]
model = model + " " * (3 - len(model) % 4)
while model != "":
b1 = map.index(model[0:1])
b2 = map.index(model[1:2])
b3 = map.index(model[2:3])
b4 = map.index(model[3:4])
model = model[4:]
code.append(b1 << 2 | b2 >> 4)
code.append((b2 & 0xf) << 4 | b3 >> 2)
code.append((b3 & 0x3) << 6 | b4)
return code
def create_header(buf, belkin_header, belkin_model):
head = bytearray(32)
head[0:4] = int(belkin_header, 0).to_bytes(4, 'big')
head[8:12] = int(time.time()).to_bytes(4, 'big')
head[12:16] = len(buf).to_bytes(4, byteorder='big')
head[24:28] = xcrc32(buf)
head[28:29] = VERSION1.to_bytes(1, byteorder='big')
head[29:30] = VERSION2.to_bytes(1, byteorder='big')
head[30:31] = VERSION3.to_bytes(1, byteorder='big')
head[31:32] = VERSION4.to_bytes(1, byteorder='big')
head[16:16 + len(COMPANY)] = bytes(COMPANY,'ascii')
mod = MODULE + "-{:1d}.{:02d}.{:02d}.{:02d}".format(VERSION1, VERSION2, VERSION3, VERSION4)
head.extend(bytes(mod,'ascii'))
head.append(0x00)
head.extend(encode_model(belkin_model))
head.extend(bytes([0x00] * (64 - len(head))))
head[4:8] = xcrc32(head)
return head
parser = argparse.ArgumentParser(description='Generate Belkin header.')
parser.add_argument('source', type=argparse.FileType('r+b'))
parser.add_argument('dest', type=argparse.FileType('wb'))
parser.add_argument('belkin_header')
parser.add_argument('belkin_model')
args = parser.parse_args()
buf = bytearray(args.source.read())
head = create_header(buf, args.belkin_header, args.belkin_model)
args.dest.write(head)
args.dest.write(buf)