firmware-utils: add sercomm/netgear tool
authorLudwig Thomeczek <ledesrc@wxorx.net>
Tue, 12 Jun 2018 19:16:40 +0000 (21:16 +0200)
committerMathias Kresin <dev@kresin.me>
Mon, 13 Aug 2018 06:37:19 +0000 (08:37 +0200)
This adds a tool to generate a firmware file accepted
by Netgear or sercomm devices.

They use a zip-packed rootfs with header and a custom
checksum. The generated Image can be flashed via the
nmrpflash tool or the webinterface of the router.

Signed-off-by: Ludwig Thomeczek <ledesrc@wxorx.net>
include/image-commands.mk
tools/firmware-utils/Makefile
tools/firmware-utils/src/mksercommfw.c [new file with mode: 0644]

index 05c23008864c348b1545dee040f58037eca38773..3cc5dc21e155c94abf327a20ab8217a1e4f48d44 100644 (file)
@@ -123,6 +123,16 @@ define Build/tplink-safeloader
                $(if $(findstring sysupgrade,$(word 1,$(1))),-S) && mv $@.new $@ || rm -f $@
 endef
 
+define Build/mksercommfw
+       -$(STAGING_DIR_HOST)/bin/mksercommfw \
+               $@ \
+               $(KERNEL_OFFSET) \
+               $(HWID) \
+               $(HWVER) \
+               $(SWVER)
+endef
+
+
 define Build/append-dtb
        cat $(KDIR)/image-$(firstword $(DEVICE_DTS)).dtb >> $@
 endef
index 4b4af999088455e3d9231b227fecfa71c8284b2f..436a43794cd63263df962040eadedfcd026e362b 100644 (file)
@@ -84,6 +84,7 @@ define Host/Compile
        $(call cc,mkdhpimg buffalo-lib, -Wall)
        $(call cc,mkdlinkfw mkdlinkfw-lib, -lz -Wall --std=gnu99)
        $(call cc,dns313-header, -Wall)
+       $(call cc,mksercommfw, -Wall --std=gnu99)
 endef
 
 define Host/Install
