[firmware-utils 2/2] iptime-crc32: add image header tool for new ipTIME models

Sungbo Eo mans0n at gorani.run
Sat Jan 22 05:40:16 PST 2022


Some ipTIME models (e.g. A8004T-XR) started to use a new 56-byte header
format which uses accumulated CRC-32 for its checksum algorithm. This tool
helps to pass through the factory image verification process on the
applicable models.

Signed-off-by: Sungbo Eo <mans0n at gorani.run>
---
 CMakeLists.txt     |   1 +
 src/iptime-crc32.c | 147 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 148 insertions(+)
 create mode 100644 src/iptime-crc32.c

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9c7e0e1..46af4b3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -42,6 +42,7 @@ FW_UTIL(encode_crc "" "" "")
 FW_UTIL(fix-u-media-header src/cyg_crc32.c "" "")
 FW_UTIL(hcsmakeimage src/bcmalgo.c "" "")
 FW_UTIL(imagetag "src/imagetag_cmdline.c;src/cyg_crc32.c" "" "")
+FW_UTIL(iptime-crc32 src/cyg_crc32.c "" "")
 FW_UTIL(iptime-naspkg "" "" "")
 FW_UTIL(jcgimage "" "" "${ZLIB_LIBRARIES}")
 FW_UTIL(lxlfw "" "" "")
diff --git a/src/iptime-crc32.c b/src/iptime-crc32.c
new file mode 100644
index 0000000..51b0519
--- /dev/null
+++ b/src/iptime-crc32.c
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2021 Sungbo Eo <mans0n at gorani.run>
+ *
+ * This code is based on mkdhpimg.c and mkzcfw.c
+ * Copyright (C) 2010 Gabor Juhos <juhosg at openwrt.org>
+ * Copyright (c) 2016 FUKAUMI Naoki <naobsd at gmail.com>
+ *
+ * Checksum algorithm is derived from add_iptime_fw_header.c
+ * Copyright (C) 2020 Jaehoon You <teslamint at gmail.com>
+ */
+
+#include <byteswap.h>
+#include <endian.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "cyg_crc.h"
+
+#if !defined(__BYTE_ORDER)
+#error "Unknown byte order"
+#endif
+
+#if (__BYTE_ORDER == __BIG_ENDIAN)
+#define HOST_TO_LE32(x)	bswap_32(x)
+#elif (__BYTE_ORDER == __LITTLE_ENDIAN)
+#define HOST_TO_LE32(x)	(x)
+#else
+#error "Unsupported endianness"
+#endif
+
+#define FW_VERSION	"00_000"
+
+struct fw_header {
+	uint8_t model[8];
+	uint8_t version[8];
+	uint8_t reserved[32];
+	uint32_t size;
+	uint32_t checksum;
+} __attribute__ ((packed));
+
+struct board_info {
+	const char *model;
+	size_t payload_offset;
+};
+
+struct board_info boards[] = {
+	{ .model = "ax2004m", .payload_offset = 0x38 },
+	{ /* sentinel */ }
+};
+
+struct board_info *find_board(const char *model)
+{
+	struct board_info *ret = NULL;
+	struct board_info *board;
+
+	for (board = boards; board->model != NULL; board++) {
+		if (strcmp(model, board->model) == 0) {
+			ret = board;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+uint32_t make_checksum(struct fw_header *header, uint8_t *payload, int size)
+{
+	cyg_uint32 checksum;
+
+	/* get CRC of header */
+	checksum = cyg_crc32_accumulate(~0L, header, sizeof(*header));
+
+	/* get CRC of payload buffer with header CRC as initial value */
+	return (uint32_t)cyg_crc32_accumulate(checksum, payload, size);
+}
+
+void make_header(struct board_info *board, uint8_t *buffer, size_t img_size)
+{
+	struct fw_header *header = (struct fw_header *)buffer;
+	uint32_t checksum;
+
+	strncpy((char *)header->model, board->model, sizeof(header->model)-1);
+	strncpy((char *)header->version, FW_VERSION, sizeof(header->version)-1);
+	header->size = HOST_TO_LE32(img_size);
+	checksum = make_checksum(header, buffer + board->payload_offset, img_size);
+	header->checksum = HOST_TO_LE32(checksum);
+}
+
+int main(int argc, const char *argv[])
+{
+	const char *model_name, *img_in, *img_out;
+	struct board_info *board;
+	int file_in, file_out;
+	struct stat stat_in;
+	size_t size_in, size_out;
+	uint8_t *buffer;
+
+	if (argc != 4) {
+		fprintf(stderr, "Usage: %s <model> <input> <output>\n", argv[0]);
+		return EXIT_FAILURE;
+	}
+	model_name = argv[1];
+	img_in = argv[2];
+	img_out = argv[3];
+
+	board = find_board(model_name);
+	if (board == NULL) {
+		fprintf(stderr, "%s: Not supported model\n", model_name);
+		return EXIT_FAILURE;
+	}
+
+	if ((file_in = open(img_in, O_RDONLY)) == -1)
+		err(EXIT_FAILURE, "%s", img_in);
+
+	if (fstat(file_in, &stat_in) == -1)
+		err(EXIT_FAILURE, "%s", img_in);
+
+	size_in = stat_in.st_size;
+	size_out = board->payload_offset + size_in;
+
+	if ((buffer = malloc(size_out)) == NULL)
+		err(EXIT_FAILURE, "malloc");
+
+	read(file_in, buffer + board->payload_offset, size_in);
+	close(file_in);
+
+	memset(buffer, 0, board->payload_offset);
+
+	make_header(board, buffer, size_in);
+
+	if ((file_out = creat(img_out, 0644)) == -1)
+		err(EXIT_FAILURE, "%s", img_out);
+	write(file_out, buffer, size_out);
+	close(file_out);
+
+	free(buffer);
+
+	return EXIT_SUCCESS;
+}
-- 
2.34.1




More information about the openwrt-devel mailing list