/*
- WRT350Nv2-Builder 2.1 (previously called buildimg)
+ WRT350Nv2-Builder 2.4 (previously called buildimg)
Copyright (C) 2008-2009 Dirk Teurlings <info@upexia.nl>
- Copyright (C) 2009-2010 Matthias Buecher (http://www.maddes.net/)
+ Copyright (C) 2009-2011 Matthias Buecher (http://www.maddes.net/)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
:kernel 0x001A0000 /path/to/uImage
:rootfs 0 /path/to/root.squashfs
:u-boot 0 /path/to/u-boot.bin
+ #version 0x2020
+
+ Additionally since v2.4 an already complete image can be used:
+ :image 0 /path/to/openwrt-wrt350nv2-[squashfs|jffs2-64k].img
args:
1 wrt350nv2.par parameter file describing the image layout
To extract everything from a Linksys style firmware image see
https://forum.openwrt.org/viewtopic.php?pid=92928#p92928
-*/
+ Changelog:
+ v2.4 - added ":image" definition for parameter file, this allows
+ to use a complete sysupgrade image without any kernel size check
+ v2.3 - allow jffs by adding its magic number (0x8519)
+ added parameter option -i to ignore unknown magic numbers
+ v2.2 - fixed checksum byte calculation for other versions than 0x2019
+ fixed rare problem with padsize
+ updated info to stock firmware 2.00.20
+ fixed typos
+ v2.1 - used "wrt350n.bin" for the created image (closer to stock)
+ added option to create the image in two separate steps (-b / -z)
+ v2.0 - complete re-write
-// ToDo:
-// * Has NODE to be added to bin file *after* creating checksum byte?
+*/
// includes
#define _GNU_SOURCE // for GNU's basename()
// custom includes
#include "md5.h" // MD5 routines
-#include "upgrade.h" // Linksys definitions from firmware 2.0.19
+#include "upgrade.h" // Linksys definitions from firmware 2.0.19 (unchanged up to 2.0.20)
// version info
-#define VERSION "2.1"
+#define VERSION "2.4"
char program_info[] = "WRT350Nv2-Builder v%s by Dirk Teurlings <info@upexia.nl> and Matthias Buecher (http://www.maddes.net/)\n";
// verbosity
mtd_info mtd_kernel = { "kernel", 0, 0, NULL, 0L, { 0, 0 } };
mtd_info mtd_rootfs = { "rootfs", 0, 0, NULL, 0L, { 0, 0 } };
+mtd_info mtd_image = { "image", 0, 0, NULL, 0L, { 0, 0 } };
mtd_info mtd_uboot = { "u-boot", 0, 0, NULL, 0L, { 0, 0 } };
#define ROOTFS_END_OFFSET 0x00760000
#define ROOTFS_MIN_OFFSET 0x00640000 // should be filled up to here, to make sure that the zip file is big enough to pass the size check of the stock firmware
- // 2.0.17: filled up to 0x00640000, 2.0.19: filled up to 0x0670000
+ // 2.0.17: filled up to 0x00640000
+ // 2.0.19: filled up to 0x00670000
+ // 2.0.20: filled up to 0x00670000
// rootfs statics via: hexdump -v -e '1/1 "0x%02X, "' -s 0x0075FFE0 -n 16 "wrt350n.bin" ; echo -en "\n"
unsigned char product_id[] = { 0x00, 0x03 }; // seems to be a fixed value
unsigned char protocol_id[] = { 0x00, 0x00 }; // seems to be a fixed value
-unsigned char fw_version[] = { 0x20, 0x19 };
+unsigned char fw_version[] = { 0x20, 0x20 };
unsigned char rootfs_unknown[] = { 0x90, 0xF7 }; // seems to be a fixed value
unsigned char sign[] = { 0x65, 0x52, 0x63, 0x4F, 0x6D, 0x4D, 0x00, 0x00 }; // eRcOmM
0x00, 0x00, 0x00, 0x04,
0x73, 0x45, 0x72, 0x43, 0x6F, 0x4D, 0x6D }; // sErCoMm
-// img statics via: hexdump -v -e '1/1 "0x%02X, "' -s 0 -n 512 "WRT350N-EU-ETSI-2.00.19.img" ; echo -en "\n"
+// img statics via: hexdump -v -e '1/1 "0x%02X, "' -s 0 -n 512 "WRT350N-EU-ETSI-2.00.19.img" ; echo -en "\n" (unchanged up to 2.0.20)
unsigned char img_hdr[] = { 0x00, 0x01, 0x00, 0x00, 0x59, 0x42, 0x50, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
mtd = &mtd_rootfs;
} else if (!strcmp(string1, mtd_uboot.name)) {
mtd = &mtd_uboot;
+ } else if (!strcmp(string1, mtd_image.name)) {
+ mtd = &mtd_image;
}
if (!mtd) {
case '#': // integer values
count = sscanf(line, "#%255s %i", string1, &value);
if (count != 2) {
- printf("line %i does not meet defined format (:<variable name> <integer>\n", lineno);
+ printf("line %i does not meet defined format (#<variable name> <integer>\n", lineno);
} else {
if (!strcmp(string1, "version")) {
// changing version
// add files
if (!exitcode) {
- for (i = 1; i <= 3; i++) {
+ for (i = 1; i <= 4; i++) {
addsize = 0;
padsize = 0;
switch (i) {
case 1:
- mtd = &mtd_kernel;
+ mtd = &mtd_image;
+ padsize = ROOTFS_MIN_OFFSET - mtd->filesize;
break;
case 2:
+ mtd = &mtd_kernel;
+ break;
+ case 3:
mtd = &mtd_rootfs;
addsize = mtd->filesize;
padsize = ROOTFS_MIN_OFFSET - mtd_kernel.size - mtd->filesize;
break;
- case 3:
+ case 4:
mtd = &mtd_uboot;
addsize = mtd->filesize;
break;
// padding
if (padsize > 0) {
- printf("mtd %s input file %s is too small (0x%08lX), adding 0x%08X random bytes\n", mtd->name, mtd->filename, mtd->filesize, padsize);
-
addsize = padsize & 0x0000FFFF; // start on next 64KB border
padsize -= addsize;
+ }
+ if (padsize > 0) {
+ printf("mtd %s input file %s is too small (0x%08lX), adding 0x%08X random bytes\n", mtd->name, mtd->filename, mtd->filesize, padsize);
+
addsize += KERNEL_CODE_OFFSET + mtd->offset + mtd->filesize; // get offset
lprintf(DEBUG, " padding offset 0x%08X length 0x%08X\n", addsize, padsize);
memcpy(&buffer[KERNEL_CODE_OFFSET + FW_VERSION_OFFSET + 2], rootfs_unknown, 2);
memcpy(&buffer[KERNEL_CODE_OFFSET + SIGN_OFFSET], sign, 8); // eRcOmM
- lprintf(DEBUG, "adding u-boot special data 1/2\n"); // ToDo: or after creating the checksum byte?
-// memcpy(&buffer[KERNEL_CODE_OFFSET + SN_OFF], sn, 12); // ToDo: find out what's this for?
-// memcpy(&buffer[KERNEL_CODE_OFFSET + PIN_OFF], pin, 8); // ToDo: find out what's this for?
-// memcpy(&buffer[KERNEL_CODE_OFFSET + NODE_BASE_OFF], node, 25); // ToDo: find out what's this for?
+ lprintf(DEBUG, "adding u-boot special data\n");
+// memcpy(&buffer[KERNEL_CODE_OFFSET + SN_OFF], sn, 12); // ToDo: currently zero, find out what's this for?
+// memcpy(&buffer[KERNEL_CODE_OFFSET + PIN_OFF], pin, 8); // ToDo: currently zero, find out what's this for?
+// memcpy(&buffer[KERNEL_CODE_OFFSET + NODE_BASE_OFF], node, 25); // ToDo: currently zero, find out what's this for?
+ memcpy(&buffer[KERNEL_CODE_OFFSET + BOOT_ADDR_BASE_OFF + PID_OFFSET], pid, 70); // sErCoMm
+ memcpy(&buffer[KERNEL_CODE_OFFSET + BOOT_ADDR_BASE_OFF + PID_OFFSET + 57], fw_version, 2);
lprintf(DEBUG, "adding checksum byte\n");
csum = 0;
}
lprintf(DEBUG_LVL2, " checksum 0x%016lX (%li)\n", csum, csum);
- buffer[KERNEL_CODE_OFFSET + NODE_BASE_OFF + 25] = ~(csum+108)+1;
+ buffer[KERNEL_CODE_OFFSET + NODE_BASE_OFF + 25] = ~csum + 1;
lprintf(DEBUG, " byte 0x%02X\n", buffer[KERNEL_CODE_OFFSET + NODE_BASE_OFF + 25]);
-
- lprintf(DEBUG, "adding u-boot special data 2/2\n");
- memcpy(&buffer[KERNEL_CODE_OFFSET + BOOT_ADDR_BASE_OFF + PID_OFFSET], pid, 70); // sErCoMm
- memcpy(&buffer[KERNEL_CODE_OFFSET + BOOT_ADDR_BASE_OFF + PID_OFFSET + 57], fw_version, 2);
}
// write bin file
int help;
int onlybin;
int havezip;
+ int ignoremagic;
char option;
char *par_filename = NULL;
char *img_filename = NULL;
int i;
mtd_info *mtd;
- int mandatory;
int noupdate;
int sizecheck;
- unsigned char magic[2];
+ int magiccheck;
+ int magicerror;
// display program header
help = 0;
onlybin = 0;
havezip = 0;
- while ((option = getopt(argc, argv, ":hbzf:v")) != -1) {
+ ignoremagic = 0;
+ while ((option = getopt(argc, argv, "hbzif:v")) != -1) {
switch(option) {
case 'h':
help = 1;
case 'z':
havezip = 1;
break;
+ case 'i':
+ ignoremagic = 1;
+ break;
case 'f':
sizecheck = sscanf(optarg, "%i", &i);
if (sizecheck != 1) {
printf("This program creates Linksys style images for the WRT350Nv2 router.\n");
}
printf(" Usage:\n\
- %s [-h] [-b] [-z] [-f <version>] [-v] <parameter or zip file> [<image file>]\n\n\
+ %s [-h] [-b] [-z] [-i] [-f <version>] [-v] <parameter or zip file> [<image file>]\n\n\
Options:\n\
-h - Show this help\n\
-b - Create only bin file, no img or zip file is created\n\
-z - Have zip file, the img file will be directly created from it\n\
+ -i - Ignore unknown magic numbers\n\
-f <version> - Wanted firmware version to use with -z\n\
- Default firmware version is 0x2019 = 2.00.19.\n\
+ Default firmware version is 0x2020 = 2.00.20.\n\
Note: version from parameter file will supersede this\n\
-v - Increase debug verbosity level\n\n\
Example:\n\
if ((!exitcode) && (par_filename)) {
lprintf(DEBUG, "checking mtd data...\n");
- for (i = 1; i <= 3; i++) {
- mandatory = 0;
+ for (i = 1; i <= 4; i++) {
noupdate = 0;
sizecheck = 0;
- magic[0] = 0;
- magic[1] = 0;
+ magiccheck = 0;
switch (i) {
case 1:
+ mtd = &mtd_image;
+ sizecheck = ROOTFS_END_OFFSET;
+ magiccheck = 1;
+ break;
+ case 2:
mtd = &mtd_kernel;
- mandatory = 1;
sizecheck = mtd_kernel.size - 16;
- magic[0] = 0x27;
- magic[1] = 0x05;
+ magiccheck = 1;
break;
- case 2:
+ case 3:
mtd = &mtd_rootfs;
mtd->offset = mtd_kernel.size;
mtd->size = ROOTFS_END_OFFSET - mtd_kernel.size;
- mandatory = 1;
sizecheck = PRODUCT_ID_OFFSET - mtd_kernel.size;
- magic[0] = 0x68;
- magic[1] = 0x73;
+ magiccheck = 1;
break;
- case 3:
+ case 4:
mtd = &mtd_uboot;
mtd->offset = BOOT_ADDR_BASE_OFF;
noupdate = 1;
lprintf(DEBUG_LVL2, " checking mtd %s\n", mtd->name);
// general checks
- if ((mandatory) && (!mtd->filename)) {
- exitcode = 1;
- printf("mtd %s not specified correctly or at all in parameter file\n", mtd->name);
- }
- // end checks if no file data present
+ // no further checks if no file data present
if (!mtd->filename) {
continue;
}
}
// general magic number check
- if (magic[0]) {
- if ((mtd->magic[0] != magic[0]) || (mtd->magic[1] != magic[1])) {
- exitcode = 1;
- printf("mtd %s input file %s has wrong magic number (0x%02X%02X)\n", mtd->name, mtd->filename, mtd->magic[0], mtd->magic[1]);
+ magicerror = 0;
+ if (magiccheck) {
+ switch (i) {
+ case 1: // image
+ case 2: // kernel
+ if (!(
+ ((mtd->magic[0] == 0x27) && (mtd->magic[1] == 0x05)) // uImage
+ )) {
+ magicerror = 1;
+ }
+ break;
+ case 3: // rootfs
+ if (!(
+ ((mtd->magic[0] == 0x68) && (mtd->magic[1] == 0x73)) // squashfs
+ || ((mtd->magic[0] == 0x85) && (mtd->magic[1] == 0x19)) // jffs
+ )) {
+ magicerror = 1;
+ }
+ break;
+ default:
+ magicerror = 1;
+ break;
+ }
+ if (magicerror) {
+ printf("mtd %s input file %s has unknown magic number (0x%02X%02X)", mtd->name, mtd->filename, mtd->magic[0], mtd->magic[1]);
+ if (ignoremagic) {
+ printf("...ignoring");
+ } else {
+ exitcode = 1;
+ }
+ printf("\n");
}
}
// mtd specific size check
+ if (mtd == &mtd_image) {
+ if (mtd->filesize < 0x00200000) {
+ exitcode = 1;
+ printf("mtd %s input file %s too unrealistic small (0x%08lX)\n", mtd->name, mtd->filename, mtd->filesize);
+ }
+ }
+
if (mtd == &mtd_kernel) {
- if (mtd->filesize < 0x00050000) {
+ if (mtd->filesize < 0x00080000) {
exitcode = 1;
printf("mtd %s input file %s too unrealistic small (0x%08lX)\n", mtd->name, mtd->filename, mtd->filesize);
}
}
}
}
+
+ // Check for mandatory parts
+ if ((!mtd_image.filename) && (!mtd_kernel.filename || !mtd_rootfs.filename)) {
+ exitcode = 1;
+ if (mtd_kernel.filename && !mtd_rootfs.filename) {
+ printf("Kernel without rootfs, either incorrectly specified or not at all in parameter file\n");
+ } else if (!mtd_kernel.filename && mtd_rootfs.filename) {
+ printf("Rootfs without kernel, either incorrectly specified or not at all in parameter file\n");
+ } else {
+ printf("Neither an image nor kernel with rootfs was/were correctly specified or at all in parameter file\n");
+ }
+ }
+
+ // Check for duplicate parts
+ if ((mtd_image.filename) && (mtd_kernel.filename || mtd_rootfs.filename)) {
+ exitcode = 1;
+ printf("Image and kernel/rootfs specified in parameter file\n");
+ }
+
lprintf(DEBUG, "...done checking mtd data\n");
}