firmware-utils: support checksum for AVM fritzbox wasp SOCs
authorDaniel Kestrel <kestrel1974@t-online.de>
Mon, 17 Jan 2022 08:36:29 +0000 (09:36 +0100)
committerPetr Štetiar <ynezz@true.cz>
Sat, 19 Feb 2022 18:43:19 +0000 (19:43 +0100)
This patch adds creating the checksum to be able to create an
image and boot the secondary ath79 based wireless assist (WASP)
SoC with a second instance of OpenWrt for some AVM Fritzbox
devices (3390, 3490, 5490, 7490).
The utility is called avm-wasp-checksum and was originally
created by Andreas Boehler.

Signed-off-by: Daniel Kestrel <kestrel1974@t-online.de>
CMakeLists.txt
src/avm-wasp-checksum.c [new file with mode: 0644]

index 4de70d1f5142198bc1d03058c4a3fafaf81df0e1..e6592bccb157ca4a04e0c9ffa58e50510a9a87b5 100644 (file)
@@ -29,6 +29,7 @@ ENDMACRO(FW_UTIL)
 FW_UTIL(add_header "" "" "")
 FW_UTIL(addpattern "" "" "")
 FW_UTIL(asustrx "" "" "")
+FW_UTIL(avm-wasp-checksum "" --std=gnu99 "")
 FW_UTIL(bcm4908asus "" "" "")
 FW_UTIL(bcm4908kernel "" "" "")
 FW_UTIL(buffalo-enc src/buffalo-lib.c "" "")
diff --git a/src/avm-wasp-checksum.c b/src/avm-wasp-checksum.c
new file mode 100644 (file)
index 0000000..8c112f3
--- /dev/null
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2020 Andreas Boehler <dev@aboehler.at>
+ *
+ * This tool was based on:
+ *      firmware-crc.pl by Atheros Communications
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <getopt.h>     /* for getopt() */
+#include <byteswap.h>
+
+char *infile;
+char *outfile;
+char *progname;
+enum {
+       MODEL_3390,
+       MODEL_X490
+} model;
+
+#define CHUNK_SIZE 256
+
+uint32_t crc32_for_byte(uint32_t r)
+{
+       for (int j = 0; j < 8; ++j)
+               r = (r & 1 ? 0 : (uint32_t)0xEDB88320L) ^ r >> 1;
+       return r ^ (uint32_t)0xFF000000L;
+}
+
+void crc32(const void *data, size_t n_bytes, uint32_t *crc)
+{
+       static uint32_t table[0x100];
+
+       if (!*table)
+               for (size_t i = 0; i < 0x100; ++i)
+                       table[i] = crc32_for_byte(i);
+       for (size_t i = 0; i < n_bytes; ++i)
+               *crc = table[(uint8_t)*crc ^ ((uint8_t *)data)[i]] ^ *crc >> 8;
+}
+
+static void usage(int status)
+{
+       fprintf(stderr, "Usage: %s [OPTIONS...]\n", progname);
+       fprintf(stderr,
+               "\n"
+               "Options:\n"
+               "  -i              input file name\n"
+               "  -o              output file name\n"
+               "  -m              model (3390, x490 for 3490/5490/7490)\n"
+               "  -h              show this screen\n"
+       );
+
+       exit(status);
+}
+
+int main(int argc, char *argv[])
+{
+       uint32_t crc = 0;
+       FILE *in_fp;
+       FILE *out_fp;
+       uint32_t buf[CHUNK_SIZE];
+       size_t read;
+
+       progname = argv[0];
+
+       while (1) {
+               int c;
+
+               c = getopt(argc, argv, "i:o:m:h");
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'i':
+                       infile = optarg;
+                       break;
+               case 'o':
+                       outfile = optarg;
+                       break;
+               case 'm':
+                       if (strcmp(optarg, "3390") == 0)
+                               model = MODEL_3390;
+                       else if (strcmp(optarg, "x490") == 0)
+                               model = MODEL_X490;
+                       else
+                               usage(EXIT_FAILURE);
+                       break;
+               case 'h':
+                       usage(EXIT_SUCCESS);
+               default:
+                       usage(EXIT_FAILURE);
+                       break;
+               }
+       }
+
+       if (!infile || !outfile)
+               usage(EXIT_FAILURE);
+
+       in_fp = fopen(infile, "r");
+       if (!in_fp) {
+               fprintf(stderr, "Error opening input file: %s\n", infile);
+               return EXIT_FAILURE;
+       }
+       out_fp = fopen(outfile, "w");
+       if (!out_fp) {
+               fprintf(stderr, "Error opening output file: %s\n", outfile);
+               fclose(in_fp);
+               return EXIT_FAILURE;
+       }
+
+       while (!feof(in_fp)) {
+               switch (model) {
+               case MODEL_3390:
+                       read = fread(buf, sizeof(uint32_t), CHUNK_SIZE, in_fp);
+                       if (ferror(in_fp)) {
+                               fprintf(stderr, "Error reading input file: %s\n", infile);
+                               fclose(in_fp);
+                               fclose(out_fp);
+                               return EXIT_FAILURE;
+                       }
+                       for (int i = 0; i < read; i++)
+                               crc = crc ^ buf[i];
+                       fwrite(buf, sizeof(uint32_t), read, out_fp);
+                       if (ferror(out_fp)) {
+                               fprintf(stderr, "Error writing output file: %s\n", outfile);
+                               fclose(in_fp);
+                               fclose(out_fp);
+                               return EXIT_FAILURE;
+                       }
+                       break;
+               case MODEL_X490:
+                       read = fread(buf, 1, sizeof(uint32_t) * CHUNK_SIZE, in_fp);
+                       if (ferror(in_fp)) {
+                               fprintf(stderr, "Error reading input file: %s\n", infile);
+                               fclose(in_fp);
+                               fclose(out_fp);
+                               return EXIT_FAILURE;
+                       }
+                       crc32(buf, read, &crc);
+                       fwrite(buf, 1, read, out_fp);
+                       if (ferror(out_fp)) {
+                               fprintf(stderr, "Error writing output file: %s\n", outfile);
+                               fclose(in_fp);
+                               fclose(out_fp);
+                               return EXIT_FAILURE;
+                       }
+                       break;
+               }
+       }
+       if (model == MODEL_X490)
+               crc = __bswap_32(crc);
+       fwrite(&crc, sizeof(uint32_t), 1, out_fp);
+       if (ferror(out_fp)) {
+               fprintf(stderr, "Error writing checksum to output file: %s\n", outfile);
+               fclose(in_fp);
+               fclose(out_fp);
+               return EXIT_FAILURE;
+       }
+       fclose(in_fp);
+       fclose(out_fp);
+       printf("Done.\n");
+       return EXIT_SUCCESS;
+}