diff --git a/tools/firmware-utils/src/mksercommfw.c b/tools/firmware-utils/src/mksercommfw.c
new file mode 100644 (file)
index 0000000..3c56170
--- /dev/null
@@ -0,0 +1,254 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+/* #define DEBUG 1 */
+
+/*
+ * Fw Header Layout for Netgear / Sercomm devices
+ * */
+static const char *magic = "sErCoMm"; /* 7 */
+/* 7-11: version control/download control ? */
+unsigned char version[4] = {0x00, 0x01, 0x00, 0x00};
+char *hwID = ""; /* 11-43 , ASCII/HEX */
+char *hwVer = ""; /* 44-57 , ASCII/HEX */
+char *swVer = ""; /* 58-62 , ASCII/HEX */
+/* magic again. */
+
+#define HEADER_SIZE 71
+
+/* null bytes until 511 */
+u_int32_t checksum = 0xFF; /* checksum */
+/* 512 onwards -> ZIP containing rootfs with the same Header */
+
+
+/* appended on rootfs for the Header. */
+const int footer_size = 128;
+
+struct file_info {
+       char            *file_name;     /* name of the file */
+       char            *file_data;     /* data of the file in memory */
+       u_int32_t        file_size;     /* length of the file */
+};
+
+u_int8_t getCheckSum(char *data, int len)
+{
+
+       int32_t previous = 0;
+       u_int32_t new = 0;
+
+       for (u_int32_t i = 0; i < len; i++) {
+               new = (data[i] + previous) % 256;
+               previous = new | previous & -256;
+       }
+       return (u_int8_t) new;
+}
+
+void *bufferFile(struct file_info *finfo, int dontload)
+{
+       int fs = 0;
+       FILE *f = NULL;
+
+#ifdef DEBUG
+       printf("Opening file: %s\n", finfo->file_name);
+#endif
+       f = fopen(finfo->file_name, "rb");
+       if (f == NULL) {
+               perror("Error");
+               exit(1);
+       }
+
+       fseek(f, 0L, SEEK_END);
+       fs = ftell(f);
+       rewind(f);
+
+#ifdef DEBUG
+       printf("Filesize: %i .\n", fs);
+#endif
+
+       finfo->file_size = fs;
+
+       if (dontload) {
+               return 0;
+       }
+
+       char *data = malloc(fs);
+       finfo->file_data = data;
+
+       int read = fread(data, fs, 1, f);
+
+       if (read != 1) {
+               printf("Error reading file %s.", finfo->file_name);
+               exit(1);
+       }
+
+#ifdef DEBUG
+       printf("File: read successfully %i bytes.\n", read*fs);
+#endif
+       fclose(f);
+}
+
+void *writeFile(struct file_info *finfo)
+{
+
+#ifdef DEBUG
+       printf("Writing file: %s.\n", finfo->file_name);
+#endif
+
+       FILE *fout = fopen(finfo->file_name, "w");
+
+       if (!fwrite(finfo->file_data, finfo->file_size, 1, fout)) {
+               printf("Wanted to write, but something went wrong.\n");
+               fclose(fout);
+               exit(1);
+       }
+       fclose(fout);
+}
+
+void *rmFile(struct file_info *finfo)
+{
+       remove(finfo->file_name);
+       free(finfo->file_data);
+       finfo->file_size = 0;
+}
+
+void *usage(char *argv[])
+{
+       printf("Usage: %s <sysupgradefile> <kernel_offset> <HWID> <HWVER> <SWID>\n"
+               "All are positional arguments ...       \n"
+               "       sysupgradefile:         File with the kernel uimage at 0\n"
+               "       kernel_offset:          Offset in Hex where the kernel is located\n"
+               "       HWID:                   Hardware ID, ASCII\n"
+               "       HWVER:                  Hardware Version, ASCII\n"
+               "       SWID:                   Software Version, Hex\n"
+               "       \n"
+               "       ", argv[0]);
+}
+
+int main(int argc, char *argv[])
+{
+       printf("Building fw image for sercomm devices.\n");
+
+       if (argc == 2) {
+               struct file_info myfile = {argv[1], 0, 0};
+               bufferFile(&myfile, 0);
+               char chksum = getCheckSum(myfile.file_data, myfile.file_size);
+               printf("Checksum for File: %X.\n", chksum);
+               return;
+       }
+
+       if (argc != 6) {
+               usage(argv);
+               return 1;
+       }
+
+       /* Args */
+
+       struct file_info sysupgrade = {argv[1], 0, 0};
+       bufferFile(&sysupgrade, 0);
+
+       int kernel_offset = 0x90000; /* offset for the kernel inside the rootfs, default val */
+       sscanf(argv[2], "%X", &kernel_offset);
+#ifdef DEBUG
+       printf("Kernel_offset: at %X/%i bytes.\n", kernel_offset, kernel_offset);
+#endif
+       char *hwID = argv[3];
+       char *hwVer = argv[4];
+       u_int32_t swVer = 0;
+       sscanf(argv[5],"%4X",&swVer);
+       swVer = bswap_32(swVer);
+
+       char *rootfsname = malloc(2*strlen(sysupgrade.file_name) + 8);
+       sprintf(rootfsname, "%s.rootfs", sysupgrade.file_name);
+
+       char *zipfsname = malloc(2*strlen(rootfsname) + 5);
+       sprintf(zipfsname, "%s.zip", rootfsname);
+       /* / Args */
+
+#ifdef DEBUG
+       printf("Building header: %s %s %2X %s.\n", hwID , hwVer, swVer, magic);
+#endif
+       /* Construct the firmware header/magic */
+       struct file_info header = {0, 0, 0};
+       header.file_size = HEADER_SIZE;
+       header.file_data = malloc(HEADER_SIZE);
+       bzero(header.file_data, header.file_size);
+
+       char *tg = header.file_data;
+       strcpy(tg, magic);
+       memcpy(tg+7, version, 4*sizeof(char));
+       strcpy(tg+11, hwID);
+       strcpy(tg+45, hwVer);
+       memcpy(tg+55, &swVer,sizeof(u_int32_t));
+       strcpy(tg+63, magic);
+
+#ifdef DEBUG
+       printf("Header done, now creating rootfs.");
+#endif
+       /* Construct a rootfs */
+       struct file_info rootfs = {0, 0, 0};
+       rootfs.file_size = sysupgrade.file_size + kernel_offset + footer_size;
+       rootfs.file_data =  malloc(rootfs.file_size);
+       bzero(rootfs.file_data, rootfs.file_size);
+       rootfs.file_name = rootfsname;
+
+       /* copy Owrt image to Kernel location */
+       memcpy(rootfs.file_data+kernel_offset, sysupgrade.file_data, sysupgrade.file_size);
+
+       /* 22 added to get away from sysup image, no other reason.
+        *  updater searches for magic anyway */
+       tg = rootfs.file_data + kernel_offset + sysupgrade.file_size+22;
+
+       memcpy(tg, header.file_data, header.file_size);
+       writeFile(&rootfs);
+
+#ifdef DEBUG
+       printf("Preparing to zip.\n");
+#endif
+       /* now that we got the rootfs, repeat the whole thing again(sorta):
+        * 1. zip the rootfs */
+       char *zipper = malloc(5 + 2*strlen(rootfs.file_name) + 4);
+       sprintf(zipper, "%s %s %s", "zip ", zipfsname, rootfs.file_name);
+       int ret = system(zipper);
+
+       /* clear rootfs file */
+       rmFile(&rootfs);
+
+       /* and load zipped fs */
+       struct file_info zippedfs = {zipfsname, 0, 0};
+       bufferFile(&zippedfs, 0);
+
+#ifdef DEBUG
+       printf("Creating Image.\n");
+#endif
+
+       /* 2. create new file 512+rootfs size */
+       struct file_info image = {argv[1], 0, 0};
+       image.file_data = malloc(zippedfs.file_size + 512);
+       image.file_size = zippedfs.file_size + 512;
+
+       /* 3. copy zipfile at loc 512 */
+       memcpy(image.file_data+512, zippedfs.file_data, zippedfs.file_size);
+       rmFile(&zippedfs);
+
+       /* 4. add header to file */
+       memcpy(image.file_data, header.file_data, header.file_size);
+
+       /* 5. do a checksum run, and compute checksum */
+       char chksum = getCheckSum(image.file_data, image.file_size);
+#ifdef DEBUG
+       printf("Checksum for Image: %X.\n", chksum);
+#endif
+
+       /* 6. write the checksum invert into byte 511 to bring it to 0 */
+       chksum = (chksum ^ 0xFF) + 1;
+       memcpy(image.file_data+511, &chksum, 1);
+
+       chksum = getCheckSum(image.file_data, image.file_size);
+#ifdef DEBUG
+       printf("Checksum for after fix: %X.\n", chksum);
+#endif
+       /* 7. pray that the updater will accept the file */
+       writeFile(&image);
+       return 0;
+}