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 <ledesrc@wxorx.net>
This commit is contained in:
Ludwig Thomeczek 2018-06-12 21:16:40 +02:00 committed by Mathias Kresin
parent 42dc0e2594
commit e5b802b9c2
3 changed files with 265 additions and 0 deletions

View 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

View 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

View file

@ -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;
}