summaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
authorMaximilian Martin <mm@simonwunderlich.de>2023-06-13 12:55:59 +0200
committerHauke Mehrtens <hauke@hauke-m.de>2023-06-25 12:59:26 +0200
commit906e2a1b994ed0d965ed582f188ab94eca988b87 (patch)
tree8d590fab889f33a92c7f1f693b0574d120d524c5 /scripts
parente4fe3097ef6a961874b66932a0ac4be18070630a (diff)
downloadopenwrt-906e2a1b994ed0d965ed582f188ab94eca988b87.tar.gz
openwrt-906e2a1b994ed0d965ed582f188ab94eca988b87.tar.bz2
openwrt-906e2a1b994ed0d965ed582f188ab94eca988b87.zip
ath79: Add support for MOXA AWK-1137C
Device specifications: ====================== * Qualcomm/Atheros AR9344 * 128 MB of RAM * 16 MB of SPI NOR flash * 2x 10/100 Mbps Ethernet * 2T2R 2.4/5 GHz Wi-Fi * 4x GPIO-LEDs (1x wifi, 2x ethernet, 1x power) * 1x GPIO-button (reset) * 2x fast ethernet - lan1 + builtin switch port 1 + used as WAN interface - lan2 + builtin switch port 2 + used as LAN interface * 9-30V DC * external antennas Flashing instructions: ====================== Log in to https://192.168.127.253/ Username: admin Password: moxa Open Maintenance > Firmware Upgrade and install the factory image. Serial console access: ====================== Connect a RS232-USB converter to the maintenance port. Pinout: (reset button left) [GND] [NC] [RX] [TX] Firmware Recovery: ================== When the WLAN and SYS LEDs are flashing, the device is in recovery mode. Serial console access is required to proceed with recovery. Download the original image from MOXA and rename it to 'awk-1137c.rom'. Set up a TFTP server at 192.168.127.1 and connect to a lan port. Follow the instructions on the serial console to start the recovery. Signed-off-by: Maximilian Martin <mm@simonwunderlich.de>
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/moxa-encode-fw.py109
1 files changed, 109 insertions, 0 deletions
diff --git a/scripts/moxa-encode-fw.py b/scripts/moxa-encode-fw.py
new file mode 100755
index 0000000000..48d139b839
--- /dev/null
+++ b/scripts/moxa-encode-fw.py
@@ -0,0 +1,109 @@
+#! /usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import argparse
+import struct
+
+from binascii import crc32
+from dataclasses import dataclass
+from itertools import cycle
+from typing import List
+
+
+def xor(data: bytes) -> bytes:
+ passphrase = "Seek AGREEMENT for the date of completion.\0"
+ pw = cycle(bytearray(passphrase.encode('ascii')))
+ return bytearray(b ^ next(pw) for b in data)
+
+
+def add_fw_header(data: bytes, magic: int, hwid: int, build_id: int,
+ offsets: List[int]) -> bytes:
+ unknown_1 = 0x01
+ unknown_2 = 0x0000
+ unknown_3 = 0x00000000
+ unknown_4 = 0x01000000
+ file_crc = crc(data, 0)
+
+ header_struct = struct.Struct('>QIBBHIIIIII' + 'I' * len(offsets))
+ header_size = header_struct.size
+ file_size = header_size + len(data)
+
+ header_offsets = map(lambda x: x + header_size, offsets)
+
+ header_data = header_struct.pack(magic, file_size, unknown_1, len(offsets),
+ unknown_2, hwid, build_id, unknown_3,
+ build_id, unknown_4, *header_offsets,
+ file_crc)
+ return header_data + data
+
+
+def add_file_header(data: bytes, filename: str, build_id: int) -> bytes:
+ unknown1 = 0x01000000
+ unknown2 = 0x00000000
+ file_crc = crc(data, 0)
+
+ header_struct = struct.Struct(">16sIIIII")
+ file_size = header_struct.size + len(data)
+
+ header_data = header_struct.pack(filename.encode('ascii'), file_size,
+ unknown1, build_id, unknown2, file_crc)
+ return header_data + data
+
+
+def crc(data: bytes, init_val: int) -> int:
+ return 0xffffffff ^ (crc32(data, 0xffffffff ^ init_val))
+
+
+@dataclass
+class Partition:
+ name: str
+ size: int
+
+
+def main():
+ partitions = [
+ Partition(name='kernel', size=2048 * 1024),
+ Partition(name='root', size=9216 * 1024),
+ Partition(name='userdisk', size=3076 * 1024),
+ ]
+
+ parser = argparse.ArgumentParser(prog='moxa-encode-fw',
+ description='MOXA IW firmware encoder')
+ parser.add_argument('-i', '--input', required=True, type=str, help='Firmware file')
+ parser.add_argument('-o', '--output', required=True, type=str, help="Output path for encoded firmware file")
+ parser.add_argument('-m', '--magic', required=True, type=lambda x: int(x,0), help="Magic for firmware header")
+ parser.add_argument('-d', '--hwid', required=True, type=lambda x: int(x,0), help="Hardware id of device")
+ parser.add_argument('-b', '--buildid', required=True, type=lambda x: int(x,0), help="Build id of firmware")
+ args = parser.parse_args()
+
+ with open(args.input, 'rb') as input_file:
+ firmware = bytearray(input_file.read())
+
+ offsets = []
+ pos_input = 0
+ pos_output = 0
+ firmware_seg = bytearray()
+
+ for partition in partitions:
+ part_data = firmware[pos_input:pos_input + partition.size]
+
+ # just to make sure that no partition is empty
+ if len(part_data) == 0:
+ part_data = bytearray([0x00])
+
+ header = add_file_header(part_data, partition.name, args.buildid)
+ firmware_seg += header
+
+ offsets.append(pos_output)
+ pos_input += partition.size
+ pos_output += len(header)
+
+ moxa_firmware = add_fw_header(firmware_seg, args.magic, args.hwid, args.buildid, offsets)
+
+ encrypted = xor(moxa_firmware)
+ with open(args.output, 'wb') as output_file:
+ output_file.write(encrypted)
+
+
+if __name__ == '__main__':
+ main()