[firmware-utils] asus_qca_fix_checksum: new tool for ASUS QCA/QCN uImage

Enrico Mioso mrkiko.rs at gmail.com
Mon Nov 29 05:00:46 PST 2021


Sorry, the real name is required to be specified in the commit.

Enrico


On Mon, 29 Nov 2021, webmaster at playmp3.kr wrote:

> Date: Mon, 29 Nov 2021 11:56:09
> From: webmaster at playmp3.kr
> To: openwrt-devel at lists.openwrt.org
> Cc: daebo01 <daebo01 at playmp3.kr>
> Subject: [firmware-utils] asus_qca_fix_checksum: new tool for ASUS QCA/QCN
>     uImage
> 
> From: daebo01 <daebo01 at playmp3.kr>
>
> Fix checksum of Asus QCA/QCN devices.
> Tested on ac59u v1
>
> Signed-off-by: daebo01 <daebo01 at playmp3.kr>
> ---
> CMakeLists.txt              |   1 +
> src/asus_qca_fix_checksum.c | 205 ++++++++++++++++++++++++++++++++++++
> 2 files changed, 206 insertions(+)
> create mode 100644 src/asus_qca_fix_checksum.c
>
> diff --git a/CMakeLists.txt b/CMakeLists.txt
> index f406520..f551b88 100644
> --- a/CMakeLists.txt
> +++ b/CMakeLists.txt
> @@ -28,6 +28,7 @@ ENDMACRO(FW_UTIL)
>
> FW_UTIL(add_header "" "" "")
> FW_UTIL(addpattern "" "" "")
> +FW_UTIL(asus_qca_fix_checksum "" "" "${ZLIB_LIBRARIES}")
> FW_UTIL(asustrx "" "" "")
> FW_UTIL(bcm4908asus "" "" "")
> FW_UTIL(bcm4908kernel "" "" "")
> diff --git a/src/asus_qca_fix_checksum.c b/src/asus_qca_fix_checksum.c
> new file mode 100644
> index 0000000..8bb4420
> --- /dev/null
> +++ b/src/asus_qca_fix_checksum.c
> @@ -0,0 +1,205 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * asus_qca_fix_checksum.c : checksum fix for ASUS QCA/QCN SoC uImage
> + *
> + * Copyright (C) 2021 daebo01 <daebo01 at playmp3.kr>
> + *
> + * Based on:
> + * 		uimage_padhdr.c : add zero paddings after the tail of uimage header
> + * 		Copyright (C) 2019 NOGUCHI Hiroshi <drvlabo at gmail.com>
> + *
> + */
> +
> +#include <stdio.h>
> +#include <errno.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <fcntl.h>
> +#include <arpa/inet.h>
> +#include <zlib.h>
> +
> +/* from asuswrt opensource */
> +#define MAX_STRING 12
> +#define MAX_VER 5
> +
> +typedef struct
> +{
> +	uint8_t major;
> +	uint8_t minor;
> +} version_t;
> +
> +/*
> + * ASUS QCA/QCN Custom Header
> + */
> +typedef struct
> +{
> +	version_t kernel;
> +	version_t fs;
> +	char productid[MAX_STRING];
> +	uint16_t sn;
> +	uint16_t en;
> +	uint8_t pkey;
> +	uint8_t key;
> +	version_t hw[MAX_VER];
> +} TAIL;
> +
> +/* from u-boot/include/image.h */
> +#define IH_MAGIC 0x27051956 /* Image Magic Number		*/
> +#define IH_NMLEN 32			/* Image Name Length		*/
> +
> +/*
> + * Legacy format image header,
> + * all data in network byte order (aka natural aka bigendian).
> + */
> +typedef struct image_header
> +{
> +	uint32_t ih_magic; /* Image Header Magic Number	*/
> +	uint32_t ih_hcrc;  /* Image Header CRC Checksum	*/
> +	uint32_t ih_time;  /* Image Creation Timestamp	*/
> +	uint32_t ih_size;  /* Image Data Size			*/
> +	uint32_t ih_load;  /* Data	 Load  Address		*/
> +	uint32_t ih_ep;	   /* Entry Point Address		*/
> +	uint32_t ih_dcrc;  /* Image Data CRC Checksum	*/
> +	uint8_t ih_os;	   /* Operating System			*/
> +	uint8_t ih_arch;   /* CPU architecture			*/
> +	uint8_t ih_type;   /* Image Type				*/
> +	uint8_t ih_comp;   /* Compression Type			*/
> +	union
> +	{
> +		uint8_t ih_name[IH_NMLEN]; /* Image Name			*/
> +		TAIL tail;				   /* Asuswrt Custom Tail	*/
> +	} u;
> +} image_header_t;
> +
> +void fix_checksum(uint8_t *image, off_t image_len, TAIL *tail)
> +{
> +	image_header_t *header = (image_header_t *)image;
> +
> +	uint32_t checksum_a_offset = 0; // image first byte
> +	uint32_t checksum_b_offset = (ntohl(header->ih_size) + sizeof(image_header_t)) >> 1;
> +
> +	uint8_t checksum_a = image[checksum_a_offset];
> +	uint8_t checksum_b;
> +
> +	uint32_t recalc_crc;
> +
> +	if (image_len < checksum_b_offset)
> +	{
> +		fprintf(stderr, "too small uImage size\n");
> +		exit(1);
> +	}
> +
> +	checksum_b = image[checksum_b_offset];
> +
> +	tail->key = checksum_a + ~checksum_b;
> +
> +	// copy an existing image name
> +	memcpy(&tail->productid, &header->u.ih_name, sizeof(tail->productid) - 1);
> +
> +	// overwrite asus custom header to image name field
> +	header->u.tail = *tail;
> +
> +	header->ih_hcrc = 0;
> +	recalc_crc = crc32(0, image, sizeof(image_header_t));
> +	header->ih_hcrc = htonl(recalc_crc);
> +}
> +
> +void usage(char *prog)
> +{
> +	fprintf(stderr, "%s -i <input_uimage_file> -o <output_file>\n", prog);
> +	fprintf(stderr, "		-v <asuswrt version (ex. 3.0.0.4.382.52482)>");
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +	struct stat statbuf;
> +	uint8_t *filebuf;
> +	int ifd;
> +	int ofd;
> +	ssize_t rsz;
> +	int opt;
> +	char *infname = NULL;
> +	char *outfname = NULL;
> +	char *version = NULL;
> +	TAIL tail = {};
> +
> +	while ((opt = getopt(argc, argv, "i:o:v:")) != -1)
> +	{
> +		switch (opt)
> +		{
> +		case 'i':
> +			infname = optarg;
> +			break;
> +		case 'o':
> +			outfname = optarg;
> +			break;
> +		case 'v':
> +			version = optarg;
> +			if (6 != sscanf(
> +						 version, "%hhu.%hhu.%hhu.%hhu.%hu.%hu",
> +						 &tail.kernel.major, &tail.kernel.minor,
> +						 &tail.fs.major, &tail.fs.minor,
> +						 &tail.sn, &tail.en))
> +				fprintf(stderr, "Version %s doesn't match suppored 6-digits format\n", version);
> +			break;
> +		default:
> +			break;
> +		}
> +	}
> +
> +	if (!infname || !outfname || !version)
> +	{
> +		usage(argv[0]);
> +		exit(1);
> +	}
> +
> +	ifd = open(infname, O_RDONLY);
> +	if (ifd < 0)
> +	{
> +		fprintf(stderr,
> +				"could not open input file. (errno = %d)\n", errno);
> +		exit(1);
> +	}
> +
> +	ofd = open(outfname, O_WRONLY | O_CREAT, 0644);
> +	if (ofd < 0)
> +	{
> +		fprintf(stderr,
> +				"could not open output file. (errno = %d)\n", errno);
> +		exit(1);
> +	}
> +
> +	if (fstat(ifd, &statbuf) < 0)
> +	{
> +		fprintf(stderr,
> +				"could not fstat input file. (errno = %d)\n", errno);
> +		exit(1);
> +	}
> +
> +	filebuf = malloc(statbuf.st_size);
> +	if (!filebuf)
> +	{
> +		fprintf(stderr, "buffer allocation failed\n");
> +		exit(1);
> +	}
> +
> +	rsz = read(ifd, filebuf, statbuf.st_size);
> +	if (rsz != statbuf.st_size)
> +	{
> +		fprintf(stderr,
> +				"could not read input file (errno = %d).\n", errno);
> +		exit(1);
> +	}
> +
> +	fix_checksum(filebuf, statbuf.st_size, &tail);
> +
> +	rsz = write(ofd, filebuf, statbuf.st_size);
> +	if (rsz != statbuf.st_size)
> +	{
> +		fprintf(stderr,
> +				"could not write output file (errnor = %d).\n", errno);
> +		exit(1);
> +	}
> +
> +	return 0;
> +}
> -- 
> 2.20.1
>
>
> _______________________________________________
> openwrt-devel mailing list
> openwrt-devel at lists.openwrt.org
> https://lists.openwrt.org/mailman/listinfo/openwrt-devel
>



More information about the openwrt-devel mailing list