add wrt350n v2 image building code from #5970 (thx, maddes)
authorFelix Fietkau <nbd@openwrt.org>
Sat, 12 Dec 2009 00:44:03 +0000 (00:44 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Sat, 12 Dec 2009 00:44:03 +0000 (00:44 +0000)
SVN-Revision: 18761

tools/Makefile
tools/wrt350nv2-builder/Makefile [new file with mode: 0644]
tools/wrt350nv2-builder/src/crypt.h [new file with mode: 0644]
tools/wrt350nv2-builder/src/ioapi.c [new file with mode: 0644]
tools/wrt350nv2-builder/src/ioapi.h [new file with mode: 0644]
tools/wrt350nv2-builder/src/md5.c [new file with mode: 0644]
tools/wrt350nv2-builder/src/md5.h [new file with mode: 0644]
tools/wrt350nv2-builder/src/upgrade.h [new file with mode: 0644]
tools/wrt350nv2-builder/src/wrt350nv2-builder.c [new file with mode: 0644]

index f5be9bb..272c625 100644 (file)
@@ -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 (file)
index 0000000..648dd84
--- /dev/null
@@ -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 (file)
index 0000000..622f4bc
--- /dev/null
@@ -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<RAND_HEAD_LEN)
+      return 0;
+
+    /* First generate RAND_HEAD_LEN-2 random bytes. We encrypt the
+     * output of rand() to get less predictability, since rand() is
+     * often poorly implemented.
+     */
+    if (++calls == 1)
+    {
+        srand((unsigned)(time(NULL) ^ ZCR_SEED2));
+    }
+    init_keys(passwd, pkeys, pcrc_32_tab);
+    for (n = 0; n < RAND_HEAD_LEN-2; n++)
+    {
+        c = (rand() >> 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 (file)
index 0000000..f1bee23
--- /dev/null
@@ -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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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 (file)
index 0000000..7d457ba
--- /dev/null
@@ -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 (file)
index 0000000..c35d96c
--- /dev/null
@@ -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
+  <ghost@aladdin.com>.  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 <string.h>
+       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 <stdio.h> 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 <string.h>
+
+#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 (file)
index 0000000..698c995
--- /dev/null
@@ -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
+  <ghost@aladdin.com>.  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 <purschke@bnl.gov>.
+  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 (file)
index 0000000..2b5953a
--- /dev/null
@@ -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 (file)
index 0000000..9bc0006
--- /dev/null
@@ -0,0 +1,1044 @@
+/*
+
+       WRT350Nv2-Builder 2.0 (previously called buildimg)
+       Copyright (C) 2008-2009 Dirk Teurlings <info@upexia.nl>
+       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 <assert.h>
+#include <errno.h>     // errno
+#include <stdarg.h>
+#include <stdio.h>     // fopen(), fread(), fclose(), etc.
+#include <stdlib.h>    // system(), etc.
+#include <string.h>    // basename(), strerror(), strdup(), etc.
+#include <unistd.h>    // optopt(), access(), etc.
+#include <sys/wait.h>  // 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 <info@upexia.nl> 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 (:<mtdname> <mtdsize> <file>)\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 (:<variable name> <integer>\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 (:<mtdname> <mtdsize> <file>)\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 <version>] [-v] <parameter or zip file> <output file>\n\n\
+  Options:\n\
+  -h            -  Show this help\n\
+  -z            -  Have zip file, the img file will be directly created from it\n\
+  -f <version>  -  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;
+}