diff --git a/tools/Makefile b/tools/Makefile index f5be9bb5c44..272c6254351 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -16,6 +16,7 @@ endif tools-y += m4 autoconf automake bison pkg-config sed mklibs tools-y += sstrip ipkg-utils genext2fs mtd-utils mkimage tools-y += firmware-utils patch-cmdline quilt yaffs2 +tools-y += wrt350nv2-builder ifneq ($(CONFIG_LINUX_2_4)$(CONFIG_LINUX_2_6_21)$(CONFIG_LINUX_2_6_25)$(CONFIG_LINUX_2_6_28),) tools-y += squashfs lzma-old else diff --git a/tools/wrt350nv2-builder/Makefile b/tools/wrt350nv2-builder/Makefile new file mode 100644 index 00000000000..648dd84db9c --- /dev/null +++ b/tools/wrt350nv2-builder/Makefile @@ -0,0 +1,33 @@ +# +# Copyright (C) 2006-2009 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=wrt350nv2-builder +PKG_VERSION:=2.0 + +HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/${PKG_NAME}-$(PKG_VERSION) + +include $(INCLUDE_DIR)/host-build.mk + +define Host/Compile + $(HOSTCC) $(HOST_CFLAGS) -c src/md5.c -o $(HOST_BUILD_DIR)/md5.o + $(HOSTCC) $(HOST_CFLAGS) -c src/ioapi.c -o $(HOST_BUILD_DIR)/ioapi.o + $(HOSTCC) $(HOST_CFLAGS) -c src/wrt350nv2-builder.c -o $(HOST_BUILD_DIR)/wrt350nv2-builder.o + $(HOSTCC) $(HOST_CFLAGS) -o $(HOST_BUILD_DIR)/wrt350nv2-builder $(HOST_BUILD_DIR)/wrt350nv2-builder.o $(HOST_BUILD_DIR)/md5.o $(HOST_BUILD_DIR)/ioapi.o +endef + +define Host/Install + $(INSTALL_DIR) $(STAGING_DIR_HOST)/bin + $(INSTALL_BIN) $(HOST_BUILD_DIR)/wrt350nv2-builder $(STAGING_DIR_HOST)/bin/ +endef + +define Host/Clean + rm -f $(STAGING_DIR_HOST)/bin/wrt350nv2-builder +endef + +$(eval $(call HostBuild)) diff --git a/tools/wrt350nv2-builder/src/crypt.h b/tools/wrt350nv2-builder/src/crypt.h new file mode 100644 index 00000000000..622f4bc2ec4 --- /dev/null +++ b/tools/wrt350nv2-builder/src/crypt.h @@ -0,0 +1,132 @@ +/* crypt.h -- base code for crypt/uncrypt ZIPfile + + + Version 1.01e, February 12th, 2005 + + Copyright (C) 1998-2005 Gilles Vollant + + This code is a modified version of crypting code in Infozip distribution + + The encryption/decryption parts of this source code (as opposed to the + non-echoing password parts) were originally written in Europe. The + whole source package can be freely distributed, including from the USA. + (Prior to January 2000, re-export from the US was a violation of US law.) + + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). + + If you don't need crypting in your application, just define symbols + NOCRYPT and NOUNCRYPT. + + This code support the "Traditional PKWARE Encryption". + + The new AES encryption added on Zip format by Winzip (see the page + http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong + Encryption is not supported. +*/ + +#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) + +/*********************************************************************** + * Return the next byte in the pseudo-random sequence + */ +static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab) +{ + unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an + * unpredictable manner on 16-bit systems; not a problem + * with any known compiler so far, though */ + + temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2; + return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); +} + +/*********************************************************************** + * Update the encryption keys with the next byte of plain text + */ +static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c) +{ + (*(pkeys+0)) = CRC32((*(pkeys+0)), c); + (*(pkeys+1)) += (*(pkeys+0)) & 0xff; + (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; + { + register int keyshift = (int)((*(pkeys+1)) >> 24); + (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift); + } + return c; +} + + +/*********************************************************************** + * Initialize the encryption keys and the random header according to + * the given password. + */ +static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab) +{ + *(pkeys+0) = 305419896L; + *(pkeys+1) = 591751049L; + *(pkeys+2) = 878082192L; + while (*passwd != '\0') { + update_keys(pkeys,pcrc_32_tab,(int)*passwd); + passwd++; + } +} + +#define zdecode(pkeys,pcrc_32_tab,c) \ + (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) + +#define zencode(pkeys,pcrc_32_tab,c,t) \ + (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c)) + +#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED + +#define RAND_HEAD_LEN 12 + /* "last resort" source for second part of crypt seed pattern */ +# ifndef ZCR_SEED2 +# define ZCR_SEED2 3141592654UL /* use PI as default pattern */ +# endif + +static int crypthead(passwd, buf, bufSize, pkeys, pcrc_32_tab, crcForCrypting) + const char *passwd; /* password string */ + unsigned char *buf; /* where to write header */ + int bufSize; + unsigned long* pkeys; + const unsigned long* pcrc_32_tab; + unsigned long crcForCrypting; +{ + int n; /* index in random header */ + int t; /* temporary */ + int c; /* random byte */ + unsigned char header[RAND_HEAD_LEN-2]; /* random header */ + static unsigned calls = 0; /* ensure different random header each time */ + + if (bufSize> 7) & 0xff; + header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t); + } + /* Encrypt random header (last two bytes is high word of crc) */ + init_keys(passwd, pkeys, pcrc_32_tab); + for (n = 0; n < RAND_HEAD_LEN-2; n++) + { + buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t); + } + buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); + buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); + return n; +} + +#endif diff --git a/tools/wrt350nv2-builder/src/ioapi.c b/tools/wrt350nv2-builder/src/ioapi.c new file mode 100644 index 00000000000..f1bee23e64b --- /dev/null +++ b/tools/wrt350nv2-builder/src/ioapi.c @@ -0,0 +1,177 @@ +/* ioapi.c -- IO base function header for compress/uncompress .zip + files using zlib + zip or unzip API + + Version 1.01e, February 12th, 2005 + + Copyright (C) 1998-2005 Gilles Vollant +*/ + +#include +#include +#include + +#include "zlib.h" +#include "ioapi.h" + + + +/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ + +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif + +#ifndef SEEK_END +#define SEEK_END 2 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +voidpf ZCALLBACK fopen_file_func OF(( + voidpf opaque, + const char* filename, + int mode)); + +uLong ZCALLBACK fread_file_func OF(( + voidpf opaque, + voidpf stream, + void* buf, + uLong size)); + +uLong ZCALLBACK fwrite_file_func OF(( + voidpf opaque, + voidpf stream, + const void* buf, + uLong size)); + +long ZCALLBACK ftell_file_func OF(( + voidpf opaque, + voidpf stream)); + +long ZCALLBACK fseek_file_func OF(( + voidpf opaque, + voidpf stream, + uLong offset, + int origin)); + +int ZCALLBACK fclose_file_func OF(( + voidpf opaque, + voidpf stream)); + +int ZCALLBACK ferror_file_func OF(( + voidpf opaque, + voidpf stream)); + + +voidpf ZCALLBACK fopen_file_func (opaque, filename, mode) + voidpf opaque; + const char* filename; + int mode; +{ + FILE* file = NULL; + const char* mode_fopen = NULL; + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + mode_fopen = "rb"; + else + if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + mode_fopen = "r+b"; + else + if (mode & ZLIB_FILEFUNC_MODE_CREATE) + mode_fopen = "wb"; + + if ((filename!=NULL) && (mode_fopen != NULL)) + file = fopen(filename, mode_fopen); + return file; +} + + +uLong ZCALLBACK fread_file_func (opaque, stream, buf, size) + voidpf opaque; + voidpf stream; + void* buf; + uLong size; +{ + uLong ret; + ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + + +uLong ZCALLBACK fwrite_file_func (opaque, stream, buf, size) + voidpf opaque; + voidpf stream; + const void* buf; + uLong size; +{ + uLong ret; + ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + +long ZCALLBACK ftell_file_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + long ret; + ret = ftell((FILE *)stream); + return ret; +} + +long ZCALLBACK fseek_file_func (opaque, stream, offset, origin) + voidpf opaque; + voidpf stream; + uLong offset; + int origin; +{ + int fseek_origin=0; + long ret; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + fseek_origin = SEEK_CUR; + break; + case ZLIB_FILEFUNC_SEEK_END : + fseek_origin = SEEK_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + fseek_origin = SEEK_SET; + break; + default: return -1; + } + ret = 0; + fseek((FILE *)stream, offset, fseek_origin); + return ret; +} + +int ZCALLBACK fclose_file_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + int ret; + ret = fclose((FILE *)stream); + return ret; +} + +int ZCALLBACK ferror_file_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + int ret; + ret = ferror((FILE *)stream); + return ret; +} + +void fill_fopen_filefunc (pzlib_filefunc_def) + zlib_filefunc_def* pzlib_filefunc_def; +{ + pzlib_filefunc_def->zopen_file = fopen_file_func; + pzlib_filefunc_def->zread_file = fread_file_func; + pzlib_filefunc_def->zwrite_file = fwrite_file_func; + pzlib_filefunc_def->ztell_file = ftell_file_func; + pzlib_filefunc_def->zseek_file = fseek_file_func; + pzlib_filefunc_def->zclose_file = fclose_file_func; + pzlib_filefunc_def->zerror_file = ferror_file_func; + pzlib_filefunc_def->opaque = NULL; +} diff --git a/tools/wrt350nv2-builder/src/ioapi.h b/tools/wrt350nv2-builder/src/ioapi.h new file mode 100644 index 00000000000..7d457baab34 --- /dev/null +++ b/tools/wrt350nv2-builder/src/ioapi.h @@ -0,0 +1,75 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + files using zlib + zip or unzip API + + Version 1.01e, February 12th, 2005 + + Copyright (C) 1998-2005 Gilles Vollant +*/ + +#ifndef _ZLIBIOAPI_H +#define _ZLIBIOAPI_H + + +#define ZLIB_FILEFUNC_SEEK_CUR (1) +#define ZLIB_FILEFUNC_SEEK_END (2) +#define ZLIB_FILEFUNC_SEEK_SET (0) + +#define ZLIB_FILEFUNC_MODE_READ (1) +#define ZLIB_FILEFUNC_MODE_WRITE (2) +#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) + +#define ZLIB_FILEFUNC_MODE_EXISTING (4) +#define ZLIB_FILEFUNC_MODE_CREATE (8) + + +#ifndef ZCALLBACK + +#if (defined(WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) +#define ZCALLBACK CALLBACK +#else +#define ZCALLBACK +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); +typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); +typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); +typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); +typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); +typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); + +typedef struct zlib_filefunc_def_s +{ + open_file_func zopen_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell_file_func ztell_file; + seek_file_func zseek_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc_def; + + + +void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); + +#define ZREAD(filefunc,filestream,buf,size) ((*((filefunc).zread_file))((filefunc).opaque,filestream,buf,size)) +#define ZWRITE(filefunc,filestream,buf,size) ((*((filefunc).zwrite_file))((filefunc).opaque,filestream,buf,size)) +#define ZTELL(filefunc,filestream) ((*((filefunc).ztell_file))((filefunc).opaque,filestream)) +#define ZSEEK(filefunc,filestream,pos,mode) ((*((filefunc).zseek_file))((filefunc).opaque,filestream,pos,mode)) +#define ZCLOSE(filefunc,filestream) ((*((filefunc).zclose_file))((filefunc).opaque,filestream)) +#define ZERROR(filefunc,filestream) ((*((filefunc).zerror_file))((filefunc).opaque,filestream)) + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/tools/wrt350nv2-builder/src/md5.c b/tools/wrt350nv2-builder/src/md5.c new file mode 100644 index 00000000000..c35d96c5ef5 --- /dev/null +++ b/tools/wrt350nv2-builder/src/md5.c @@ -0,0 +1,381 @@ +/* + Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.c is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order + either statically or dynamically; added missing #include + in library. + 2002-03-11 lpd Corrected argument list for main(), and added int return + type, in test program and T value program. + 2002-02-21 lpd Added missing #include in test program. + 2000-07-03 lpd Patched to eliminate warnings about "constant is + unsigned in ANSI C, signed in traditional"; made test program + self-checking. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). + 1999-05-03 lpd Original version. + */ + +#include "md5.h" +#include + +#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ +#ifdef ARCH_IS_BIG_ENDIAN +# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) +#else +# define BYTE_ORDER 0 +#endif + +#define T_MASK ((md5_word_t)~0) +#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) +#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) +#define T3 0x242070db +#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) +#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) +#define T6 0x4787c62a +#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) +#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) +#define T9 0x698098d8 +#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) +#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) +#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) +#define T13 0x6b901122 +#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) +#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) +#define T16 0x49b40821 +#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) +#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) +#define T19 0x265e5a51 +#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) +#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) +#define T22 0x02441453 +#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) +#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) +#define T25 0x21e1cde6 +#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) +#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) +#define T28 0x455a14ed +#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) +#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) +#define T31 0x676f02d9 +#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) +#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) +#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) +#define T35 0x6d9d6122 +#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) +#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) +#define T38 0x4bdecfa9 +#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) +#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) +#define T41 0x289b7ec6 +#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) +#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) +#define T44 0x04881d05 +#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) +#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) +#define T47 0x1fa27cf8 +#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) +#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) +#define T50 0x432aff97 +#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) +#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) +#define T53 0x655b59c3 +#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) +#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) +#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) +#define T57 0x6fa87e4f +#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) +#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) +#define T60 0x4e0811a1 +#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) +#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) +#define T63 0x2ad7d2bb +#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) + + +static void +md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) +{ + md5_word_t + a = pms->abcd[0], b = pms->abcd[1], + c = pms->abcd[2], d = pms->abcd[3]; + md5_word_t t; +#if BYTE_ORDER > 0 + /* Define storage only for big-endian CPUs. */ + md5_word_t X[16]; +#else + /* Define storage for little-endian or both types of CPUs. */ + md5_word_t xbuf[16]; + const md5_word_t *X; +#endif + + { +#if BYTE_ORDER == 0 + /* + * Determine dynamically whether this is a big-endian or + * little-endian machine, since we can use a more efficient + * algorithm on the latter. + */ + static const int w = 1; + + if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ +#endif +#if BYTE_ORDER <= 0 /* little-endian */ + { + /* + * On little-endian machines, we can process properly aligned + * data without copying it. + */ + if (!((data - (const md5_byte_t *)0) & 3)) { + /* data are properly aligned */ + X = (const md5_word_t *)data; + } else { + /* not aligned */ + memcpy(xbuf, data, 64); + X = xbuf; + } + } +#endif +#if BYTE_ORDER == 0 + else /* dynamic big-endian */ +#endif +#if BYTE_ORDER >= 0 /* big-endian */ + { + /* + * On big-endian machines, we must arrange the bytes in the + * right order. + */ + const md5_byte_t *xp = data; + int i; + +# if BYTE_ORDER == 0 + X = xbuf; /* (dynamic only) */ +# else +# define xbuf X /* (static only) */ +# endif + for (i = 0; i < 16; ++i, xp += 4) + xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); + } +#endif + } + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + + /* Round 1. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ +#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + F(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 7, T1); + SET(d, a, b, c, 1, 12, T2); + SET(c, d, a, b, 2, 17, T3); + SET(b, c, d, a, 3, 22, T4); + SET(a, b, c, d, 4, 7, T5); + SET(d, a, b, c, 5, 12, T6); + SET(c, d, a, b, 6, 17, T7); + SET(b, c, d, a, 7, 22, T8); + SET(a, b, c, d, 8, 7, T9); + SET(d, a, b, c, 9, 12, T10); + SET(c, d, a, b, 10, 17, T11); + SET(b, c, d, a, 11, 22, T12); + SET(a, b, c, d, 12, 7, T13); + SET(d, a, b, c, 13, 12, T14); + SET(c, d, a, b, 14, 17, T15); + SET(b, c, d, a, 15, 22, T16); +#undef SET + + /* Round 2. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ +#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + G(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 1, 5, T17); + SET(d, a, b, c, 6, 9, T18); + SET(c, d, a, b, 11, 14, T19); + SET(b, c, d, a, 0, 20, T20); + SET(a, b, c, d, 5, 5, T21); + SET(d, a, b, c, 10, 9, T22); + SET(c, d, a, b, 15, 14, T23); + SET(b, c, d, a, 4, 20, T24); + SET(a, b, c, d, 9, 5, T25); + SET(d, a, b, c, 14, 9, T26); + SET(c, d, a, b, 3, 14, T27); + SET(b, c, d, a, 8, 20, T28); + SET(a, b, c, d, 13, 5, T29); + SET(d, a, b, c, 2, 9, T30); + SET(c, d, a, b, 7, 14, T31); + SET(b, c, d, a, 12, 20, T32); +#undef SET + + /* Round 3. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + H(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 5, 4, T33); + SET(d, a, b, c, 8, 11, T34); + SET(c, d, a, b, 11, 16, T35); + SET(b, c, d, a, 14, 23, T36); + SET(a, b, c, d, 1, 4, T37); + SET(d, a, b, c, 4, 11, T38); + SET(c, d, a, b, 7, 16, T39); + SET(b, c, d, a, 10, 23, T40); + SET(a, b, c, d, 13, 4, T41); + SET(d, a, b, c, 0, 11, T42); + SET(c, d, a, b, 3, 16, T43); + SET(b, c, d, a, 6, 23, T44); + SET(a, b, c, d, 9, 4, T45); + SET(d, a, b, c, 12, 11, T46); + SET(c, d, a, b, 15, 16, T47); + SET(b, c, d, a, 2, 23, T48); +#undef SET + + /* Round 4. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ +#define I(x, y, z) ((y) ^ ((x) | ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + I(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 6, T49); + SET(d, a, b, c, 7, 10, T50); + SET(c, d, a, b, 14, 15, T51); + SET(b, c, d, a, 5, 21, T52); + SET(a, b, c, d, 12, 6, T53); + SET(d, a, b, c, 3, 10, T54); + SET(c, d, a, b, 10, 15, T55); + SET(b, c, d, a, 1, 21, T56); + SET(a, b, c, d, 8, 6, T57); + SET(d, a, b, c, 15, 10, T58); + SET(c, d, a, b, 6, 15, T59); + SET(b, c, d, a, 13, 21, T60); + SET(a, b, c, d, 4, 6, T61); + SET(d, a, b, c, 11, 10, T62); + SET(c, d, a, b, 2, 15, T63); + SET(b, c, d, a, 9, 21, T64); +#undef SET + + /* Then perform the following additions. (That is increment each + of the four registers by the value it had before this block + was started.) */ + pms->abcd[0] += a; + pms->abcd[1] += b; + pms->abcd[2] += c; + pms->abcd[3] += d; +} + +void +md5_init(md5_state_t *pms) +{ + pms->count[0] = pms->count[1] = 0; + pms->abcd[0] = 0x67452301; + pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; + pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; + pms->abcd[3] = 0x10325476; +} + +void +md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) +{ + const md5_byte_t *p = data; + int left = nbytes; + int offset = (pms->count[0] >> 3) & 63; + md5_word_t nbits = (md5_word_t)(nbytes << 3); + + if (nbytes <= 0) + return; + + /* Update the message length. */ + pms->count[1] += nbytes >> 29; + pms->count[0] += nbits; + if (pms->count[0] < nbits) + pms->count[1]++; + + /* Process an initial partial block. */ + if (offset) { + int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); + + memcpy(pms->buf + offset, p, copy); + if (offset + copy < 64) + return; + p += copy; + left -= copy; + md5_process(pms, pms->buf); + } + + /* Process full blocks. */ + for (; left >= 64; p += 64, left -= 64) + md5_process(pms, p); + + /* Process a final partial block. */ + if (left) + memcpy(pms->buf, p, left); +} + +void +md5_finish(md5_state_t *pms, md5_byte_t digest[16]) +{ + static const md5_byte_t pad[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + md5_byte_t data[8]; + int i; + + /* Save the length before padding. */ + for (i = 0; i < 8; ++i) + data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); + /* Pad to 56 bytes mod 64. */ + md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); + /* Append the length. */ + md5_append(pms, data, 8); + for (i = 0; i < 16; ++i) + digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); +} diff --git a/tools/wrt350nv2-builder/src/md5.h b/tools/wrt350nv2-builder/src/md5.h new file mode 100644 index 00000000000..698c995d8f4 --- /dev/null +++ b/tools/wrt350nv2-builder/src/md5.h @@ -0,0 +1,91 @@ +/* + Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.h is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Removed support for non-ANSI compilers; removed + references to Ghostscript; clarified derivation from RFC 1321; + now handles byte order either statically or dynamically. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); + added conditionalization for C++ compilation from Martin + Purschke . + 1999-05-03 lpd Original version. + */ + +#ifndef md5_INCLUDED +# define md5_INCLUDED + +/* + * This package supports both compile-time and run-time determination of CPU + * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be + * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is + * defined as non-zero, the code will be compiled to run only on big-endian + * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to + * run on either big- or little-endian CPUs, but will run slightly less + * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. + */ + +typedef unsigned char md5_byte_t; /* 8-bit byte */ +typedef unsigned int md5_word_t; /* 32-bit word */ + +/* Define the state of the MD5 Algorithm. */ +typedef struct md5_state_s { + md5_word_t count[2]; /* message length in bits, lsw first */ + md5_word_t abcd[4]; /* digest buffer */ + md5_byte_t buf[64]; /* accumulate block */ +} md5_state_t; + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Initialize the algorithm. */ +void md5_init(md5_state_t *pms); + +/* Append a string to the message. */ +void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); + +/* Finish the message and return the digest. */ +void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif /* md5_INCLUDED */ diff --git a/tools/wrt350nv2-builder/src/upgrade.h b/tools/wrt350nv2-builder/src/upgrade.h new file mode 100644 index 00000000000..2b5953acc8e --- /dev/null +++ b/tools/wrt350nv2-builder/src/upgrade.h @@ -0,0 +1,77 @@ +#ifndef _UPGRADE_H_ +#define _UPGRADE_H_ + +#define FLASH_END_ADDR 0xffffffff +#define FLASH_ADDR_BASE 0xff800000 +#define BOOT_ADDR_BASE 0xfffc0000 +#define BOOT_ADDR_BASE_OFF 0x7c0000 +#define FLASH_SIZE 0x800000 +#define BOOT_SIZE 0x40000 +//NVRAM in boot area +//#define NVRAM_ADDR_BASE 0xfff90000 +//#define NVRAM_ADDR_BASE_OFF 0x790000 +//#define NVRAM_SIZE 0x10000 + +#define PID_OFFSET (BOOT_SIZE- 0x46) +#define NODE_ADDRESS (BOOT_SIZE-0x60) +#define NODE_BASE_OFF (FLASH_SIZE-0x60) +#define PIN_ADDRESS (BOOT_SIZE-0x70)//WPS PIN,8bytes +#define PIN_OFF (FLASH_SIZE-0x70) +#define KERNEL_CODE_OFFSET 0 +#define SN_ADDRESS (BOOT_SIZE-0x80) //12bytes +#define SN_OFF (FLASH_SIZE-0x80) + + +#define UPGRADE_START_OFFSET 0 +#define UPGRADE_END_OFFSET 0x7A0000 +#define PRODUCT_ID_OFFSET 0x75ffe0//(UPGRADE_END_OFFSET - 0x10) +#define PROTOCOL_ID_OFFSET (PRODUCT_ID_OFFSET + 0x02) +#define FW_VERSION_OFFSET (PRODUCT_ID_OFFSET + 0x04) +#define SIGN_OFFSET (PRODUCT_ID_OFFSET + 0x08) /* eRcOmM */ + +//#define LANG_UPGRADE +#ifdef LANG_UPGRADE +#define LANGBUF_BEGIN 0x1300000 +#define LANGBUF_END 0x1f00000 +#define LANGBUF_LENTH (LANGBUF_END - LANGBUF_BEGIN) +#endif +#ifndef ERROR +#define ERROR -1 +#endif + +#ifndef OK +#define OK 0 +#endif + +#ifndef NULL +#define NULL 0 +#endif + + +void do_boot(void); +void Download(void); +void Assign(void); + +void gpio_init(void); +void Led_Power(int value); +void Led_security(int value); +int PushButton(void); + +static unsigned short xchg ( unsigned short dwData); +int FlashDriver(unsigned long dlAddress,unsigned char *dbData,unsigned long dlLength,unsigned long dlFlag); +int ProgramChip(unsigned long dlAddress,unsigned char * dbData,unsigned long dlLength); +int dl_Initialize(void); +void dl_GetAddr(unsigned char *node); +int dl_Receive(void); +int dl_Transmit(char *buf,int len); +void reset(void); +void AssignHWAddress(unsigned char *psBuffer); +int ResetChip(unsigned long ulRomDstAddr); +int GetFlashType(void); + +#ifdef LANG_UPGRADE +int save_lang_buf(unsigned long flash_addr, char *mem_addr,unsigned long length); +int LangDriver(unsigned long flash_addr, char *mem_addr,unsigned long length, unsigned long dlFlag); +#endif +#endif + diff --git a/tools/wrt350nv2-builder/src/wrt350nv2-builder.c b/tools/wrt350nv2-builder/src/wrt350nv2-builder.c new file mode 100644 index 00000000000..9bc00066bac --- /dev/null +++ b/tools/wrt350nv2-builder/src/wrt350nv2-builder.c @@ -0,0 +1,1044 @@ +/* + + WRT350Nv2-Builder 2.0 (previously called buildimg) + Copyright (C) 2008-2009 Dirk Teurlings + Copyright (C) 2009 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + A lot of thanks to Kaloz and juhosg from OpenWRT and Lennert Buytenhek from + marvell for helping me figure this one out. This code is based on bash + scripts wrote by Peter van Valderen so the real credit should go to him. + + This program reads the provided parameter file and creates an image which can + be used to flash a Linksys WRT350N v2 from stock firmware. + The trick is to fill unused space in the bin file with random, so that the + resulting zip file passes the size check of the stock firmware. + + The parameter file layout for an original Linksys firmware: + :kernel 0x001A0000 /path/to/uImage + :rootfs 0 /path/to/root.squashfs + :u-boot 0 /path/to/u-boot.bin + + args: + 1 wrt350nv2.par parameter file describing the image layout + 2 wrt350nv2.img output file for linksys style image + + An u-boot image inside the bin file is not necessary. + The version is not important. + The name of the bin file is not important. + + Linksys assumes that no mtd will be used to its maximum, so the last 16 bytes + of the mtd are abused to define the length of the next mtd content (4 bytes for + size + 12 pad bytes). + + At the end of "rootfs" additional 16 bytes are abused for some data and an + highly important eRcOmM identifier, so the last 32 bytes of "rootfs" are abused. + + At the end of "u-boot" 128 bytes are abused for some data, a checksum and an + highly important sErCoMm identifier. + + + This program uses a special GNU scanf modifier to allocate + sufficient memory for a strings with unknown length. + See http://www.kernel.org/doc/man-pages/online/pages/man3/scanf.3.html#NOTES + + + To extract everything from a Linksys style firmware image see + https://forum.openwrt.org/viewtopic.php?pid=92928#p92928 + +*/ + +// ToDo: +// * Has NODE to be added to bin file *after* creating checksum byte? + +// includes +#define _GNU_SOURCE // for GNU's basename() +#include +#include // errno +#include +#include // fopen(), fread(), fclose(), etc. +#include // system(), etc. +#include // basename(), strerror(), strdup(), etc. +#include // optopt(), access(), etc. +#include // WEXITSTATUS, etc. + +// custom includes +#include "md5.h" // MD5 routines +#include "upgrade.h" // Linksys definitions from firmware 2.0.19 + + +// version info +#define VERSION "2.0" +char program_info[] = "WRT350Nv2-Builder v%s by Dirk Teurlings and Matthias Buecher (http://www.maddes.net/)\n"; + +// verbosity +#define DEBUG 1 +#define DEBUG_LVL2 2 +int verbosity = 0; + +// mtd info +typedef struct { + char *name; + int offset; + int size; + char *filename; + long int filesize; + unsigned char magic[2]; +} mtd_info; + +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_uboot = { "u-boot", 0, 0, NULL, 0L, { 0, 0 } }; + +#define ROOTFS_END_OFFSET 0x00760000 +#define ROOTFS_MIN_OFFSET 0x00700000 // 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 + +// 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 rootfs_unknown[] = { 0x90, 0xF7 }; // seems to be a fixed value +unsigned char sign[] = { 0x65, 0x52, 0x63, 0x4F, 0x6D, 0x4D, 0x00, 0x00 }; // eRcOmM + +// u-boot statics via: hexdump -v -e '1/1 "0x%02X, "' -s 0x007FFF80 -n 128 "wrt350n.bin" ; echo -en "\n" +//unsigned char sn[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // (12) seems to be an unused value +//unsigned char pin[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // (8) seems to be an unused value +//unsigned char node[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // (25) seems to be an unused value +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +//unsigned char checksum[] = { 0xE9 }; // (1) is calculated, does it belong to node? +unsigned char pid[] = { 0x73, 0x45, 0x72, 0x43, 0x6F, 0x4D, 0x6D, 0x00, 0x01, 0x00, 0x00, 0x59, 0x42, 0x50, 0x00, 0x01, // (70) seems to be a fixed value, except for fw version + 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, // protocol id? + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, // protocol id? + 0x12, 0x34, // firmware version, same as in rootfs + 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" +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, + 0x00, 0x00, + 0x12, 0x34, // firmware version, same as in rootfs + 0x00, 0x00, 0x00, 0x04, 0x61, 0x44, 0x6D, 0x42, 0x6C, 0x4B, 0x3D, 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, 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, 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, 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, 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, + 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, 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, 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, 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, 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, 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, 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, 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, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, // md5 checksum + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +unsigned char img_eof[] = { 0xFF }; + + +void lprintf(int outputlevel, char *fmt, ...) { + va_list argp; + if (outputlevel <= verbosity) { + va_start(argp, fmt); + vprintf(fmt, argp); + va_end(argp); + } +} + + +int parse_par_file(FILE *f_par) { + int exitcode = 0; + + char *buffer; + size_t buffer_size; + char *line; + + int lineno; + int count; + + char *string1; + char *string2; + int value; + + mtd_info *mtd; + FILE *f_in; + int f_exitcode = 0; + + // read all lines + buffer_size = 1000; + buffer = NULL; + lineno = 0; + while (!feof(f_par)) { + // read next line into memory + do { + // allocate memory for input line + if (buffer == NULL) { + buffer = malloc(buffer_size); + } + if (buffer == NULL) { + exitcode = 1; + printf("parse_par_file: can not allocate %i bytes\n", buffer_size); + break; + } + + line = fgets(buffer, buffer_size, f_par); + if (line == NULL) { + exitcode = ferror(f_par); + if (exitcode) { + printf("parse_par_file: %s\n", strerror(exitcode)); + } + break; + } + + // if buffer was not completely filled, then assume that line is complete + count = strlen(buffer) + 1; + if (count-- < buffer_size) { + break; + } + + // otherwise.... + + // reset file position to line start + value = fseek(f_par, -count, SEEK_CUR); + if (value == -1) { + exitcode = errno; + printf("parse_par_file: %s\n", strerror(exitcode)); + break; + } + + // double buffer size + free(buffer); + buffer = NULL; + buffer_size *= 2; + lprintf(DEBUG_LVL2, " extending buffer to %i bytes\n", buffer_size); + } while (1); + if (line == NULL || exitcode) { + break; + } + + lineno++; // increase line number + + lprintf(DEBUG_LVL2, " line %i (%i) %s", lineno, count, line); + + string1 = NULL; + string2 = NULL; + value = 0; + mtd = NULL; + + // split line if starting with a colon + switch (line[0]) { + case ':': + count = sscanf(line, ":%ms %i %ms", &string1, &value, &string2); + if (count != 3) { + printf("line %i does not meet defined format (: )\n", lineno); + } else { + // populate mtd_info if supported mtd names + if (strcmp(string1, mtd_kernel.name) == 0) { + mtd = &mtd_kernel; + } else if (strcmp(string1, mtd_rootfs.name) == 0) { + mtd = &mtd_rootfs; + } else if (strcmp(string1, mtd_uboot.name) == 0) { + mtd = &mtd_uboot; + } + + if (mtd == NULL) { + printf("unknown mtd %s in line %i\n", string1, lineno); + } else if (mtd->filename != NULL) { + f_exitcode = 1; + printf("mtd %s in line %i multiple definitions\n", string1, lineno); + } else { + mtd->size = value; + mtd->filename = string2; + string2 = NULL; // do not free + + // Get file size + f_in = fopen(mtd->filename, "rb"); + if (f_in == NULL) { + f_exitcode = errno; + printf("input file %s: %s\n", mtd->filename, strerror(f_exitcode)); + } else { + value = fread(&mtd->magic, 1, 2, f_in); + if (value < 2) { + if (ferror(f_in)) { + f_exitcode = ferror(f_in); + printf("input file %s: %s\n", mtd->filename, strerror(f_exitcode)); + } else { + f_exitcode = 1; + printf("input file %s: smaller than two bytes, no magic code\n", mtd->filename); + } + } + + value = fseek(f_in, 0, SEEK_END); + if (value == -1) { + f_exitcode = errno; + printf("input file %s: %s\n", mtd->filename, strerror(f_exitcode)); + } else { + mtd->filesize = ftell(f_in); + if (mtd->filesize == -1) { + f_exitcode = errno; + printf("input file %s: %s\n", mtd->filename, strerror(f_exitcode)); + } + } + + fclose(f_in); + } + + lprintf(DEBUG, "mtd %s in line %i: size=0x%08X, filesize=0x%08lX, magic=0x%02X%02X, file=%s\n", mtd->name, lineno, mtd->size, mtd->filesize, mtd->magic[0], mtd->magic[1], mtd->filename); + } + } + break; + case '#': // integer values + count = sscanf(line, "#%ms %i", &string1, &value); + if (count != 2) { + printf("line %i does not meet defined format (: \n", lineno); + } else { + if (strcmp(string1, "version") == 0) { + // changing version + fw_version[0] = 0x000000FF & ( value >> 8 ); + fw_version[1] = 0x000000FF & value; + } else { + printf("unknown integer variable %s in line %i\n", string1, lineno); + } + + lprintf(DEBUG, "integer variable %s in line %i: 0x%08X\n", string1, lineno, value); + } + break; + case '$': // strings + count = sscanf(line, "$%ms %ms", &string1, &string2); + if (count != 2) { + printf("line %i does not meet defined format (: )\n", lineno); + } else { +/* + if (strcmp(string1, "something") == 0) { + something = string2; + string2 = NULL; // do not free + } else { +*/ + printf("unknown string variable %s in line %i\n", string1, lineno); +// } + lprintf(DEBUG, "string variable %s in line %i: %s\n", string1, lineno, string2); + } + break; + default: + break; + } + + if (string1) { + free(string1); + } + if (string2) { + free(string2); + } + } + free(buffer); + + if (!exitcode) { + exitcode = f_exitcode; + } + + return exitcode; +} + + +int create_bin_file(char *bin_filename) { + int exitcode = 0; + + unsigned char *buffer; + + int i; + mtd_info *mtd; + int addsize; + int padsize; + + char *rand_filename = "/dev/urandom"; + FILE *f_in; + int size; + + unsigned long int csum; + unsigned char checksum; + + FILE *f_out; + + // allocate memory for bin file + buffer = malloc(KERNEL_CODE_OFFSET + FLASH_SIZE); + if (buffer == NULL) { + exitcode = 1; + printf("create_bin_file: can not allocate %i bytes\n", FLASH_SIZE); + } else { + // initialize with zero + memset(buffer, 0, KERNEL_CODE_OFFSET + FLASH_SIZE); + } + + // add files + if (!exitcode) { + for (i = 1; i <= 3; i++) { + addsize = 0; + padsize = 0; + + switch (i) { + case 1: + mtd = &mtd_kernel; + break; + case 2: + mtd = &mtd_rootfs; + addsize = mtd->filesize; + padsize = ROOTFS_MIN_OFFSET - mtd_kernel.size - mtd->filesize; + break; + case 3: + mtd = &mtd_uboot; + addsize = mtd->filesize; + break; + default: + mtd = NULL; + exitcode = 1; + printf("create_bin_file: unknown mtd %i\n", i); + break; + } + if (mtd == NULL) { + break; + } + if (mtd->filename == NULL) { + continue; + } + + lprintf(DEBUG, "adding mtd %s file %s\n", mtd->name, mtd->filename); + + // adding file size + if (addsize) { + buffer[KERNEL_CODE_OFFSET + mtd->offset - 16] = 0x000000FFL & ( addsize >> 24 ); + buffer[KERNEL_CODE_OFFSET + mtd->offset - 15] = 0x000000FFL & ( addsize >> 16 ); + buffer[KERNEL_CODE_OFFSET + mtd->offset - 14] = 0x000000FFL & ( addsize >> 8 ); + buffer[KERNEL_CODE_OFFSET + mtd->offset - 13] = 0x000000FFL & addsize; + } + + // adding file content + f_in = fopen(mtd->filename, "rb"); + if (f_in == NULL) { + exitcode = errno; + printf("input file %s: %s\n", mtd->filename, strerror(exitcode)); + } else { + size = fread(&buffer[KERNEL_CODE_OFFSET + mtd->offset], mtd->filesize, 1, f_in); + if (size < 1) { + if (ferror(f_in)) { + exitcode = ferror(f_in); + printf("input file %s: %s\n", mtd->filename, strerror(exitcode)); + } else { + exitcode = 1; + printf("input file %s: smaller than before *doh*\n", mtd->filename); + } + } + fclose(f_in); + } + + // 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; + addsize += KERNEL_CODE_OFFSET + mtd->offset + mtd->filesize; // get offset + lprintf(DEBUG, " padding offset 0x%08X length 0x%08X\n", addsize, padsize); + + f_in = fopen(rand_filename, "rb"); + if (f_in == NULL) { + exitcode = errno; + printf("input file %s: %s\n", rand_filename, strerror(exitcode)); + } else { + size = fread(&buffer[addsize], padsize, 1, f_in); + if (size < 1) { + if (ferror(f_in)) { + exitcode = ferror(f_in); + printf("input file %s: %s\n", rand_filename, strerror(exitcode)); + } else { + exitcode = 1; + printf("input file %s: smaller than before *doh*\n", rand_filename); + } + } + } + fclose(f_in); + } + } + } + + // add special contents + if (!exitcode) { + lprintf(DEBUG, "adding rootfs special data\n"); + memcpy(&buffer[KERNEL_CODE_OFFSET + PRODUCT_ID_OFFSET], product_id, 2); + memcpy(&buffer[KERNEL_CODE_OFFSET + PROTOCOL_ID_OFFSET], protocol_id, 2); + memcpy(&buffer[KERNEL_CODE_OFFSET + FW_VERSION_OFFSET], fw_version, 2); + 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 checksum byte\n"); + csum = 0; + for (i = 0; i < KERNEL_CODE_OFFSET + FLASH_SIZE; i++) { + csum += buffer[i]; + } + lprintf(DEBUG_LVL2, " checksum 0x%016lX (%li)\n", csum, csum); + + buffer[KERNEL_CODE_OFFSET + NODE_BASE_OFF + 25] = ~(csum+108)+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 + if (!exitcode) { + lprintf(DEBUG, "writing file %s\n", bin_filename); + f_out = fopen(bin_filename, "wb"); + if (f_out == NULL) { + exitcode = errno; + printf("output file %s: %s\n", bin_filename, strerror(exitcode)); + } else { + size = fwrite(buffer, KERNEL_CODE_OFFSET + FLASH_SIZE, 1, f_out); + if (size < 1) { + if (ferror(f_out)) { + exitcode = ferror(f_out); + printf("output file %s: %s\n", bin_filename, strerror(exitcode)); + } else { + exitcode = 1; + printf("output file %s: unspecified write error\n", bin_filename); + } + } + fclose(f_out); + } + } + + return exitcode; +} + + +int create_zip_file(char *zip_filename, char *bin_filename) { + int exitcode = 0; + + char *buffer; + size_t buffer_size; + int count; + + buffer_size = 1000; + buffer = NULL; + do { + // allocate memory for command line + if (buffer == NULL) { + buffer = malloc(buffer_size); + } + if (buffer == NULL) { + exitcode = 1; + printf("create_zip_file: can not allocate %i bytes\n", buffer_size); + break; + } + + // if buffer was not completely filled, then line fit in completely + count = snprintf(buffer, buffer_size, "zip %s %s", zip_filename, bin_filename); + if (count > -1 && count < buffer_size) { + break; + } + + // otherwise try again with more space + if (count > -1) { // glibc 2.1 + buffer_size = count + 1; // precisely what is needed + } else { // glibc 2.0 + buffer_size *= 2; // twice the old size + } + free(buffer); + buffer = NULL; + lprintf(DEBUG_LVL2, " extending buffer to %i bytes\n", buffer_size); + } while (1); + + if (!exitcode) { + // zipping binfile + lprintf(DEBUG, "%s\n", buffer); + count = system(buffer); + if (count < 0 || WEXITSTATUS(count)) { + exitcode = 1; + printf("create_zip_file: can not execute %s bytes\n", buffer); + } + } + + return exitcode; +} + + +int create_img_file(FILE *f_out, char *out_filename, char *zip_filename) { + int exitcode = 0; + + md5_state_t state; + md5_byte_t digest[16]; + + int i; + int size; + + FILE *f_in; + unsigned char buffer[1]; + + // copy firmware version + memcpy(&img_hdr[50], fw_version, 2); + + // clear md5 checksum + memset(&img_hdr[480], 0, 16); + + // prepare md5 checksum calculation + md5_init(&state); + + // add img header + lprintf(DEBUG_LVL2, " adding img header\n"); + for (i = 0; i < 512; i++) { + size = fputc(img_hdr[i], f_out); + if (size == EOF) { + exitcode = ferror(f_out); + printf("output file %s: %s\n", out_filename, strerror(exitcode)); + break; + } + md5_append(&state, (const md5_byte_t *)&img_hdr[i], 1); + } + + // adding zip file + if (!exitcode) { + lprintf(DEBUG_LVL2, " adding zip file\n"); + f_in = fopen(zip_filename, "rb"); + if (f_in == NULL) { + exitcode = errno; + printf("input file %s: %s\n", zip_filename, strerror(exitcode)); + } else { + while ((size = fgetc(f_in)) != EOF) { + buffer[0] = size; + + size = fputc(buffer[0], f_out); + if (size == EOF) { + exitcode = ferror(f_out); + printf("output file %s: %s\n", out_filename, strerror(exitcode)); + break; + } + md5_append(&state, (const md5_byte_t *)buffer, 1); + } + if (ferror(f_in)) { + exitcode = ferror(f_in); + printf("input file %s: %s\n", zip_filename, strerror(exitcode)); + } + } + + } + + // add end byte + if (!exitcode) { + lprintf(DEBUG_LVL2, " adding img eof byte\n"); + size = fputc(img_eof[0], f_out); + if (size == EOF) { + exitcode = ferror(f_out); + printf("output file %s: %s\n", out_filename, strerror(exitcode)); + } + md5_append(&state, (const md5_byte_t *)img_eof, 1); + } + + // append salt to md5 checksum + md5_append(&state, (const md5_byte_t *)"A^gU*<>?RFY@#DR&Z", 17); + + // finish md5 checksum calculation + md5_finish(&state, digest); + + // write md5 checksum into img header + if (!exitcode) { + lprintf(DEBUG_LVL2, " writing md5 checksum into img header of file\n"); + + size = fseek(f_out, 480, SEEK_SET); + if (size == -1) { + exitcode = errno; + printf("output file %s: %s\n", out_filename, strerror(exitcode)); + } else { + size = fwrite(digest, 16, 1, f_out); + if (size < 1) { + if (ferror(f_out)) { + exitcode = ferror(f_out); + printf("output file %s: %s\n", out_filename, strerror(exitcode)); + } else { + exitcode = 1; + printf("output file %s: unspecified write error\n", out_filename); + } + } + } + + fclose(f_in); + } + + return exitcode; +} + + +int main(int argc, char *argv[]) { + int exitcode = 0; + + int help; + int havezip; + char option; + char *par_filename = NULL; + char *out_filename = NULL; + char *base_filename = NULL; + char *bin_filename = NULL; + char *zip_filename = NULL; + + FILE *f_par; + FILE *f_out; + + int i; + mtd_info *mtd; + int mandatory; + int noupdate; + int sizecheck; + unsigned char magic[2]; + + +// display program header + printf(program_info, VERSION); + + +// command line processing + // options + help = 0; + havezip = 0; + while ((option = getopt(argc, argv, ":hzf:v")) != -1) { + switch(option) { + case 'h': + help = 1; + break; + case 'z': + havezip = 1; + break; + case 'f': + sizecheck = sscanf(optarg, "%i", &i); + if (sizecheck != 1) { + printf("firmware version of -f option not a valid integer\n"); + exitcode = 1; + } else { + fw_version[0] = 0x000000FF & ( i >> 8 ); + fw_version[1] = 0x000000FF & i; + } + break; + case 'v': + verbosity++; + break; + case ':': // option with missing operand + printf("Option -%c requires an operand\n", optopt); + exitcode = 1; + break; + case '?': + printf("Unrecognized option: -%c\n", optopt); + exitcode = 1; + break; + } + } + + // files + for ( ; optind < argc; optind++) { + if (par_filename == NULL) { + par_filename = argv[optind]; + + if (access(par_filename, R_OK)) { + if (havezip) { + printf("No read access to zip file %s\n", par_filename); + } else { + printf("No read access to parameter or zip file %s\n", par_filename); + } + exitcode = 1; + } + + continue; + } + + if (out_filename == NULL) { + out_filename = argv[optind]; + + if (!access(out_filename, F_OK)) { // if file already exists then check write access + if (access(out_filename, W_OK)) { + printf("No write access to output file %s\n", out_filename); + exitcode = 1; + } + } + + continue; + } + + printf("Too many files stated\n"); + exitcode = 1; + break; + } + + // file name checks + if (par_filename == NULL) { + if (havezip) { + printf("Zip file not stated\n"); + } else { + printf("Parameter file not stated\n"); + } + exitcode = 1; + } else { + base_filename = basename(par_filename); + if (base_filename == NULL) { + if (havezip) { + printf("Zip file is a directory\n"); + } else { + printf("Parameter file is a directory\n"); + } + exitcode = 1; + } + } + + if (out_filename == NULL) { + printf("Output file not stated\n"); + exitcode = 1; + } else { + base_filename = basename(out_filename); + if (base_filename == NULL) { + printf("Output file is a directory\n"); + exitcode = 1; + } else { + base_filename = strdup(base_filename); + zip_filename = strrchr(base_filename, '.'); + if (zip_filename != NULL) { + zip_filename[0] = 0; + zip_filename = NULL; // clean up + } + } + } + + // react on parameter problems or help request, and exit + if ((exitcode != 0) || help) { + if (help) { + printf("This program creates Linksys style images for the WRT350Nv2 router.\n"); + } + printf(" Usage:\n\ + %s [-h] [-z] [-f ] [-v] \n\n\ + Options:\n\ + -h - Show this help\n\ + -z - Have zip file, the img file will be directly created from it\n\ + -f - Wanted firmware version to use with -z\n\ + Default firmware version is 0x2019 = 2.00.19.\n\ + Note: version from parameter file will supersede this\n\ + -v - Increase debug verbosity level\n\n\ + Example:\n\ + %s wrt350nv2.par wrt350nv2.img\n\n", argv[0], argv[0]); + return exitcode; + } + + // handle special case when zipfile is stated + if (havezip) { + zip_filename = par_filename; + par_filename = NULL; + } + + lprintf(DEBUG_LVL2, " verbosity: %i\n", verbosity); + lprintf(DEBUG_LVL2, " program: %s\n", argv[0]); + + lprintf(DEBUG, "Parameter file: %s\n", par_filename); + lprintf(DEBUG, "Output file: %s\n", out_filename); + lprintf(DEBUG_LVL2, " basename: %s (%i)\n", base_filename, strlen(base_filename)); + + +// open files from command line + // parameter file + if (par_filename != NULL) { + f_par = fopen(par_filename, "r"); + if (f_par == NULL) { + exitcode = errno; + printf("input file %s: %s\n", par_filename, strerror(exitcode)); + } + } + + // output file + f_out = fopen(out_filename, "w"); + if (f_out == NULL) { + exitcode = errno; + printf("Output file %s: %s\n", out_filename, strerror(exitcode)); + } + + if (exitcode) { + return exitcode; + } + + +// parameter file processing + if (!exitcode && par_filename != NULL) { + lprintf(DEBUG, "parsing parameter file...\n"); + + exitcode = parse_par_file(f_par); + + lprintf(DEBUG, "...done parsing file\n"); + } + if (par_filename != NULL) { + fclose(f_par); + } + + +// check all input data + if (!exitcode && par_filename != NULL) { + lprintf(DEBUG, "checking mtd data...\n"); + + for (i = 1; i <= 3; i++) { + mandatory = 0; + noupdate = 0; + sizecheck = 0; + magic[0] = 0; + magic[1] = 0; + + switch (i) { + case 1: + mtd = &mtd_kernel; + mandatory = 1; + sizecheck = mtd_kernel.size - 16; + magic[0] = 0x27; + magic[1] = 0x05; + break; + case 2: + 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; + break; + case 3: + mtd = &mtd_uboot; + mtd->offset = BOOT_ADDR_BASE_OFF; + noupdate = 1; + sizecheck = SN_OFF - BOOT_ADDR_BASE_OFF; + break; + default: + mtd = NULL; + exitcode = 1; + printf("unknown mtd check %i\n", i); + break; + } + if (mtd == NULL) { + break; + } + + lprintf(DEBUG_LVL2, " checking mtd %s\n", mtd->name); + + // general checks + if (mandatory && mtd->filename == NULL) { + exitcode = 1; + printf("mtd %s not specified correctly or at all in parameter file\n", mtd->name); + } + + // end checks if no file data present + if (mtd->filename == NULL) { + continue; + } + + // not updated by stock firmware + if (noupdate) { + printf("mtd %s is specified, but will not be updated as of Linksys firmware 2.0.19\n", mtd->name); + } + + // 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]); + } + } + + // mtd specific size check + if (mtd == &mtd_kernel) { + if (mtd->filesize < 0x00050000) { + exitcode = 1; + printf("mtd %s input file %s too unrealistic small (0x%08lX)\n", mtd->name, mtd->filesize); + } + } + + // general size check + if (sizecheck) { + if (sizecheck <= 0) { + exitcode = 1; + printf("mtd %s bad file size check (%i) due to input data\n", mtd->name, sizecheck); + } else { + if (mtd->filesize > sizecheck) { + exitcode = 1; + printf("mtd %s input file %s too big (0x%08lX)\n", mtd->name, mtd->filename, mtd->filesize); + } + } + } + } + lprintf(DEBUG, "...done checking mtd data\n"); + } + + +// bin creation in memory + if (!exitcode && par_filename != NULL) { + // create bin name from basename + bin_filename = malloc(strlen(base_filename)+10); + sprintf(bin_filename, "%s.bin", base_filename); + + lprintf(DEBUG, "creating bin file %s...\n", bin_filename); + + exitcode = create_bin_file(bin_filename); + + lprintf(DEBUG, "...done creating bin file\n"); + } + + +// zip file creation + if (!exitcode && zip_filename == NULL) { + // create zip name from basename + zip_filename = malloc(strlen(base_filename)+10); + sprintf(zip_filename, "%s.zip", base_filename); + + lprintf(DEBUG, "creating zip file %s...\n", zip_filename); + + exitcode = create_zip_file(zip_filename, bin_filename); + + lprintf(DEBUG, "...done creating zip file\n"); + } + + +// img file creation + if (!exitcode) { + lprintf(DEBUG, "creating img file...\n"); + + exitcode = create_img_file(f_out, out_filename, zip_filename); + + lprintf(DEBUG, "...done creating img file\n"); + } + fclose(f_out); + + +// end program + return exitcode; +}