From: Alisha Kim <daeb...@playmp3.kr>

Fix checksum of Asus QCA/QCN devices.
Tested on ac59u v1

Signed-off-by: Alisha Kim <daeb...@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..511f101
--- /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 Alisha Kim <daeb...@playmp3.kr>
+ *
+ * Based on:
+ *             uimage_padhdr.c : add zero paddings after the tail of uimage 
header
+ *             Copyright (C) 2019 NOGUCHI Hiroshi <drvl...@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@lists.openwrt.org
https://lists.openwrt.org/mailman/listinfo/openwrt-devel

Reply via email to