From e5b802b9c2711316e26402669bee9349f4c6ec65 Mon Sep 17 00:00:00 2001 From: Ludwig Thomeczek Date: Tue, 12 Jun 2018 21:16:40 +0200 Subject: [PATCH] firmware-utils: add sercomm/netgear tool 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 --- include/image-commands.mk | 10 + tools/firmware-utils/Makefile | 1 + tools/firmware-utils/src/mksercommfw.c | 254 +++++++++++++++++++++++++ 3 files changed, 265 insertions(+) create mode 100644 tools/firmware-utils/src/mksercommfw.c diff --git a/include/image-commands.mk b/include/image-commands.mk index 05c2300886..3cc5dc21e1 100644 --- a/include/image-commands.mk +++ b/include/image-commands.mk @@ -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 diff --git a/tools/firmware-utils/Makefile b/tools/firmware-utils/Makefile index 4b4af99908..436a43794c 100644 --- a/tools/firmware-utils/Makefile +++ b/tools/firmware-utils/Makefile @@ -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 index 0000000000..3c561708d1 --- /dev/null +++ b/tools/firmware-utils/src/mksercommfw.c @@ -0,0 +1,254 @@ +#include +#include +#include + +/* #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 \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; +}