#include <unistd.h>
#include <byteswap.h>
#include <endian.h>
+#include <getopt.h>
#if !defined(__BYTE_ORDER)
#error "Unknown byte order"
#if __BYTE_ORDER == __BIG_ENDIAN
#define cpu_to_be32(x) (x)
-#define be32_to_cpu(x) (x)
-#define cpu_to_be16(x) (x)
-#define be16_to_cpu(x) (x)
#elif __BYTE_ORDER == __LITTLE_ENDIAN
#define cpu_to_be32(x) bswap_32(x)
-#define be32_to_cpu(x) bswap_32(x)
-#define cpu_to_be16(x) bswap_16(x)
-#define be16_to_cpu(x) bswap_16(x)
#else
#error "Unsupported endianness"
#endif
#endif
#define ERR(...) {printf(__VA_ARGS__); }
-#define ALIGN(a,b) ((a) + ((b) - ((a) % (b))))
-#define ROOTFS_ALIGN 128
-#define HEADER_SIZE 71
/*
* Fw Header Layout for Netgear / Sercomm devices (bytes)
* magic : 63-69 ASCII
* ChkSum : 511 Inverse value of the full image checksum while this location is 0x00
*/
-
static const char* magic = "sErCoMm"; /* 7 */
-
-/* 7-11: version control/download control ? */
static const unsigned char version[4] = { 0x00, 0x01, 0x00, 0x00 };
+static const int header_sz = 512;
+static const int footer_sz = 71;
-
-/* 512 onwards -> ZIP containing rootfs with the same Header */
+static int is_header = 1;
struct file_info {
char* file_name; /* name of the file */
static u_int8_t getCheckSum(char* data, int len) {
u_int8_t new = 0;
+ int i;
if (!data) {
ERR("Invalid pointer provided!\n");
return 0;
}
- for (int i = 0; i < len; i++) {
+ for (i = 0; i < len; i++) {
new += data[i];
}
return new;
}
-static int bufferFile(struct file_info* finfo) {
- int fs = 0;
+/*
+ * read file into buffer
+ * add space for header/footer
+ */
+static int copyToOutputBuf(struct file_info* finfo) {
FILE* fp = NULL;
+ int file_sz = 0;
+ int extra_sz;
+ int hdr_pos;
+ int img_pos;
+
if (!finfo || !finfo->file_name) {
ERR("Invalid pointer provided!\n");
return -1;
/* Get filesize */
rewind(fp);
fseek(fp, 0L, SEEK_END);
- fs = ftell(fp);
+ file_sz = ftell(fp);
rewind(fp);
- if (fs < 0) {
+ if (file_sz < 1) {
ERR("Error getting filesize: %s\n", finfo->file_name);
fclose(fp);
return -1;
}
- DBG("Filesize: %i\n", fs);
- finfo->file_size = fs;
+ if (is_header) {
+ extra_sz = header_sz;
+ hdr_pos = 0;
+ img_pos = header_sz;
+ } else {
+ extra_sz = footer_sz;
+ hdr_pos = file_sz;
+ img_pos = 0;
+ }
+
+ DBG("Filesize: %i\n", file_sz);
+ finfo->file_size = file_sz + extra_sz;
- if (!(finfo->file_data = malloc(fs))) {
+ if (!(finfo->file_data = malloc(finfo->file_size))) {
ERR("Out of memory!\n");
fclose(fp);
return -1;
}
- if (fread(finfo->file_data, 1, fs, fp) != fs) {
+ /* init header/footer bytes */
+ memset(finfo->file_data + hdr_pos, 0, extra_sz);
+
+ /* read file and take care of leading header if exists */
+ if (fread(finfo->file_data + img_pos, 1, file_sz, fp) != file_sz) {
ERR("Error reading file %s\n", finfo->file_name);
fclose(fp);
return -1;
DBG("File: read successful\n");
fclose(fp);
- return 0;
+ return hdr_pos;
}
static int writeFile(struct file_info* finfo) {
return 0;
}
-static void fi_clean(struct file_info* finfo) {
- if (!finfo)
- return;
-
- if (finfo->file_name) {
- finfo->file_name = NULL;
- }
-
- if (finfo->file_data) {
- free(finfo->file_data);
- finfo->file_data = NULL;
- }
-
- finfo->file_size = 0;
-}
-
static 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 where the kernel is located (decimal, hex or octal notation)\n"
- " HWID: Hardware ID, ASCII\n"
- " HWVER: Hardware Version, ASCII\n"
- " SWID: Software Version (decimal, hex or octal notation)\n"
- " \n"
- , argv[0]);
+ printf("Usage: %s [OPTIONS...]\n"
+ "\n"
+ "Options:\n"
+ " -f add sercom footer (if absent, header)\n"
+ " -b <hwid> use hardware id specified with <hwid> (ASCII)\n"
+ " -r <hwrev> use hardware revision specified with <hwrev> (ASCII)\n"
+ " -v <version> set image version to <version> (decimal, hex or octal notation)\n"
+ " -i <file> input file\n"
+ , argv[0]);
}
int main(int argc, char* argv[]) {
- int ret = 1;
- int rootfsname_sz;
- int zipfsname_sz;
- int zipcmd_sz;
- u_int32_t kernel_offset = 0x90000; /* offset for the kernel inside the rootfs, default val */
- u_int32_t swVer = 0;
- struct file_info sysupgrade = { 0 };
- struct file_info header = { 0 };
- struct file_info rootfs = { 0 };
- struct file_info zippedfs = { 0 };
struct file_info image = { 0 };
+
char* hwID = NULL;
char* hwVer = NULL;
- char* rootfsname = NULL;
- char* zipfsname = NULL;
- char* zipcmd = NULL;
+ u_int32_t swVer = 0;
u_int8_t chkSum;
-
- if (argc == 2) {
- struct file_info myfile = { argv[1], 0, 0 };
-
- if (bufferFile(&myfile))
- return 1;
-
- chkSum = getCheckSum(myfile.file_data, myfile.file_size);
- printf("Checksum for File: 0x%hhX\n", chkSum);
-
- return 0;
+ int hdr_offset;
+
+ while ( 1 ) {
+ int c;
+
+ c = getopt(argc, argv, "b:i:r:v:f");
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'b':
+ hwID = optarg;
+ break;
+ case 'f':
+ is_header = 0;
+ break;
+ case 'i':
+ image.file_name = optarg;
+ break;
+ case 'r':
+ hwVer = optarg;
+ break;
+ case 'v':
+ swVer = (u_int32_t) strtol(optarg, NULL, 0);
+ swVer = cpu_to_be32(swVer);
+ break;
+ default:
+ usage(argv);
+ return EXIT_FAILURE;
+ }
}
- if (argc != 6) {
- usage(argv);
- return 1;
+ if (!hwID || !hwVer || !image.file_name) {
+ usage(argv);
+ return EXIT_FAILURE;
}
- printf("Building fw image for sercomm devices ..\n");
-
- /* process args */
- hwID = argv[3];
- hwVer = argv[4];
-
- sysupgrade.file_name = argv[1];
- image.file_name = argv[1];
- kernel_offset = (u_int32_t) strtol(argv[2], NULL, 0);
- swVer = (u_int32_t) strtol(argv[5], NULL, 0);
- swVer = cpu_to_be32(swVer);
-
- /* Check if files actually exist */
- if (access(sysupgrade.file_name, (F_OK | R_OK))) {
- /* Error */
- ERR("File not found: %s\n", sysupgrade.file_name);
- goto cleanup;
+ /*
+ * copy input to buffer, add extra space for header/footer and return
+ * header position
+ */
+ hdr_offset = copyToOutputBuf(&image);
+ if (hdr_offset < 0)
+ return EXIT_FAILURE;
+
+ DBG("Filling header: %s %s %2X %s\n", hwID, hwVer, swVer, magic);
+
+ strncpy(image.file_data + hdr_offset + 0, magic, 7);
+ memcpy(image.file_data + hdr_offset + 7, version, sizeof(version));
+ strncpy(image.file_data + hdr_offset + 11, hwID, 34);
+ strncpy(image.file_data + hdr_offset + 45, hwVer, 10);
+ memcpy(image.file_data + hdr_offset + 55, &swVer, sizeof(swVer));
+ strncpy(image.file_data + hdr_offset + 63, magic, 7);
+
+ /* calculate checksum and invert checksum */
+ if (is_header) {
+ chkSum = getCheckSum(image.file_data, image.file_size);
+ chkSum = (chkSum ^ 0xFF) + 1;
+ DBG("Checksum for Image: %hhX\n", chkSum);
+
+ /* write checksum to header */
+ image.file_data[511] = (char) chkSum;
}
- /* Calculate amount of required memory (incl. 0-term) */
- rootfsname_sz = strlen(sysupgrade.file_name) + 7 + 1;
- zipfsname_sz = strlen(sysupgrade.file_name) + 7 + 4 + 1;
-
- /* Allocate required memory */
- if (!(rootfsname = (char*) malloc(rootfsname_sz)) || !(zipfsname =
- (char*) malloc(zipfsname_sz))) {
- /* Error */
- ERR("Out of memory!\n");
- goto cleanup;
- }
-
- /* Create filenames */
- if (snprintf(rootfsname, rootfsname_sz, "%s.rootfs", sysupgrade.file_name)
- >= rootfsname_sz
- || snprintf(zipfsname, zipfsname_sz, "%s.rootfs.zip",
- sysupgrade.file_name) >= zipfsname_sz) {
- /* Error */
- ERR("Buffer too small!\n");
- goto cleanup;
- }
-
- /* Buffer all files */
- if (bufferFile(&sysupgrade)) {
- /* Error */
- goto cleanup;
- }
-
- DBG("Building header: %s %s %2X %s\n", hwID, hwVer, swVer, magic);
-
- /* Construct the firmware header/magic */
- header.file_name = NULL;
- header.file_size = HEADER_SIZE;
-
- if (!(header.file_data = (char*) calloc(1, HEADER_SIZE))) {
- /* Error */
- ERR("Out of memory!\n");
- goto cleanup;
- }
-
- strncpy(header.file_data + 0, magic, 7);
- memcpy(header.file_data + 7, version, sizeof(version));
- strncpy(header.file_data + 11, hwID, 34);
- strncpy(header.file_data + 45, hwVer, 10);
- memcpy(header.file_data + 55, &swVer, sizeof(swVer));
- strncpy(header.file_data + 63, magic, 7);
-
- DBG("Creating rootfs ..\n");
-
- /* Construct a rootfs */
- rootfs.file_name = rootfsname;
- rootfs.file_size = ALIGN(
- sysupgrade.file_size + kernel_offset + header.file_size,
- ROOTFS_ALIGN);
-
- if (!(rootfs.file_data = calloc(1, rootfs.file_size))) {
- /* Error */
- ERR("Out of memory!\n");
- goto cleanup;
- }
-
- /* copy Owrt image to kernel location */
- memcpy(rootfs.file_data + kernel_offset, sysupgrade.file_data,
- sysupgrade.file_size);
-
- /* Append header after the owrt image. The updater searches for it */
- memcpy(rootfs.file_data + kernel_offset + sysupgrade.file_size,
- header.file_data, header.file_size);
-
- /* Write to file */
- if (writeFile(&rootfs)) {
- /* Error */
- goto cleanup;
- }
-
- /* Construct a zip */
- DBG("Preparing to zip ..\n");
-
- /* now that we got the rootfs, repeat the whole thing again(sorta):
- * 1. zip the rootfs */
- zipcmd_sz = 3 + 1 + strlen(zipfsname) + 1 + strlen(rootfs.file_name) + 1;
-
- if (!(zipcmd = malloc(zipcmd_sz))) {
- /* Error */
- ERR("Out of memory!\n");
- goto cleanup;
- }
-
- if (snprintf(zipcmd, zipcmd_sz, "%s %s %s", "zip", zipfsname,
- rootfs.file_name) >= zipcmd_sz) {
- /* Error */
- ERR("Buffer too small!\n");
- goto cleanup;
- }
-
- if (system(zipcmd)) {
- /* Error */
- ERR("Error creating a zip file!\n");
- goto cleanup;
- }
-
- /* and load zipped fs */
- zippedfs.file_name = zipfsname;
-
- if (bufferFile(&zippedfs)) {
- /* Error */
- goto cleanup;
- }
-
- DBG("Creating Image.\n");
-
- /* 2. create new file 512 + rootfs size */
- image.file_size = zippedfs.file_size + 512;
- if (!(image.file_data = malloc(zippedfs.file_size + 512))) {
- /* Error */
- ERR("Out of memory!\n");
- goto cleanup;
- }
-
- /* 3. add header to file */
- memcpy(image.file_data, header.file_data, header.file_size);
-
- /* 4. clear remaining space */
- if (header.file_size < 512)
- memset(image.file_data + header.file_size, 0, 512 - header.file_size);
-
- /* 5. copy zipfile at loc 512 */
- memcpy(image.file_data + 512, zippedfs.file_data, zippedfs.file_size);
-
- /* 6. do a checksum run, and compute checksum */
- chkSum = getCheckSum(image.file_data, image.file_size);
-
- DBG("Checksum for Image: %hhX\n", chkSum);
-
- /* 7. write the checksum inverted into byte 511 to bring it to 0 on verification */
- chkSum = (chkSum ^ 0xFF) + 1;
- image.file_data[511] = (char) chkSum;
-
- chkSum = getCheckSum(image.file_data, image.file_size);
- DBG("Checksum for after fix: %hhX\n", chkSum);
-
- if (chkSum != 0) {
- ERR("Invalid checksum!\n")
- goto cleanup;
- }
-
- /* 8. pray that the updater will accept the file */
- if (writeFile(&image)) {
- /* Error */
- goto cleanup;
- }
-
- /* All seems OK */
- ret = 0;
-
- cleanup:
-
- if (rootfs.file_name && !access(rootfs.file_name, F_OK | W_OK))
- remove(rootfs.file_name);
-
- if (zippedfs.file_name && !access(zippedfs.file_name, F_OK | W_OK))
- remove(zippedfs.file_name);
-
- fi_clean(&sysupgrade);
- fi_clean(&header);
- fi_clean(&rootfs);
- fi_clean(&zippedfs);
- fi_clean(&image);
-
- if (rootfsname)
- free(rootfsname);
-
- if (zipfsname)
- free(zipfsname);
-
- if (zipcmd)
- free(zipcmd);
+ /* overwrite input file */
+ if (writeFile(&image))
+ return EXIT_FAILURE;
- return ret;
+ return EXIT_SUCCESS;
}