Skip to content
Snippets Groups Projects
Select Git revision
  • c1b9ea2d9cfadf9179aa628c53074b3d3a3ac78d
  • v2018.2.x default protected
  • 0x4A6F-rpi4
  • 0x4A6F-master
  • master
  • v2018.2.2-ffs
  • v2016.2.4-batmanbug
  • radv-filterd
  • v2016.2.x
  • hoodselector
  • v2016.1.x
  • babel
  • v2015.1.x
  • 2014.4.x
  • 2014.3.x
  • v2018.2.2-ffs0.1
  • v2018.2.1-ffs0.1
  • v2018.2.1
  • v2018.2-ffs0.1
  • v2018.2
  • v2018.1.4
  • v2018.1.3
  • v2018.1.2
  • v2018.1.1
  • v2018.1
  • v2017.1.8
  • v2017.1.7
  • v2017.1.6
  • v2017.1.5
  • v2017.1.4
  • v2017.1.3
  • v2017.1.2
  • v2016.2.7
  • v2017.1.1
  • v2017.1
35 results

gluon-switch-domain

  • Forked from firmware / FFS Gluon
    Source project has a limited visibility.
    0069-firmware-utils-mktplinkfw-backport-from-LEDE-a4fc62bc0ea4010ddbfbd738453c9db70988a57c.patch 23.42 KiB
    From: Matthias Schiffer <mschiffer@universe-factory.net>
    Date: Sun, 28 Aug 2016 20:20:35 +0200
    Subject: firmware-utils: mktplinkfw: backport from LEDE a4fc62bc0ea4010ddbfbd738453c9db70988a57c
    
    diff --git a/tools/firmware-utils/Makefile b/tools/firmware-utils/Makefile
    index 03978456636ad50fc8128c0a5a51845135301a3d..aee8e87a1c0839f3220686e97cd8458516fc17cf 100644
    --- a/tools/firmware-utils/Makefile
    +++ b/tools/firmware-utils/Makefile
    @@ -40,7 +40,7 @@ define Host/Compile
     	$(call cc,encode_crc)
     	$(call cc,nand_ecc)
     	$(call cc,mkplanexfw sha1)
    -	$(call cc,mktplinkfw md5)
    +	$(call cc,mktplinkfw md5, -Wall)
     	$(call cc,mktplinkfw2 md5)
     	$(call cc,tplink-safeloader md5, -Wall)
     	$(call cc,pc1crypt)
    diff --git a/tools/firmware-utils/src/mktplinkfw.c b/tools/firmware-utils/src/mktplinkfw.c
    index 9785a3f232ed4457e77aee249c0da86b4e99c532..34e6546a2d7db72748146ef233830c2e8de9ce97 100644
    --- a/tools/firmware-utils/src/mktplinkfw.c
    +++ b/tools/firmware-utils/src/mktplinkfw.c
    @@ -28,53 +28,10 @@
     #include "md5.h"
     
     #define ALIGN(x,a) ({ typeof(a) __a = (a); (((x) + __a - 1) & ~(__a - 1)); })
    +#define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0]))
     
     #define HEADER_VERSION_V1	0x01000000
    -#define HWID_ANTMINER_S1	0x04440101
    -#define HWID_ANTMINER_S3	0x04440301
    -#define HWID_GL_INET_V1		0x08000001
    -#define HWID_GS_OOLITE_V1	0x3C000101
    -#define HWID_ONION_OMEGA	0x04700001
    -#define HWID_TL_MR10U_V1	0x00100101
    -#define HWID_TL_MR13U_V1	0x00130101
    -#define HWID_TL_MR3020_V1	0x30200001
    -#define HWID_TL_MR3220_V1	0x32200001
    -#define HWID_TL_MR3220_V2	0x32200002
    -#define HWID_TL_MR3420_V1	0x34200001
    -#define HWID_TL_MR3420_V2	0x34200002
    -#define HWID_TL_WA701N_V1	0x07010001
    -#define HWID_TL_WA701N_V2	0x07010002
    -#define HWID_TL_WA7210N_V2	0x72100002
    -#define HWID_TL_WA7510N_V1	0x75100001
    -#define HWID_TL_WA801ND_V1	0x08010001
    -#define HWID_TL_WA830RE_V1	0x08300010
    -#define HWID_TL_WA830RE_V2	0x08300002
    -#define HWID_TL_WA801ND_V2	0x08010002
    -#define HWID_TL_WA801ND_V3	0x08010003
    -#define HWID_TL_WA901ND_V1	0x09010001
    -#define HWID_TL_WA901ND_V2	0x09010002
    -#define HWID_TL_WA901ND_V4	0x09010004
    -#define HWID_TL_WDR4300_V1_IL	0x43008001
    -#define HWID_TL_WDR4900_V1	0x49000001
    -#define HWID_TL_WR703N_V1	0x07030101
    -#define HWID_TL_WR720N_V3	0x07200103
    -#define HWID_TL_WR720N_V4	0x07200104
    -#define HWID_TL_WR741ND_V1	0x07410001
    -#define HWID_TL_WR741ND_V4	0x07410004
    -#define HWID_TL_WR740N_V1	0x07400001
    -#define HWID_TL_WR740N_V3	0x07400003
    -#define HWID_TL_WR743ND_V1	0x07430001
    -#define HWID_TL_WR743ND_V2	0x07430002
    -#define HWID_TL_WR841N_V1_5	0x08410002
    -#define HWID_TL_WR841ND_V3	0x08410003
    -#define HWID_TL_WR841ND_V5	0x08410005
    -#define HWID_TL_WR841ND_V7	0x08410007
    -#define HWID_TL_WR941ND_V2	0x09410002
    -#define HWID_TL_WR941ND_V4	0x09410004
    -#define HWID_TL_WR1043ND_V1	0x10430001
    -#define HWID_TL_WR1043ND_V2	0x10430002
    -#define HWID_TL_WR1041N_V2	0x10410002
    -#define HWID_TL_WR2543N_V1	0x25430001
    +#define HEADER_VERSION_V2	0x02000000
     
     #define MD5SUM_LEN	16
     
    @@ -89,7 +46,7 @@ struct fw_header {
     	char		fw_version[36];
     	uint32_t	hw_id;		/* hardware id */
     	uint32_t	hw_rev;		/* hardware revision */
    -	uint32_t	unk1;
    +	uint32_t	region_code;	/* region code */
     	uint8_t		md5sum1[MD5SUM_LEN];
     	uint32_t	unk2;
     	uint8_t		md5sum2[MD5SUM_LEN];
    @@ -106,7 +63,10 @@ struct fw_header {
     	uint16_t	ver_hi;
     	uint16_t	ver_mid;
     	uint16_t	ver_lo;
    -	uint8_t		pad[354];
    +	uint8_t		pad[130];
    +	char		region_str1[32];
    +	char		region_str2[32];
    +	uint8_t		pad2[160];
     } __attribute__ ((packed));
     
     struct flash_layout {
    @@ -117,13 +77,12 @@ struct flash_layout {
     	uint32_t	rootfs_ofs;
     };
     
    -struct board_info {
    -	char		*id;
    -	uint32_t	hw_id;
    -	uint32_t	hw_rev;
    -	char		*layout_id;
    +struct fw_region {
    +	char		name[4];
    +	uint32_t	code;
     };
     
    +
     /*
      * Globals
      */
    @@ -132,15 +91,17 @@ static char *progname;
     static char *vendor = "TP-LINK Technologies";
     static char *version = "ver. 1.0";
     static char *fw_ver = "0.0.0";
    +static uint32_t hdr_ver = HEADER_VERSION_V1;
     
    -static char *board_id;
    -static struct board_info *board;
     static char *layout_id;
     static struct flash_layout *layout;
     static char *opt_hw_id;
     static uint32_t hw_id;
     static char *opt_hw_rev;
     static uint32_t hw_rev;
    +static uint32_t opt_hdr_ver = 1;
    +static char *country;
    +static const struct fw_region *region;
     static int fw_ver_lo;
     static int fw_ver_mid;
     static int fw_ver_hi;
    @@ -163,12 +124,12 @@ static uint32_t reserved_space;
     static struct file_info inspect_info;
     static int extract = 0;
     
    -char md5salt_normal[MD5SUM_LEN] = {
    +static const char md5salt_normal[MD5SUM_LEN] = {
     	0xdc, 0xd7, 0x3a, 0xa5, 0xc3, 0x95, 0x98, 0xfb,
     	0xdd, 0xf9, 0xe7, 0xf4, 0x0e, 0xae, 0x47, 0x38,
     };
     
    -char md5salt_boot[MD5SUM_LEN] = {
    +static const char md5salt_boot[MD5SUM_LEN] = {
     	0x8c, 0xef, 0x33, 0x5b, 0xd5, 0xc5, 0xce, 0xfa,
     	0xa7, 0x9c, 0x28, 0xda, 0xb2, 0xe9, 0x0f, 0x42,
     };
    @@ -213,7 +174,7 @@ static struct flash_layout layouts[] = {
     	}, {
     		.id		= "16Mppc",
     		.fw_max_len	= 0xf80000,
    -		.kernel_la	= 0x00000000,
    +		.kernel_la	= 0x00000000 ,
     		.kernel_ep	= 0xc0000000,
     		.rootfs_ofs	= 0x2a0000,
     	}, {
    @@ -221,235 +182,10 @@ static struct flash_layout layouts[] = {
     	}
     };
     
    -static struct board_info boards[] = {
    -	{
    -		.id		= "TL-MR10Uv1",
    -		.hw_id		= HWID_TL_MR10U_V1,
    -		.hw_rev		= 1,
    -		.layout_id	= "4Mlzma",
    -	}, {
    -		.id		= "TL-MR13Uv1",
    -		.hw_id		= HWID_TL_MR13U_V1,
    -		.hw_rev		= 1,
    -		.layout_id	= "4Mlzma",
    -	}, {
    -		.id		= "TL-MR3020v1",
    -		.hw_id		= HWID_TL_MR3020_V1,
    -		.hw_rev		= 1,
    -		.layout_id	= "4Mlzma",
    -	}, {
    -		.id		= "TL-MR3220v1",
    -		.hw_id		= HWID_TL_MR3220_V1,
    -		.hw_rev		= 1,
    -		.layout_id	= "4M",
    -	}, {
    -		.id		= "TL-MR3220v2",
    -		.hw_id		= HWID_TL_MR3220_V2,
    -		.hw_rev		= 1,
    -		.layout_id	= "4Mlzma",
    -	}, {
    -		.id		= "TL-MR3420v1",
    -		.hw_id		= HWID_TL_MR3420_V1,
    -		.hw_rev		= 1,
    -		.layout_id	= "4M",
    -	}, {
    -		.id		= "TL-MR3420v2",
    -		.hw_id		= HWID_TL_MR3420_V2,
    -		.hw_rev		= 1,
    -		.layout_id	= "4Mlzma",
    -	}, {
    -		.id		= "TL-WA701Nv1",
    -		.hw_id		= HWID_TL_WA701N_V1,
    -		.hw_rev		= 1,
    -		.layout_id	= "4M",
    -	}, {
    -		.id		= "TL-WA701Nv2",
    -		.hw_id		= HWID_TL_WA701N_V2,
    -		.hw_rev		= 1,
    -		.layout_id	= "4Mlzma",
    -	}, {
    -		.id		= "TL-WA7210N",
    -		.hw_id		= HWID_TL_WA7210N_V2,
    -		.hw_rev		= 2,
    -		.layout_id	= "4Mlzma",
    -	}, {
    -		.id		= "TL-WA7510N",
    -		.hw_id		= HWID_TL_WA7510N_V1,
    -		.hw_rev		= 1,
    -		.layout_id	= "4M",
    -	}, {
    -		.id		= "TL-WA801NDv1",
    -		.hw_id		= HWID_TL_WA801ND_V1,
    -		.hw_rev		= 1,
    -		.layout_id	= "4M",
    -	}, {
    -		.id		= "TL-WA830REv1",
    -		.hw_id		= HWID_TL_WA830RE_V1,
    -		.hw_rev		= 1,
    -		.layout_id	= "4M",
    -	}, {
    -		.id		= "TL-WA830REv2",
    -		.hw_id		= HWID_TL_WA830RE_V2,
    -		.hw_rev		= 1,
    -		.layout_id	= "4M",
    -	}, {
    -		.id             = "TL-WA801NDv2",
    -		.hw_id          = HWID_TL_WA801ND_V2,
    -		.hw_rev         = 1,
    -		.layout_id	= "4Mlzma",
    -	},{
    -		.id							= "TL-WA801NDv3",
    -		.hw_id          = HWID_TL_WA801ND_V3,
    -		.hw_rev         = 1,
    -		.layout_id  = "4Mlzma",
    -	}, {
    -		.id		= "TL-WA901NDv1",
    -		.hw_id		= HWID_TL_WA901ND_V1,
    -		.hw_rev		= 1,
    -		.layout_id	= "4M",
    -	}, {
    -		.id             = "TL-WA901NDv2",
    -		.hw_id          = HWID_TL_WA901ND_V2,
    -		.hw_rev         = 1,
    -		.layout_id	= "4M",
    -	}, {
    -		.id             = "TL-WA901NDv4",
    -		.hw_id          = HWID_TL_WA901ND_V4,
    -		.hw_rev         = 1,
    -		.layout_id	= "4Mlzma",
    -	}, {
    -		.id             = "TL-WDR4300v1",
    -		.hw_id          = HWID_TL_WDR4300_V1_IL,
    -		.hw_rev         = 1,
    -		.layout_id	= "8Mlzma",
    -	}, {
    -		.id             = "TL-WDR4900v1",
    -		.hw_id          = HWID_TL_WDR4900_V1,
    -		.hw_rev         = 1,
    -		.layout_id	= "16Mppc",
    -	}, {
    -		.id		= "TL-WR741NDv1",
    -		.hw_id		= HWID_TL_WR741ND_V1,
    -		.hw_rev		= 1,
    -		.layout_id	= "4M",
    -	}, {
    -		.id		= "TL-WR741NDv4",
    -		.hw_id		= HWID_TL_WR741ND_V4,
    -		.hw_rev		= 1,
    -		.layout_id	= "4Mlzma",
    -	}, {
    -		.id		= "TL-WR740Nv1",
    -		.hw_id		= HWID_TL_WR740N_V1,
    -		.hw_rev		= 1,
    -		.layout_id	= "4M",
    -	}, {
    -		.id		= "TL-WR740Nv3",
    -		.hw_id		= HWID_TL_WR740N_V3,
    -		.hw_rev		= 1,
    -		.layout_id	= "4M",
    -	}, {
    -		.id		= "TL-WR743NDv1",
    -		.hw_id		= HWID_TL_WR743ND_V1,
    -		.hw_rev		= 1,
    -		.layout_id	= "4M",
    -	}, {
    -		.id		= "TL-WR743NDv2",
    -		.hw_id		= HWID_TL_WR743ND_V2,
    -		.hw_rev		= 1,
    -		.layout_id	= "4Mlzma",
    -	}, {
    -		.id		= "TL-WR841Nv1.5",
    -		.hw_id		= HWID_TL_WR841N_V1_5,
    -		.hw_rev		= 2,
    -		.layout_id	= "4M",
    -	}, {
    -		.id		= "TL-WR841NDv3",
    -		.hw_id		= HWID_TL_WR841ND_V3,
    -		.hw_rev		= 3,
    -		.layout_id	= "4M",
    -	}, {
    -		.id		= "TL-WR841NDv5",
    -		.hw_id		= HWID_TL_WR841ND_V5,
    -		.hw_rev		= 1,
    -		.layout_id	= "4M",
    -	}, {
    -		.id		= "TL-WR841NDv7",
    -		.hw_id		= HWID_TL_WR841ND_V7,
    -		.hw_rev		= 1,
    -		.layout_id	= "4M",
    -	}, {
    -		.id		= "TL-WR941NDv2",
    -		.hw_id		= HWID_TL_WR941ND_V2,
    -		.hw_rev		= 2,
    -		.layout_id	= "4M",
    -	}, {
    -		.id		= "TL-WR941NDv4",
    -		.hw_id		= HWID_TL_WR941ND_V4,
    -		.hw_rev		= 1,
    -		.layout_id	= "4M",
    -	}, {
    -		.id		= "TL-WR1041Nv2",
    -		.hw_id		= HWID_TL_WR1041N_V2,
    -		.hw_rev		= 1,
    -		.layout_id	= "4Mlzma",
    -	}, {
    -		.id		= "TL-WR1043NDv1",
    -		.hw_id		= HWID_TL_WR1043ND_V1,
    -		.hw_rev		= 1,
    -		.layout_id	= "8M",
    -	}, {
    -		.id		= "TL-WR1043NDv2",
    -		.hw_id		= HWID_TL_WR1043ND_V2,
    -		.hw_rev		= 1,
    -		.layout_id	= "8Mlzma",
    -	}, {
    -		.id		= "TL-WR2543Nv1",
    -		.hw_id		= HWID_TL_WR2543N_V1,
    -		.hw_rev		= 1,
    -		.layout_id	= "8Mlzma",
    -	}, {
    -		.id		= "TL-WR703Nv1",
    -		.hw_id		= HWID_TL_WR703N_V1,
    -		.hw_rev		= 1,
    -		.layout_id	= "4Mlzma",
    -	}, {
    -		.id		= "TL-WR720Nv3",
    -		.hw_id		= HWID_TL_WR720N_V3,
    -		.hw_rev		= 1,
    -		.layout_id	= "4Mlzma",
    -	}, {
    -		.id		= "TL-WR720Nv4",
    -		.hw_id		= HWID_TL_WR720N_V4,
    -		.hw_rev		= 1,
    -		.layout_id	= "4Mlzma",
    -	}, {
    -		.id		= "GL-INETv1",
    -		.hw_id		= HWID_GL_INET_V1,
    -		.hw_rev		= 1,
    -		.layout_id	= "8Mlzma",
    -	}, {
    -		.id		= "GS-OOLITEv1",
    -		.hw_id		= HWID_GS_OOLITE_V1,
    -		.hw_rev		= 1,
    -		.layout_id	= "16Mlzma",
    -	}, {
    -		.id		= "ONION-OMEGA",
    -		.hw_id		= HWID_ONION_OMEGA,
    -		.hw_rev		= 1,
    -		.layout_id	= "16Mlzma",
    -	}, {
    -		.id		= "ANTMINER-S1",
    -		.hw_id		= HWID_ANTMINER_S1,
    -		.hw_rev		= 1,
    -		.layout_id	= "8Mlzma",
    -	}, {
    -		.id		= "ANTMINER-S3",
    -		.hw_id		= HWID_ANTMINER_S3,
    -		.hw_rev		= 1,
    -		.layout_id	= "8Mlzma",
    -	}, {
    -		/* terminating entry */
    -	}
    +static const struct fw_region regions[] = {
    +	/* Default region (universal) uses code 0 as well */
    +	{"US", 1},
    +	{"EU", 0},
     };
     
     /*
    @@ -464,7 +200,7 @@ static struct board_info boards[] = {
     #define ERRS(fmt, ...) do { \
     	int save = errno; \
     	fflush(0); \
    -	fprintf(stderr, "[%s] *** error: " fmt "\n", \
    +	fprintf(stderr, "[%s] *** error: " fmt ": %s\n", \
     			progname, ## __VA_ARGS__, strerror(save)); \
     } while (0)
     
    @@ -472,35 +208,7 @@ static struct board_info boards[] = {
     	fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
     } while (0)
     
    -static struct board_info *find_board(char *id)
    -{
    -	struct board_info *ret;
    -	struct board_info *board;
    -
    -	ret = NULL;
    -	for (board = boards; board->id != NULL; board++){
    -		if (strcasecmp(id, board->id) == 0) {
    -			ret = board;
    -			break;
    -		}
    -	};
    -
    -	return ret;
    -}
    -
    -static struct board_info *find_board_by_hwid(uint32_t hw_id)
    -{
    -	struct board_info *board;
    -
    -	for (board = boards; board->id != NULL; board++) {
    -		if (hw_id == board->hw_id)
    -			return board;
    -	};
    -
    -	return NULL;
    -}
    -
    -static struct flash_layout *find_layout(char *id)
    +static struct flash_layout *find_layout(const char *id)
     {
     	struct flash_layout *ret;
     	struct flash_layout *l;
    @@ -516,21 +224,29 @@ static struct flash_layout *find_layout(char *id)
     	return ret;
     }
     
    +static const struct fw_region * find_region(const char *country) {
    +	size_t i;
    +
    +	for (i = 0; i < ARRAY_SIZE(regions); i++) {
    +		if (strcasecmp(regions[i].name, country) == 0)
    +			return &regions[i];
    +	}
    +
    +	return NULL;
    +}
    +
     static void usage(int status)
     {
    -	FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
    -	struct board_info *board;
    -
    -	fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
    -	fprintf(stream,
    +	fprintf(stderr, "Usage: %s [OPTIONS...]\n", progname);
    +	fprintf(stderr,
     "\n"
     "Options:\n"
    -"  -B <board>      create image for the board specified with <board>\n"
     "  -c              use combined kernel image\n"
     "  -E <ep>         overwrite kernel entry point with <ep> (hexval prefixed with 0x)\n"
     "  -L <la>         overwrite kernel load address with <la> (hexval prefixed with 0x)\n"
     "  -H <hwid>       use hardware id specified with <hwid>\n"
     "  -W <hwrev>      use hardware revision specified with <hwrev>\n"
    +"  -C <country>    set region code to <country>\n"
     "  -F <id>         use flash layout specified with <id>\n"
     "  -k <file>       read kernel image from the file <file>\n"
     "  -r <file>       read rootfs image from the file <file>\n"
    @@ -543,6 +259,7 @@ static void usage(int status)
     "  -N <vendor>     set image vendor to <vendor>\n"
     "  -V <version>    set image version to <version>\n"
     "  -v <version>    set firmware version to <version>\n"
    +"  -m <version>    set header version to <version>\n"
     "  -i <file>       inspect given firmware file <file>\n"
     "  -x              extract kernel and rootfs while inspecting (requires -i)\n"
     "  -X <size>       reserve <size> bytes in the firmware image (hexval prefixed with 0x)\n"
    @@ -552,7 +269,7 @@ static void usage(int status)
     	exit(status);
     }
     
    -static int get_md5(char *data, int size, char *md5)
    +static void get_md5(const char *data, int size, uint8_t *md5)
     {
     	MD5_CTX ctx;
     
    @@ -579,7 +296,7 @@ static int get_file_stat(struct file_info *fdata)
     	return 0;
     }
     
    -static int read_to_buf(struct file_info *fdata, char *buf)
    +static int read_to_buf(const struct file_info *fdata, char *buf)
     {
     	FILE *f;
     	int ret = EXIT_FAILURE;
    @@ -608,6 +325,7 @@ static int read_to_buf(struct file_info *fdata, char *buf)
     static int check_options(void)
     {
     	int ret;
    +	int exceed_bytes;
     
     	if (inspect_info.file_name) {
     		ret = get_file_stat(&inspect_info);
    @@ -620,33 +338,28 @@ static int check_options(void)
     		return -1;
     	}
     
    -	if (board_id == NULL && opt_hw_id == NULL) {
    -		ERR("either board or hardware id must be specified");
    +	if (opt_hw_id == NULL) {
    +		ERR("hardware id not specified");
     		return -1;
     	}
    +	hw_id = strtoul(opt_hw_id, NULL, 0);
     
    -	if (board_id) {
    -		board = find_board(board_id);
    -		if (board == NULL) {
    -			ERR("unknown/unsupported board id \"%s\"", board_id);
    -			return -1;
    -		}
    -		if (layout_id == NULL)
    -			layout_id = board->layout_id;
    +	if (layout_id == NULL) {
    +		ERR("flash layout is not specified");
    +		return -1;
    +	}
     
    -		hw_id = board->hw_id;
    -		hw_rev = board->hw_rev;
    -	} else {
    -		if (layout_id == NULL) {
    -			ERR("flash layout is not specified");
    +	if (opt_hw_rev)
    +		hw_rev = strtoul(opt_hw_rev, NULL, 0);
    +	else
    +		hw_rev = 1;
    +
    +	if (country) {
    +		region = find_region(country);
    +		if (!region) {
    +			ERR("unknown region code \"%s\"", country);
     			return -1;
     		}
    -		hw_id = strtoul(opt_hw_id, NULL, 0);
    -
    -		if (opt_hw_rev)
    -			hw_rev = strtoul(opt_hw_rev, NULL, 0);
    -		else
    -			hw_rev = 1;
     	}
     
     	layout = find_layout(layout_id);
    @@ -681,10 +394,10 @@ static int check_options(void)
     	kernel_len = kernel_info.file_size;
     
     	if (combined) {
    -		if (kernel_info.file_size >
    -		    fw_max_len - sizeof(struct fw_header)) {
    +		exceed_bytes = kernel_info.file_size - (fw_max_len - sizeof(struct fw_header));
    +		if (exceed_bytes > 0) {
     			if (!ignore_size) {
    -				ERR("kernel image is too big");
    +				ERR("kernel image is too big by %i bytes", exceed_bytes);
     				return -1;
     			}
     			layout->fw_max_len = sizeof(struct fw_header) +
    @@ -708,21 +421,21 @@ static int check_options(void)
     
     			DBG("kernel length aligned to %u", kernel_len);
     
    -			if (kernel_len + rootfs_info.file_size >
    -			    fw_max_len - sizeof(struct fw_header)) {
    -				ERR("images are too big");
    +			exceed_bytes = kernel_len + rootfs_info.file_size - (fw_max_len - sizeof(struct fw_header));
    +			if (exceed_bytes > 0) {
    +				ERR("images are too big by %i bytes", exceed_bytes);
     				return -1;
     			}
     		} else {
    -			if (kernel_info.file_size >
    -			    rootfs_ofs - sizeof(struct fw_header)) {
    -				ERR("kernel image is too big");
    +			exceed_bytes = kernel_info.file_size - (rootfs_ofs - sizeof(struct fw_header));
    +			if (exceed_bytes > 0) {
    +				ERR("kernel image is too big by %i bytes", exceed_bytes);
     				return -1;
     			}
     
    -			if (rootfs_info.file_size >
    -			    (fw_max_len - rootfs_ofs)) {
    -				ERR("rootfs image is too big");
    +			exceed_bytes = rootfs_info.file_size - (fw_max_len - rootfs_ofs);
    +			if (exceed_bytes > 0) {
    +				ERR("rootfs image is too big by %i bytes", exceed_bytes);
     				return -1;
     			}
     		}
    @@ -739,6 +452,15 @@ static int check_options(void)
     		return -1;
     	}
     
    +	if (opt_hdr_ver == 1) {
    +		hdr_ver = HEADER_VERSION_V1;
    +	} else if (opt_hdr_ver == 2) {
    +		hdr_ver = HEADER_VERSION_V2;
    +	} else {
    +		ERR("invalid header version '%u'", opt_hdr_ver);
    +		return -1;
    +	}
    +
     	return 0;
     }
     
    @@ -748,7 +470,7 @@ static void fill_header(char *buf, int len)
     
     	memset(hdr, 0, sizeof(struct fw_header));
     
    -	hdr->version = htonl(HEADER_VERSION_V1);
    +	hdr->version = htonl(hdr_ver);
     	strncpy(hdr->vendor_name, vendor, sizeof(hdr->vendor_name));
     	strncpy(hdr->fw_version, version, sizeof(hdr->fw_version));
     	hdr->hw_id = htonl(hw_id);
    @@ -773,6 +495,18 @@ static void fill_header(char *buf, int len)
     	hdr->ver_mid = htons(fw_ver_mid);
     	hdr->ver_lo = htons(fw_ver_lo);
     
    +	if (region) {
    +		hdr->region_code = htonl(region->code);
    +		snprintf(
    +			hdr->region_str1, sizeof(hdr->region_str1), "00000000;%02X%02X%02X%02X;",
    +			region->name[0], region->name[1], region->name[2], region->name[3]
    +		);
    +		snprintf(
    +			hdr->region_str2, sizeof(hdr->region_str2), "%02X%02X%02X%02X",
    +			region->name[0], region->name[1], region->name[2], region->name[3]
    +		);
    +	}
    +
     	get_md5(buf, len, hdr->md5sum1);
     }
     
    @@ -810,7 +544,7 @@ static int pad_jffs2(char *buf, int currlen)
     	return len;
     }
     
    -static int write_fw(char *data, int len)
    +static int write_fw(const char *data, int len)
     {
     	FILE *f;
     	int ret = EXIT_FAILURE;
    @@ -902,61 +636,22 @@ static int build_fw(void)
     }
     
     /* Helper functions to inspect_fw() representing different output formats */
    -static inline void inspect_fw_pstr(char *label, char *str)
    +static inline void inspect_fw_pstr(const char *label, const char *str)
     {
     	printf("%-23s: %s\n", label, str);
     }
     
    -static inline void inspect_fw_phex(char *label, uint32_t val)
    +static inline void inspect_fw_phex(const char *label, uint32_t val)
     {
     	printf("%-23s: 0x%08x\n", label, val);
     }
     
    -static inline void inspect_fw_phexpost(char *label,
    -                                       uint32_t val, char *post)
    -{
    -	printf("%-23s: 0x%08x (%s)\n", label, val, post);
    -}
    -
    -static inline void inspect_fw_phexdef(char *label,
    -                                      uint32_t val, uint32_t defval)
    -{
    -	printf("%-23s: 0x%08x                  ", label, val);
    -
    -	if (val == defval)
    -		printf("(== OpenWrt default)\n");
    -	else
    -		printf("(OpenWrt default: 0x%08x)\n", defval);
    -}
    -
    -static inline void inspect_fw_phexexp(char *label,
    -                                      uint32_t val, uint32_t expval)
    -{
    -	printf("%-23s: 0x%08x ", label, val);
    -
    -	if (val == expval)
    -		printf("(ok)\n");
    -	else
    -		printf("(expected: 0x%08x)\n", expval);
    -}
    -
    -static inline void inspect_fw_phexdec(char *label, uint32_t val)
    +static inline void inspect_fw_phexdec(const char *label, uint32_t val)
     {
     	printf("%-23s: 0x%08x / %8u bytes\n", label, val, val);
     }
     
    -static inline void inspect_fw_phexdecdef(char *label,
    -                                         uint32_t val, uint32_t defval)
    -{
    -	printf("%-23s: 0x%08x / %8u bytes ", label, val, val);
    -
    -	if (val == defval)
    -		printf("(== OpenWrt default)\n");
    -	else
    -		printf("(OpenWrt default: 0x%08x)\n", defval);
    -}
    -
    -static inline void inspect_fw_pmd5sum(char *label, uint8_t *val, char *text)
    +static inline void inspect_fw_pmd5sum(const char *label, const uint8_t *val, const char *text)
     {
     	int i;
     
    @@ -971,7 +666,6 @@ static int inspect_fw(void)
     	char *buf;
     	struct fw_header *hdr;
     	uint8_t md5sum[MD5SUM_LEN];
    -	struct board_info *board;
     	int ret = EXIT_FAILURE;
     
     	buf = malloc(inspect_info.file_size);
    @@ -988,16 +682,14 @@ static int inspect_fw(void)
     	inspect_fw_pstr("File name", inspect_info.file_name);
     	inspect_fw_phexdec("File size", inspect_info.file_size);
     
    -	if (ntohl(hdr->version) != HEADER_VERSION_V1) {
    -		ERR("file does not seem to have V1 header!\n");
    +	if ((ntohl(hdr->version) != HEADER_VERSION_V1) &&
    +	    (ntohl(hdr->version) != HEADER_VERSION_V2)) {
    +		ERR("file does not seem to have V1/V2 header!\n");
     		goto out_free_buf;
     	}
     
     	inspect_fw_phexdec("Version 1 Header size", sizeof(struct fw_header));
     
    -	if (ntohl(hdr->unk1) != 0)
    -		inspect_fw_phexdec("Unknown value 1", hdr->unk1);
    -
     	memcpy(md5sum, hdr->md5sum1, sizeof(md5sum));
     	if (ntohl(hdr->boot_len) == 0)
     		memcpy(hdr->md5sum1, md5salt_normal, sizeof(md5sum));
    @@ -1022,19 +714,9 @@ static int inspect_fw(void)
     
     	inspect_fw_pstr("Vendor name", hdr->vendor_name);
     	inspect_fw_pstr("Firmware version", hdr->fw_version);
    -	board = find_board_by_hwid(ntohl(hdr->hw_id));
    -	if (board) {
    -		layout = find_layout(board->layout_id);
    -		inspect_fw_phexpost("Hardware ID",
    -		                    ntohl(hdr->hw_id), board->id);
    -		inspect_fw_phexexp("Hardware Revision",
    -		                   ntohl(hdr->hw_rev), board->hw_rev);
    -	} else {
    -		inspect_fw_phexpost("Hardware ID",
    -		                    ntohl(hdr->hw_id), "unknown");
    -		inspect_fw_phex("Hardware Revision",
    -		                ntohl(hdr->hw_rev));
    -	}
    +	inspect_fw_phex("Hardware ID", ntohl(hdr->hw_id));
    +	inspect_fw_phex("Hardware Revision", ntohl(hdr->hw_rev));
    +	inspect_fw_phex("Region code", ntohl(hdr->region_code));
     
     	printf("\n");
     
    @@ -1042,24 +724,12 @@ static int inspect_fw(void)
     	                   ntohl(hdr->kernel_ofs));
     	inspect_fw_phexdec("Kernel data length",
     	                   ntohl(hdr->kernel_len));
    -	if (board) {
    -		inspect_fw_phexdef("Kernel load address",
    -		                   ntohl(hdr->kernel_la),
    -		                   layout ? layout->kernel_la : 0xffffffff);
    -		inspect_fw_phexdef("Kernel entry point",
    -		                   ntohl(hdr->kernel_ep),
    -		                   layout ? layout->kernel_ep : 0xffffffff);
    -		inspect_fw_phexdecdef("Rootfs data offset",
    -		                      ntohl(hdr->rootfs_ofs),
    -		                      layout ? layout->rootfs_ofs : 0xffffffff);
    -	} else {
    -		inspect_fw_phex("Kernel load address",
    -		                ntohl(hdr->kernel_la));
    -		inspect_fw_phex("Kernel entry point",
    -		                ntohl(hdr->kernel_ep));
    -		inspect_fw_phexdec("Rootfs data offset",
    -		                   ntohl(hdr->rootfs_ofs));
    -	}
    +	inspect_fw_phex("Kernel load address",
    +	                ntohl(hdr->kernel_la));
    +	inspect_fw_phex("Kernel entry point",
    +	                ntohl(hdr->kernel_ep));
    +	inspect_fw_phexdec("Rootfs data offset",
    +	                   ntohl(hdr->rootfs_ofs));
     	inspect_fw_phexdec("Rootfs data length",
     	                   ntohl(hdr->rootfs_len));
     	inspect_fw_phexdec("Boot loader data offset",
    @@ -1115,16 +785,13 @@ static int inspect_fw(void)
     int main(int argc, char *argv[])
     {
     	int ret = EXIT_FAILURE;
    -	int err;
    -
    -	FILE *outfile;
     
     	progname = basename(argv[0]);
     
     	while ( 1 ) {
     		int c;
     
    -		c = getopt(argc, argv, "a:B:H:E:F:L:V:N:W:ci:k:r:R:o:xX:hsSjv:");
    +		c = getopt(argc, argv, "a:H:E:F:L:m:V:N:W:C:ci:k:r:R:o:xX:hsSjv:");
     		if (c == -1)
     			break;
     
    @@ -1132,9 +799,6 @@ int main(int argc, char *argv[])
     		case 'a':
     			sscanf(optarg, "0x%x", &rootfs_align);
     			break;
    -		case 'B':
    -			board_id = optarg;
    -			break;
     		case 'H':
     			opt_hw_id = optarg;
     			break;
    @@ -1147,9 +811,15 @@ int main(int argc, char *argv[])
     		case 'W':
     			opt_hw_rev = optarg;
     			break;
    +		case 'C':
    +			country = optarg;
    +			break;
     		case 'L':
     			sscanf(optarg, "0x%x", &kernel_la);
     			break;
    +		case 'm':
    +			sscanf(optarg, "%u", &opt_hdr_ver);
    +			break;
     		case 'V':
     			version = optarg;
     			break;