added firmware-utils
authorRISCi_ATOM <bob@bobcall.me>
Sun, 19 Apr 2015 23:49:51 +0000 (23:49 +0000)
committerRISCi_ATOM <bob@bobcall.me>
Sun, 19 Apr 2015 23:49:51 +0000 (23:49 +0000)
78 files changed:
trunk/tools/Makefile
trunk/tools/firmware-utils/Makefile [new file with mode: 0644]
trunk/tools/firmware-utils/src/add_header.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/addpattern.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/airlink.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/bcm_tag.h [new file with mode: 0644]
trunk/tools/firmware-utils/src/bcmalgo.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/bcmalgo.h [new file with mode: 0644]
trunk/tools/firmware-utils/src/buffalo-enc.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/buffalo-lib.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/buffalo-lib.h [new file with mode: 0644]
trunk/tools/firmware-utils/src/buffalo-tag.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/buffalo-tftp.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/csysimg.h [new file with mode: 0644]
trunk/tools/firmware-utils/src/cyg_crc.h [new file with mode: 0644]
trunk/tools/firmware-utils/src/cyg_crc16.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/cyg_crc32.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/dgfirmware.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/dgn3500sum.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/edimax_fw_header.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/encode_crc.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/fix-u-media-header.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/fw.h [new file with mode: 0644]
trunk/tools/firmware-utils/src/hcsmakeimage.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/imagetag.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/imagetag.ggo [new file with mode: 0644]
trunk/tools/firmware-utils/src/imagetag_cmdline.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/imagetag_cmdline.h [new file with mode: 0644]
trunk/tools/firmware-utils/src/lzma2eva.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/makeamitbin.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/md5.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/md5.h [new file with mode: 0644]
trunk/tools/firmware-utils/src/mkbrncmdline.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/mkbrnimg.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/mkcameofw.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/mkcasfw.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/mkchkimg.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/mkcsysimg.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/mkdapimg.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/mkdcs932.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/mkdniimg.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/mkedimaximg.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/mkfwimage.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/mkfwimage2.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/mkheader_gemtek.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/mkhilinkfw.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/mkmylofw.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/mkplanexfw.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/mkporayfw.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/mkrtn56uimg.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/mksenaofw.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/mktitanimg.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/mktitanimg.h [new file with mode: 0644]
trunk/tools/firmware-utils/src/mktplinkfw.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/mktplinkfw2.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/mkwrgimg.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/mkzcfw.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/mkzynfw.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/motorola-bin.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/myloader.h [new file with mode: 0644]
trunk/tools/firmware-utils/src/nand_ecc.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/osbridge-crc.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/pc1crypt.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/ptgen.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/seama.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/seama.h [new file with mode: 0644]
trunk/tools/firmware-utils/src/sha1.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/sha1.h [new file with mode: 0644]
trunk/tools/firmware-utils/src/spw303v.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/srec2bin.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/tplink-safeloader.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/trx.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/trx2edips.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/trx2usr.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/wrt400n.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/xorimage.c [new file with mode: 0644]
trunk/tools/firmware-utils/src/zynos.h [new file with mode: 0644]
trunk/tools/firmware-utils/src/zyxbcm.c [new file with mode: 0644]

index 563ce88cc8636adfe5bba016ea87a27419e866ea..558c8671a9a5bf80243df2f6d945a0f2cbd6c77c 100644 (file)
@@ -23,7 +23,7 @@ endif
 tools-$(BUILD_TOOLCHAIN) += gmp mpfr mpc libelf
 tools-y += m4 libtool autoconf automake flex bison pkg-config sed mklibs
 tools-y += sstrip genext2fs e2fsprogs mtd-utils mkimage
-tools-y += patch-image patch quilt yaffs2 flock padjffs2
+tools-y += firmware-utils patch-image patch quilt yaffs2 flock padjffs2
 tools-y += mm-macros missing-macros xz cmake scons bc findutils gengetopt patchelf
 tools-$(CONFIG_TARGET_orion_generic) += wrt350nv2-builder upslug2
 tools-$(CONFIG_powerpc) += upx
diff --git a/trunk/tools/firmware-utils/Makefile b/trunk/tools/firmware-utils/Makefile
new file mode 100644 (file)
index 0000000..951d4dc
--- /dev/null
@@ -0,0 +1,81 @@
+#
+# Copyright (C) 2006-2012 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 := firmware-utils
+
+include $(INCLUDE_DIR)/host-build.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+define cc
+       $(HOSTCC) $(HOST_CFLAGS) -include endian.h $(HOST_LDFLAGS) -o $(HOST_BUILD_DIR)/bin/$(firstword $(1)) $(foreach src,$(1),src/$(src).c) $(2)
+endef
+
+define Host/Compile
+       mkdir -p $(HOST_BUILD_DIR)/bin
+       $(call cc,addpattern)
+       $(call cc,trx)
+       $(call cc,motorola-bin)
+       $(call cc,dgfirmware)
+       $(call cc,mksenaofw md5)
+       $(call cc,trx2usr)
+       $(call cc,ptgen)
+       $(call cc,airlink)
+       $(call cc,srec2bin)
+       $(call cc,mkmylofw)
+       $(call cc,mkcsysimg)
+       $(call cc,mkzynfw)
+       $(call cc,lzma2eva,-lz)
+       $(call cc,mkcasfw)
+       $(call cc,mkfwimage,-lz)
+       $(call cc,mkfwimage2,-lz)
+       $(call cc,imagetag imagetag_cmdline cyg_crc32)
+       $(call cc,add_header)
+       $(call cc,makeamitbin)
+       $(call cc,encode_crc)
+       $(call cc,nand_ecc)
+       $(call cc,mkplanexfw sha1)
+       $(call cc,mktplinkfw md5)
+       $(call cc,mktplinkfw2 md5)
+       $(call cc,tplink-safeloader md5, -Wall)
+       $(call cc,pc1crypt)
+       $(call cc,osbridge-crc)
+       $(call cc,wrt400n cyg_crc32)
+       $(call cc,mkdniimg)
+       $(call cc,mktitanimg)
+       $(call cc,mkchkimg)
+       $(call cc,mkzcfw cyg_crc32)
+       $(call cc,spw303v)
+       $(call cc,zyxbcm)
+       $(call cc,trx2edips)
+       $(call cc,xorimage)
+       $(call cc,buffalo-enc buffalo-lib, -Wall)
+       $(call cc,buffalo-tag buffalo-lib, -Wall)
+       $(call cc,buffalo-tftp buffalo-lib, -Wall)
+       $(call cc,mkwrgimg md5, -Wall)
+       $(call cc,mkedimaximg)
+       $(call cc,mkbrncmdline)
+       $(call cc,mkbrnimg)
+       $(call cc,mkdapimg)
+       $(call cc, mkcameofw, -Wall)
+       $(call cc,seama md5)
+       $(call cc,fix-u-media-header cyg_crc32,-Wall)
+       $(call cc,hcsmakeimage bcmalgo)
+       $(call cc,mkporayfw, -Wall)
+       $(call cc,mkhilinkfw, -lcrypto)
+       $(call cc,mkdcs932, -Wall)
+       $(call cc,mkheader_gemtek,-lz)
+       $(call cc,mkrtn56uimg, -lz)
+       $(call cc,dgn3500sum)
+       $(call cc,edimax_fw_header, -Wall)
+endef
+
+define Host/Install
+       $(INSTALL_BIN) $(HOST_BUILD_DIR)/bin/* $(STAGING_DIR_HOST)/bin/
+endef
+
+$(eval $(call HostBuild))
diff --git a/trunk/tools/firmware-utils/src/add_header.c b/trunk/tools/firmware-utils/src/add_header.c
new file mode 100644 (file)
index 0000000..6ad1527
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * add_header.c - partially based on libreCMC's motorola-bin.c
+ *
+ * Copyright (C) 2008 Imre Kaloz  <kaloz@openwrt.org>
+ *                    Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License,
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+/*
+ * The add_header utility used by various vendors preprends the buf
+ * image with a header containing a CRC32 value which is generated for the
+ * model id + reserved space for CRC32 + buf, then replaces the reserved
+ * area with the actual CRC32. This replacement tool mimics this behavior.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <inttypes.h>
+
+#define BPB 8 /* bits/byte */
+
+static uint32_t crc32[1<<BPB];
+
+static void init_crc32()
+{
+       const uint32_t poly = ntohl(0x2083b8ed);
+       int n;
+
+       for (n = 0; n < 1<<BPB; n++) {
+               uint32_t crc = n;
+               int bit;
+
+               for (bit = 0; bit < BPB; bit++)
+                       crc = (crc & 1) ? (poly ^ (crc >> 1)) : (crc >> 1);
+               crc32[n] = crc;
+       }
+}
+
+static uint32_t crc32buf(unsigned char *buf, size_t len)
+{
+       uint32_t crc = 0xFFFFFFFF;
+
+       for (; len; len--, buf++)
+               crc = crc32[(uint8_t)crc ^ *buf] ^ (crc >> BPB);
+       return ~crc;
+}
+
+struct header {
+       unsigned char model[16];
+       uint32_t crc;
+};
+
+static void usage(const char *) __attribute__ (( __noreturn__ ));
+
+static void usage(const char *mess)
+{
+       fprintf(stderr, "Error: %s\n", mess);
+       fprintf(stderr, "Usage: add_header model_id input_file output_file\n");
+       fprintf(stderr, "\n");
+       exit(1);
+}
+
+int main(int argc, char **argv)
+{
+       off_t len;                      // of original buf
+       off_t buflen;                   // of the output file
+       int fd;
+       void *input_file;               // pointer to the input file (mmmapped)
+       struct header header;
+       unsigned char *buf;     // pointer to prefix + copy of original buf
+
+       // verify parameters
+
+       if (argc != 4)
+               usage("wrong number of arguments");
+
+       // mmap input_file
+       if ((fd = open(argv[2], O_RDONLY))  < 0
+       || (len = lseek(fd, 0, SEEK_END)) < 0
+       || (input_file = mmap(0, len, PROT_READ, MAP_SHARED, fd, 0)) == (void *) (-1)
+       || close(fd) < 0)
+       {
+               fprintf(stderr, "Error loading file %s: %s\n", argv[2], strerror(errno));
+               exit(1);
+       }
+
+       buflen = len + sizeof(header);
+
+       init_crc32();
+
+       // copy model name into header
+       strncpy(header.model, argv[1], sizeof(header.model));
+       header.crc = 0;
+
+       // create a firmware image in memory and copy the input_file to it
+       buf = malloc(buflen);
+       memcpy(buf, &header, sizeof(header));
+       memcpy(&buf[sizeof(header)], input_file, len);
+
+       // CRC of temporary header + buf
+       header.crc = htonl(crc32buf(buf, buflen));
+
+       memcpy(buf, &header, sizeof(header));
+
+       // write the buf
+       if ((fd = open(argv[3], O_CREAT|O_WRONLY|O_TRUNC,0644)) < 0
+       || write(fd, buf, buflen) != buflen
+       || close(fd) < 0)
+       {
+               fprintf(stderr, "Error storing file %s: %s\n", argv[3], strerror(errno));
+               exit(2);
+       }
+
+       free(buf);
+
+       munmap(input_file,len);
+
+       return 0;
+}
diff --git a/trunk/tools/firmware-utils/src/addpattern.c b/trunk/tools/firmware-utils/src/addpattern.c
new file mode 100644 (file)
index 0000000..1d72285
--- /dev/null
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2004  Manuel Novoa III  <mjn3@codepoet.org>
+ *
+ * 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
+ */
+
+/* July 29, 2004
+ *
+ * This is a hacked replacement for the 'addpattern' utility used to
+ * create wrt54g .bin firmware files.  It isn't pretty, but it does
+ * the job for me.
+ *
+ * Extensions:
+ *  -v allows setting the version string on the command line.
+ *  -{0|1} sets the (currently ignored) hw_ver flag in the header
+ *      to 0 or 1 respectively.
+ */
+
+/* January 12, 2005
+ *
+ * Modified by rodent at rodent dot za dot net
+ * Support added for the new WRT54G v2.2 and WRT54GS v1.1 "flags"
+ * Without the flags set to 0x7, the above units will refuse to flash.
+ *
+ * Extensions:
+ *  -{0|1|2} sets {0|1} sets hw_ver flag to 0/1. {2} sets hw_ver to 1
+ *     and adds the new hardware "flags" for the v2.2/v1.1 units
+*/
+
+/* January 1, 2007
+ *
+ * Modified by juan.i.gonzalez at subdown dot net
+ * Support added for the AG241v2  and similar
+ *
+ * Extensions:
+ *  -r #.# adds revision hardware flags. AG241v2 and similar.
+ *
+ * AG241V2 firmware sets the hw_ver to 0x44.
+ *
+ * Example: -r 2.0
+ *
+ * Convert 2.0 to 20 to be an integer, and add 0x30 to skip special ASCII
+ * #define HW_Version ((HW_REV * 10) + 0x30)  -> from cyutils.h
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+/**********************************************************************/
+
+#define CODE_ID                "U2ND"          /* from code_pattern.h */
+#define CODE_PATTERN   "W54S"  /* from code_pattern.h */
+#define PBOT_PATTERN   "PBOT"
+
+#define CYBERTAN_VERSION       "v3.37.2" /* from cyutils.h */
+
+/* WRT54G v2.2 and WRT54GS v1.1 "flags" (from 3.37.32 firmware cyutils.h) */
+#define SUPPORT_4712_CHIP      0x0001
+#define SUPPORT_INTEL_FLASH    0x0002
+#define SUPPORT_5325E_SWITCH   0x0004
+/* (from 3.00.24 firmware cyutils.h) */
+#define SUPPORT_4704_CHIP      0x0008
+#define SUPPORT_5352E_CHIP     0x0010
+/* (from WD My Net Wi-Fi Range Extender's cyutils.s) */
+#define SUPPORT_4703_CHIP      0x0020
+
+struct code_header {                   /* from cyutils.h */
+       char magic[8];
+       char fwdate[3];
+       char fwvern[3];
+       char id[4];                                     /* U2ND */
+       char hw_ver;                            /* 0: for 4702, 1: for 4712 -- new in 2.04.3 */
+
+       unsigned char  sn;              // Serial Number
+       unsigned char  flags[2];        /* SUPPORT_ flags new for 3.37.2 (WRT54G v2.2 and WRT54GS v1.1) */
+       unsigned char  stable[2];       // The image is stable (for dual image)
+       unsigned char  try1[2];         // Try to boot image first time (for dual image)
+       unsigned char  try2[2];         // Try to boot image second time (for dual image)
+       unsigned char  try3[2];         // Try to boot image third time (for dual_image)
+       unsigned char  res3[2];
+} ;
+
+struct board_info {
+       char    *id;
+       char    *pattern;
+       char    hw_ver;
+       char    sn;
+       char    flags[2];
+};
+
+struct board_info boards[] = {
+       {
+               .id             = "WRT160NL",
+               .pattern        = "NL16",
+               .hw_ver         = 0x00,
+               .sn             = 0x0f,
+               .flags          = {0x3f, 0x00},
+       },
+       {
+               .id             = "mynet-rext",
+               .pattern        = "WDHNSTFH",
+               .hw_ver         = 0x00,
+               .sn             = 0x00,
+               .flags          = {0x3f, 0x00},
+       }, {
+               /* Terminating entry */
+               .id     = NULL,
+       }
+};
+
+/**********************************************************************/
+
+void usage(void) __attribute__ (( __noreturn__ ));
+
+void usage(void)
+{
+       fprintf(stderr, "Usage: addpattern [-i trxfile] [-o binfile] [-B board_id] [-p pattern] [-s serial] [-g] [-b] [-v v#.#.#] [-r #.#] [-{0|1|2|4|5}] -h\n");
+       exit(EXIT_FAILURE);
+}
+
+struct board_info *find_board(char *id)
+{
+       struct board_info *board;
+
+       for (board = boards; board->id != NULL; board++)
+               if (strcasecmp(id, board->id) == 0)
+                       return board;
+
+       return NULL;
+}
+
+int main(int argc, char **argv)
+{
+       char buf[1024]; /* keep this at 1k or adjust garbage calc below */
+       struct code_header *hdr;
+       FILE *in = stdin;
+       FILE *out = stdout;
+       char *ifn = NULL;
+       char *ofn = NULL;
+       char *pattern = CODE_PATTERN;
+       char *pbotpat = PBOT_PATTERN;
+       char *version = CYBERTAN_VERSION;
+       char *board_id = NULL;
+       struct board_info *board = NULL;
+       int gflag = 0;
+       int pbotflag = 0;
+       int c;
+       int v0, v1, v2;
+       size_t off, n;
+       time_t t;
+       struct tm *ptm;
+
+       fprintf(stderr, "mjn3's addpattern replacement - v0.81\n");
+
+       hdr = (struct code_header *) buf;
+       memset(hdr, 0, sizeof(struct code_header));
+
+       while ((c = getopt(argc, argv, "i:o:p:s:gbv:01245hr:B:")) != -1) {
+               switch (c) {
+                       case 'i':
+                               ifn = optarg;
+                               break;
+                       case 'o':
+                               ofn = optarg;
+                               break;
+                       case 'p':
+                               pattern = optarg;
+                               break;
+                       case 's':
+                               hdr->sn = (unsigned char) atoi (optarg);
+                               break;
+                       case 'g':
+                               gflag = 1;
+                               break;
+                       case 'b':
+                               pbotflag = 1;
+                               break;
+                       case 'v':                       /* extension to allow setting version */
+                               version = optarg;
+                               break;
+                       case '0':
+                               hdr->hw_ver = 0;
+                               break;
+                       case '1':
+                               hdr->hw_ver = 1;
+                               break;
+                       case '2':                       /* new 54G v2.2 and 54GS v1.1 flags */
+                               hdr->hw_ver = 1;
+                               hdr->flags[0] |= SUPPORT_4712_CHIP;
+                               hdr->flags[0] |= SUPPORT_INTEL_FLASH;
+                               hdr->flags[0] |= SUPPORT_5325E_SWITCH;
+                               break;
+                       case '4':
+                               /* V4 firmware sets the flags to 0x1f */
+                               hdr->hw_ver = 0;
+                               hdr->flags[0] = 0x1f;
+                               break;
+                       case '5':
+                               /* V5 is appended to trxV2 image */
+                               hdr->stable[0] = 0x73; // force image to be stable
+                               hdr->stable[1] = 0x00;
+                               hdr->try1[0]   = 0x74; // force try1 to be set
+                               hdr->try1[1]   = 0x00;
+                               hdr->try2[0]   = hdr->try2[1]   = 0xFF;
+                               hdr->try3[0]   = hdr->try3[1]   = 0xFF;
+                               break;
+                        case 'r':
+                                hdr->hw_ver = (char)(atof(optarg)*10)+0x30;
+                                break;
+                        case 'B':
+                                board_id = optarg;
+                                break;
+
+                        case 'h':
+                       default:
+                               usage();
+               }
+       }
+
+       if (optind != argc || optind == 1) {
+               fprintf(stderr, "illegal arg \"%s\"\n", argv[optind]);
+               usage();
+       }
+
+       if (board_id) {
+               board = find_board(board_id);
+               if (board == NULL) {
+                       fprintf(stderr, "unknown board \"%s\"\n", board_id);
+                       usage();
+               }
+               pattern = board->pattern;
+               hdr->hw_ver = board->hw_ver;
+               hdr->sn = board->sn;
+               hdr->flags[0] = board->flags[0];
+               hdr->flags[1] = board->flags[1];
+       }
+
+       if (strlen(pattern) > 8) {
+               fprintf(stderr, "illegal pattern \"%s\"\n", pattern);
+               usage();
+       }
+
+       if (ifn && !(in = fopen(ifn, "r"))) {
+               fprintf(stderr, "can not open \"%s\" for reading\n", ifn);
+               usage();
+       }
+
+       if (ofn && !(out = fopen(ofn, "w"))) {
+               fprintf(stderr, "can not open \"%s\" for writing\n", ofn);
+               usage();
+       }
+
+       if (time(&t) == (time_t)(-1)) {
+               fprintf(stderr, "time call failed\n");
+               return EXIT_FAILURE;
+       }
+
+       ptm = localtime(&t);
+
+       if (3 != sscanf(version, "v%d.%d.%d", &v0, &v1, &v2)) {
+               fprintf(stderr, "bad version string \"%s\"\n", version);
+               return EXIT_FAILURE;
+       }
+
+       memcpy(hdr->magic, pattern, strlen(pattern));
+       if (pbotflag)
+               memcpy(&hdr->magic[4], pbotpat, 4);
+       hdr->fwdate[0] = ptm->tm_year % 100;
+       hdr->fwdate[1] = ptm->tm_mon + 1;
+       hdr->fwdate[2] = ptm->tm_mday;
+       hdr->fwvern[0] = v0;
+       hdr->fwvern[1] = v1;
+       hdr->fwvern[2] = v2;
+       memcpy(hdr->id, CODE_ID, strlen(CODE_ID));
+
+       off = sizeof(struct code_header);
+
+       fprintf(stderr, "writing firmware v%d.%d.%d on %d/%d/%d (y/m/d)\n",
+                       v0, v1, v2,
+                       hdr->fwdate[0], hdr->fwdate[1], hdr->fwdate[2]);
+
+
+       while ((n = fread(buf + off, 1, sizeof(buf)-off, in) + off) > 0) {
+               off = 0;
+               if (n < sizeof(buf)) {
+                       if (ferror(in)) {
+                       FREAD_ERROR:
+                               fprintf(stderr, "fread error\n");
+                               return EXIT_FAILURE;
+                       }
+                       if (gflag) {
+                               gflag = sizeof(buf) - n;
+                               memset(buf + n, 0xff, gflag);
+                               fprintf(stderr, "adding %d bytes of garbage\n", gflag);
+                               n = sizeof(buf);
+                       }
+               }
+               if (!fwrite(buf, n, 1, out)) {
+               FWRITE_ERROR:
+                       fprintf(stderr, "fwrite error\n");
+                       return EXIT_FAILURE;
+               }
+       }
+
+       if (ferror(in)) {
+               goto FREAD_ERROR;
+       }
+
+       if (fflush(out)) {
+               goto FWRITE_ERROR;
+       }
+
+       fclose(in);
+       fclose(out);
+
+       return EXIT_SUCCESS;
+}
diff --git a/trunk/tools/firmware-utils/src/airlink.c b/trunk/tools/firmware-utils/src/airlink.c
new file mode 100644 (file)
index 0000000..560a58d
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ * Thanks to Vassily Galinsky for this tool
+*****************************************************************************
+AIRLINK AR525W firmware image structure
+  -8:-5  Extended (httpd) header checksum  -       sum2
+  -4:-1  Extended (httpd) header magic     -       "ARRN" - 0x4e525241
+   0: 3  Standard (tftpd) header magic     -       "GMTK" - 0x4b544d47
+   4: 7  Standard (tftpd) header checksum  -       sum1
+   8: b  0
+   c: f  Size of compressed linux kernel
+  10:13  Size of firmware image file with standard header
+  14:17  Product code                      -       0x5
+  18:1b  Bootloader checksum               -       sum0
+  1c:1f  0
+  20:    Compressed linux kernel
+  -      Squashfs or jffs2 file system - kernel dependent - either 32 bytes or sector aligned 
+*****************************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+
+typedef unsigned char uchar;
+
+uint32_t crctab[257] = {
+       0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
+       0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+       0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+       0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+       0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+       0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+       0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+       0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+       0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+       0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+       0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
+       0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+       0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
+       0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+       0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+       0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+       0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
+       0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+       0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
+       0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+       0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+       0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+       0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
+       0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+       0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+       0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+       0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+       0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+       0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
+       0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+       0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
+       0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+       0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+       0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+       0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+       0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+       0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
+       0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+       0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+       0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+       0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
+       0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+       0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
+       0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+       0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+       0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+       0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
+       0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+       0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+       0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+       0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+       0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+       0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
+       0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+       0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+       0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+       0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+       0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+       0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
+       0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+       0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
+       0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+       0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+       0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
+       0
+};
+
+uint32_t header[] = {
+       0x00000000, 0x4e525241,
+       0x4b544d47, 0x00000000, 0x00000000, 0x000afd4a,
+       0x00000000, 0x00000005, 0x00000000, 0x00000000
+};
+
+static int JFFS2 = 0;
+
+int generate_image(char *kname, char *fsname, char *fname, int EHDR)
+{
+       int i;
+       uint32_t lenk, lens;
+       uchar *bk, *bs;
+       int fkd, ffd, fsd;
+       fkd = open(kname, O_RDONLY);
+       ffd = creat(fname, 0644);
+       if ((fkd < 0) || (ffd < 0))
+               return -1;
+       if (fsname) {
+               fsd = open(fsname, O_RDONLY);
+               if (fsd < 0)
+                       return -1;
+       }
+       lenk = lseek(fkd, 0, SEEK_END);
+       header[5] = lenk;
+       bk = (uchar *) mmap(NULL, lenk, PROT_READ, MAP_SHARED, fkd, 0);
+       if (bk == MAP_FAILED)
+               return -1;
+       if (fsname) {
+               lens = lseek(fsd, 0, SEEK_END);
+               bs = (uchar *) mmap(NULL, lens, PROT_READ, MAP_SHARED, fsd,
+                                   0);
+               if (bs == MAP_FAILED)
+                       return -1;
+       }
+       if (EHDR)
+               write(ffd, header, 0x28);
+       else
+               write(ffd, header + 2, 0x20);
+       write(ffd, bk, lenk);
+       lenk += 0x20;
+       if (!JFFS2) JFFS2 = 0x20;
+       printf("Padding header+kernel - 0x%x +  0x%x = 0x%x\n",
+              lenk, ((lenk - 1 + JFFS2) / JFFS2) * JFFS2 - lenk,
+              ((lenk - 1 + JFFS2) / JFFS2) * JFFS2);
+       for (i = 0; i < ((lenk - 1 + JFFS2) / JFFS2) * JFFS2 - lenk; i++)
+               write(ffd, header, 1);
+       if (fsname) {
+               write(ffd, bs, lens);
+               close(fsd);
+       }
+       close(ffd);
+       close(fkd);
+       return 0;
+}
+
+uint32_t crc32(uchar * buf, uint32_t len)
+{
+       register int i;
+       uint32_t sum;
+       register uint32_t s0;
+       s0 = ~0;
+       for (i = 0; i < len; i++) {
+               s0 = (s0 >> 8) ^ crctab[(uchar) (s0 & 0xFF) ^ buf[i]];
+       }
+       sum = ~s0;
+       return sum;
+}
+
+void usage(char *prog)
+{
+       printf("Usage: %s [-b 0/1] image_filename \n", prog);
+       printf("       update checksums for firmware file\n");
+       printf
+           ("Usage: %s [-b 0/1] [-j erasesize_in_kibytes] [-e] kernel filesystem image_filename \n",
+            prog);
+       printf("       generate firmware file and update checksums\n");
+       printf("--------------------------------------------------\n");
+       printf("       -e - generate header for web upload\n");
+       printf("       -b 0/1 - clear/update bootloader checksum\n");
+       printf("       -j erasesize_in_kibytes - generate header for jffs2 filesystem\n");
+}
+
+int main(int argc, char **argv)
+{
+       uchar b[0x400];
+       char EHDR = 0;
+       char BHDR = 0;
+       int c, fd;
+       extern char *optarg;
+       extern int optind, optopt;
+
+       while ((c = getopt(argc, argv, "b:ej:")) != -1) {
+               switch (c) {
+               case 'b':
+                       if (optarg[0] == '1')
+                               BHDR = 1;
+                       break;
+               case 'e':
+                       EHDR = 1;
+                       break;
+               case 'j':
+                       sscanf(optarg, "%i", &JFFS2);
+                       JFFS2 *= 1024;
+                       break;
+               case '?':
+                       fprintf(stderr, "\nError: unknown arg %c\n\n\n",
+                               optopt);
+                       usage(argv[0]);
+                       exit(-1);
+               }
+       }
+       if (((argc - optind) < 1) && ((argc - optind) > 3)) {
+               usage(argv[0]);
+               exit(-1);
+       }
+       if ((argc - optind) == 3)
+               if (generate_image
+                   (argv[optind], argv[optind + 1], argv[optind + 2],
+                    EHDR)) {
+                       fprintf(stderr,
+                               "\nError generating image file %s\n\n\n",
+                               argv[argc - 1]);
+                       usage(argv[0]);
+                       exit(-1);
+               }
+       if ((argc - optind) == 2)
+               if (generate_image
+                   (argv[optind], NULL, argv[optind + 1], EHDR)) {
+                       fprintf(stderr,
+                               "\nError generating image file %s\n\n\n",
+                               argv[argc - 1]);
+                       usage(argv[0]);
+                       exit(-1);
+               }
+
+       fd = open(argv[argc - 1], O_RDWR);
+       if (fd < 0) {
+               fprintf(stderr, "\nImage file not found %s\n\n\n",
+                       argv[argc - 1]);
+               usage(argv[0]);
+               exit(-1);
+       }
+       long i, len = lseek(fd, 0, SEEK_END);
+       lseek(fd, 0, SEEK_SET);
+       uchar *buf = malloc(len);
+       read(fd, buf, len);
+       uint32_t sum, l0;
+       uint32_t MagicS = 0x474d544b;
+       uint32_t MagicE = 0x4152524e;
+       if (ntohl(*((uint32_t *) buf)) == MagicS) {
+               fprintf(stderr,
+                       "Image without extra 8 bytes - Standard header\n");
+               buf[0x10] = len & 0xff;
+               buf[0x11] = (len >> 8) & 0xff;
+               buf[0x12] = (len >> 16) & 0xff;
+               buf[0x13] = (len >> 24) & 0xff;
+               lseek(fd, 0x10, SEEK_SET);
+               write(fd, buf + 0x10, 0x4);
+               EHDR = 0;
+       } else if ((ntohl(*((uint32_t *) (buf + 0x8))) == MagicS)
+                  && ((ntohl(*((uint32_t *) (buf + 0x4))) == MagicE))) {
+               fprintf(stderr,
+                       "Image with extra 8 bytes - Extended header\n");
+               *((uint32_t *) (buf + 0x18)) = len - 8;
+               buf[0x18] = (len - 8) & 0xff;
+               buf[0x19] = ((len - 8) >> 8) & 0xff;
+               buf[0x1a] = ((len - 8) >> 16) & 0xff;
+               buf[0x1b] = ((len - 8) >> 24) & 0xff;
+               lseek(fd, 0x18, SEEK_SET);
+               write(fd, buf + 0x18, 0x4);
+               buf += 8;
+               EHDR = 1;
+       } else if (len == buf[0x10] | ((uint32_t)buf[0x11] << 8) | ((uint32_t)buf[0x12] << 16) | ((uint32_t)buf[0x13] << 24)) {
+               fprintf(stderr,
+                       "Image without extra 8 bytes - Standard header\n");
+               EHDR = 0;
+       } else if (len == (buf[0x18] | ((uint32_t)buf[0x19] << 8) | ((uint32_t)buf[0x1a] << 16) | ((uint32_t)buf[0x1b] << 24)) + 8) {
+               fprintf(stderr,
+                       "Image with extra 8 bytes - Extended header\n");
+               buf += 8;
+               EHDR = 1;
+       } else {
+               fprintf(stderr, "ERROR: Wrong image size\n");
+               exit(-1);
+       }
+       l0 = buf[0x10] | ((uint32_t)buf[0x11] << 8) | ((uint32_t)buf[0x12] << 16) | ((uint32_t)buf[0x13] << 24);
+       if (!BHDR)
+               *((uint32_t *) & buf[0x18]) = 0;
+       unsigned long sum0 = buf[0x18] | ((uint32_t)buf[0x19] << 8) | ((uint32_t)buf[0x1a] << 16) | ((uint32_t)buf[0x1b] << 24);
+       unsigned long sum1 = buf[0x4] | ((uint32_t)buf[0x5] << 8) | ((uint32_t)buf[0x6] << 16) | ((uint32_t)buf[0x7] << 24);
+       *((uint32_t *) & buf[0x4]) = 0x0L;
+       memcpy(b, buf, 0x100);
+       memcpy(b + 0x100, buf + ((l0 >> 1) - ((l0 & 0x6) >> 1)), 0x100);
+       memcpy(b + 0x200, buf + (l0 - 0x200), 0x200);
+       *((uint32_t *) & b[0x18]) = 0x0L;
+
+       sum = crc32(b, 0x400);
+       printf("CRC32 sum0 - (%x, %x, %x)\n", sum, sum0, 0x400);
+       if (EHDR)
+               lseek(fd, 0x20, SEEK_SET);
+       else
+               lseek(fd, 0x18, SEEK_SET);
+       buf[0x18] = (BHDR ? sum : sum0) & 0xff;
+       buf[0x19] = ((BHDR ? sum : sum0) >> 8) & 0xff;
+       buf[0x1a] = ((BHDR ? sum : sum0) >> 16) & 0xff;
+       buf[0x1b] = ((BHDR ? sum : sum0) >> 24) & 0xff;
+       write(fd, &buf[0x18], 0x4);
+
+       sum = crc32(buf, l0);
+       printf("CRC32 sum1 - (%x, %x, %x)\n", sum, sum1, l0);
+       if (EHDR)
+               lseek(fd, 0xC, SEEK_SET);
+       else
+               lseek(fd, 0x4, SEEK_SET);
+       buf[0x4] = sum & 0xff;
+       buf[0x5] = (sum >> 8) & 0xff;
+       buf[0x6] = (sum >> 16) & 0xff;
+       buf[0x7] = (sum >> 24) & 0xff;
+       write(fd, &buf[0x4], 0x4);
+       if (EHDR) {
+               unsigned long sum2 = buf[-0x8] | ((uint32_t)buf[-0x7] << 8) | ((uint32_t)buf[-0x6] << 16) | ((uint32_t)buf[-0x5] << 24);
+               *((uint32_t *) & buf[-0x8]) = 0L;
+               sum = crc32(buf - 0x4, len - 0x4);
+               printf("CRC32 sum2 - (%x, %x, %x)\n", sum, sum2,
+                      len - 0x4);
+               lseek(fd, 0, SEEK_SET);
+               *((uint32_t *) & buf[-0x8]) = htonl(sum);
+               write(fd, &buf[-0x8], 0x4);
+               buf -= 8;
+       }
+       close(fd);
+       free(buf);
+       return 0;
+}
diff --git a/trunk/tools/firmware-utils/src/bcm_tag.h b/trunk/tools/firmware-utils/src/bcm_tag.h
new file mode 100644 (file)
index 0000000..ecbd889
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef __BCM63XX_TAG_H
+#define __BCM63XX_TAG_H
+
+#define TAGVER_LEN 4                   /* Length of Tag Version */
+#define TAGLAYOUT_LEN 4                /* Length of FlashLayoutVer */
+#define SIG1_LEN 20                   /* Company Signature 1 Length */
+#define SIG2_LEN 14                    /* Company Signature 2 Lenght */
+#define BOARDID_LEN 16                /* Length of BoardId */
+#define ENDIANFLAG_LEN 2               /* Endian Flag Length */
+#define CHIPID_LEN 6                  /* Chip Id Length */
+#define IMAGE_LEN 10                   /* Length of Length Field */
+#define ADDRESS_LEN 12                 /* Length of Address field */
+#define DUALFLAG_LEN 2                /* Dual Image flag Length */
+#define INACTIVEFLAG_LEN 2            /* Inactie Flag Length */
+#define RSASIG_LEN 20                 /* Length of RSA Signature in tag */
+#define TAGINFO1_LEN 30                /* Length of vendor information field1 in tag */
+#define FLASHLAYOUTVER_LEN 4          /* Length of Flash Layout Version String tag */
+#define TAGINFO2_LEN 16                /* Length of vendor information field2 in tag */
+#define CRC_LEN 4                      /* Length of CRC in bytes */
+#define ALTTAGINFO_LEN 54              /* Alternate length for vendor information; Pirelli */
+
+#define NUM_PIRELLI 2
+#define IMAGETAG_CRC_START             0xFFFFFFFF
+
+#define PIRELLI_BOARDS { \
+  "AGPF-S0", \
+  "DWV-S0", \
+}
+
+/*
+ * The broadcom firmware assumes the rootfs starts the image,
+ * therefore uses the rootfs start (flashImageAddress)
+ * to determine where to flash the image.  Since we have the kernel first
+ * we have to give it the kernel address, but the crc uses the length
+ * associated with this address (rootLength), which is added to the kernel
+ * length (kernelLength) to determine the length of image to flash and thus
+ * needs to be rootfs + deadcode (jffs2 EOF marker)
+*/
+
+struct bcm_tag {
+       char tagVersion[TAGVER_LEN];           // 0-3: Version of the image tag
+       char sig_1[SIG1_LEN];                  // 4-23: Company Line 1
+       char sig_2[SIG2_LEN];                  // 24-37: Company Line 2
+       char chipid[CHIPID_LEN];               // 38-43: Chip this image is for
+       char boardid[BOARDID_LEN];             // 44-59: Board name
+       char big_endian[ENDIANFLAG_LEN];       // 60-61: Map endianness -- 1 BE 0 LE
+       char totalLength[IMAGE_LEN];           // 62-71: Total length of image
+       char cfeAddress[ADDRESS_LEN];          // 72-83: Address in memory of CFE
+       char cfeLength[IMAGE_LEN];             // 84-93: Size of CFE
+       char flashImageStart[ADDRESS_LEN];     // 94-105: Address in memory of image start (kernel for libreCMC, rootfs for stock firmware)
+       char flashRootLength[IMAGE_LEN];            // 106-115: Size of rootfs for flashing
+       char kernelAddress[ADDRESS_LEN];       // 116-127: Address in memory of kernel
+       char kernelLength[IMAGE_LEN];          // 128-137: Size of kernel
+       char dualImage[DUALFLAG_LEN];          // 138-139: Unused at present
+       char inactiveFlag[INACTIVEFLAG_LEN];   // 140-141: Unused at present
+        char rsa_signature[RSASIG_LEN];        // 142-161: RSA Signature (unused at present; some vendors may use this)
+       char information1[TAGINFO1_LEN];       // 162-191: Compilation and related information (not generated/used by libreCMC)
+        char flashLayoutVer[FLASHLAYOUTVER_LEN];// 192-195: Version flash layout
+        char fskernelCRC[CRC_LEN];             // 196-199: kernel+rootfs CRC32
+       char information2[TAGINFO2_LEN];       // 200-215: Unused at present except Alice Gate where is is information
+       char imageCRC[CRC_LEN];                // 216-219: CRC32 of image less imagetag (kernel for Alice Gate)
+        char rootfsCRC[CRC_LEN];               // 220-223: CRC32 of rootfs partition
+        char kernelCRC[CRC_LEN];               // 224-227: CRC32 of kernel partition
+        char imageSequence[4];                // 228-231: Image sequence number
+        char rootLength[4];                    // 232-235: steal from reserved1 to keep the real root length so we can use in the flash map even after we have change the rootLength to 0 to satisfy devices that check CRC on every boot
+        char headerCRC[CRC_LEN];               // 236-239: CRC32 of header excluding tagVersion
+        char reserved2[16];                    // 240-255: Unused at present
+};
+
+#endif /* __BCM63XX_TAG_H */
diff --git a/trunk/tools/firmware-utils/src/bcmalgo.c b/trunk/tools/firmware-utils/src/bcmalgo.c
new file mode 100644 (file)
index 0000000..e7d3b11
--- /dev/null
@@ -0,0 +1,248 @@
+#include <stdlib.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <string.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include "bcmalgo.h"
+
+
+#define UTIL_VERSION "0.1"
+#define ENDIAN_REVERSE_NEEDED
+
+uint32_t reverse_endian32 ( uint32_t data )
+{
+#ifdef ENDIAN_REVERSE_NEEDED
+       return 0 | ( data & 0x000000ff ) << 24
+              | ( data & 0x0000ff00 ) << 8
+              | ( data & 0x00ff0000 ) >> 8
+              | ( data & 0xff000000 ) >> 24;
+#else
+       return data;
+#endif
+}
+
+uint16_t reverse_endian16 ( uint16_t data )
+{
+#ifdef ENDIAN_REVERSE_NEEDED
+       return 0 | ( data & 0x00ff ) << 8
+              | ( data & 0xff00 ) >> 8;
+#else
+       return data;
+#endif
+}
+
+
+
+uint32_t get_buffer_crc ( char* filebuffer,size_t size )
+{
+
+       long crc=0xffffffffL;
+       long crcxor = 0xffffffffL;
+       long num4 = 0xffffffffL;
+       long num5 = size;
+       long num6 = 0x4c11db7L;
+       long num7 = 0x80000000L;
+       int i;
+       long j;
+       for ( i = 0; i < ( num5 ); i++ )
+       {
+               long num2 = filebuffer[i];
+               for ( j = 0x80L; j != 0L; j = j >> 1 )
+               {
+                       long num3 = crc & num7;
+                       crc = crc << 1;
+                       if ( ( num2 & j ) != 0L )
+                       {
+                               num3 ^= num7;
+                       }
+                       if ( num3 != 0L )
+                       {
+                               crc ^= num6;
+                       }
+               }
+       }
+       crc ^= crcxor;
+       crc &= num4;
+
+       uint8_t b1 = ( uint8_t ) ( ( crc & -16777216L ) >> 0x18 );
+       uint8_t b2 = ( uint8_t ) ( ( crc & 0xff0000L ) >> 0x10 );
+       uint8_t b3 = ( uint8_t ) ( ( crc & 0xff00L ) >> 8 );
+       uint8_t b4 = ( uint8_t ) ( crc & 0xffL );
+       int32_t crc_result = ( b1 | b2 << 8| b3 << 16| b4 <<24 );
+       return reverse_endian32 ( crc_result );
+}
+
+//Thnx to Vector for the algo.
+uint32_t get_file_crc ( char* filename )
+{
+       struct stat buf;
+       stat ( filename,&buf );
+       char* filebuffer = malloc ( buf.st_size+10 );
+       FILE* fd = fopen ( filename,"r" );
+       fread ( filebuffer, 1, buf.st_size,fd );
+       fclose ( fd );
+       uint32_t crc = get_buffer_crc ( filebuffer,buf.st_size );
+       free ( filebuffer );
+       return crc;
+}
+
+
+
+uint16_t get_hcs ( ldr_header_t* hd )
+{
+       uint8_t* head = ( uint8_t* ) hd;
+       uint8_t hcs_minor;
+       uint8_t hcs_major;
+       uint16_t n = 0xffff;
+       uint16_t m = 0;
+       int state = 0;
+       int i,j;
+       for ( i = 0; i < 0x54; i++ )
+       {
+               uint16_t m = head[i];
+               m = m << 8;
+               for ( j = 0; j < 8; j++ )
+               {
+                       if ( ( ( n ^ m ) & 0x8000 ) == 0 )
+                       {
+                               state = 0;
+                       }
+                       else
+                       {
+                               state = 1;
+                       }
+                       n = n << 1;
+                       if ( state )
+                       {
+                               n ^= 0x1021;
+                       }
+                       m = m << 1;
+               }
+               n &= 0xffff;
+       }
+       n ^= 0xffff;
+       hcs_major = ( uint8_t ) ( ( n & 0xff00 ) >> 8 );
+       hcs_minor = ( uint8_t ) ( n & 0xff );
+       uint16_t hcs = hcs_major <<8 | hcs_minor;
+       return hcs;
+}
+
+ldr_header_t* construct_header ( uint32_t magic, uint16_t rev_maj,uint16_t rev_min, uint32_t build_date, uint32_t filelen, uint32_t ldaddress, const char* filename, uint32_t crc_data )
+{
+       ldr_header_t* hd = malloc ( sizeof ( ldr_header_t ) );
+       hd->magic=reverse_endian16 ( magic );
+       hd->control=0; //FixMe: Make use of it once compression is around
+       hd->rev_min = reverse_endian16 ( rev_min );
+       hd->rev_maj = reverse_endian16 ( rev_maj );
+       hd->build_date = reverse_endian32 ( build_date );
+       hd->filelen = reverse_endian32 ( filelen );
+       hd->ldaddress = reverse_endian32 ( ldaddress );
+       printf ( "Creating header for %s...\n", filename );
+       if ( strlen ( filename ) >63 )
+       {
+               printf ( "[!] Filename too long - stripping it to 63 bytes.\n" );
+               strncpy ( ( char* ) &hd->filename, filename, 63 );
+               hd->filename[63]=0x00;
+       }
+       else
+       {
+               strcpy ( ( char* ) &hd->filename, filename );
+       }
+       hd->crc=reverse_endian32 ( crc_data );
+       hd->hcs = reverse_endian16 ( get_hcs ( hd ) );
+       return hd;
+}
+
+static char control_unc[]  = "Uncompressed";
+static char control_lz[]   = "LZRW1/KH";
+static char control_mlzo[] = "mini-LZO";
+static char control_nrv[] = "NRV2D99 [Bootloader?]";
+static char control_nstdlzma[] = "(non-standard) LZMA";
+static char control_unk[] = "Unknown";
+char* get_control_info ( uint16_t control )
+{
+       control = reverse_endian16 ( control );
+       switch ( control )
+       {
+               case 0:
+                       return control_unc;
+                       break;
+               case 1:
+                       return control_lz;
+                       break;
+               case 2:
+                       return control_mlzo;
+                       break;
+               case 3:
+                       return control_unc;
+                       break;
+               case 4:
+                       return control_nrv;
+                       break;
+               case 5:
+                       return control_nstdlzma;
+                       break;
+               case 6:
+                       return control_unc;
+                       break;
+               case 7:
+                       return control_unc;
+                       break;
+               default:
+                       return control_unk;
+                       break;
+       }
+
+}
+
+int dump_header ( ldr_header_t* hd )
+{
+       printf ( "=== Header Information ===\n" );
+       printf ( "Header magic:\t0x%04X\n",reverse_endian16 ( hd->magic ) );
+       printf ( "Control:\t0x%04X (%s)\n",reverse_endian16 ( hd->control ), get_control_info ( hd->control ) );
+       printf ( "Major rev. :\t0x%04X\n",reverse_endian16 ( hd->rev_maj ) );
+       printf ( "Minor rev. :\t0x%04X\n",reverse_endian16 ( hd->rev_min ) );
+       printf ( "File name :\t%s\n", ( char* ) &hd->filename );
+       printf ( "File length:\t%d bytes\n", reverse_endian32 ( hd->filelen ) );
+       printf ( "Build time:\t0x%08X //FixMe: print in human-readable form\n", reverse_endian32 ( hd->build_date ) ); //FixMe:
+       printf ( "HCS:\t\t0x%04X  ",reverse_endian16 ( hd->hcs ) );
+       uint16_t hcs = get_hcs ( hd );
+       int ret=0;
+       if ( hcs ==reverse_endian16 ( hd->hcs ) )
+       {
+               printf ( "(OK!)\n" );
+       }
+       else
+       {
+               printf ( "(ERROR! expected 0x%04X)\n",hcs );
+               ret=1;
+       }
+//printf("HCS:\t0x%02X",reverse_endian32(hd->hcs));
+       printf ( "Load address:\t0x%08X\n", reverse_endian32 ( hd->ldaddress ) ); //FixMe:
+       printf ( "HNW:\t\t0x%04X\n",reverse_endian16 ( hd->her_znaet_chto ) ); //Hell knows what
+       printf ( "CRC:\t\t0x%08X\n",reverse_endian32 ( hd->crc ) );
+       printf ( "=== Binary Header Dump===\n" );
+       int i,j;
+       uint8_t* head = ( uint8_t* ) hd;
+       for ( i=0;i<=sizeof ( ldr_header_t );i++ )
+       {
+               if ( i % 8==0 )
+                       printf ( "\n" );
+               printf ( "0x%02x   ",head[i] );
+       }
+       printf ( "\n\n== End Of Header dump ==\n" );
+       return ret;
+}
+
+
+void print_copyright()
+{
+       printf ( "Part of bcm-utils package ver. " UTIL_VERSION " \n" );
+       printf ( "Copyright (C) 2009  Andrew 'Necromant' Andrianov\n"
+                "This is free software, and you are welcome to redistribute it\n"
+                "under certain conditions. See COPYING for details\n" );
+}
diff --git a/trunk/tools/firmware-utils/src/bcmalgo.h b/trunk/tools/firmware-utils/src/bcmalgo.h
new file mode 100644 (file)
index 0000000..46647cf
--- /dev/null
@@ -0,0 +1,83 @@
+#ifndef bcmutils_H
+#define bcmutils_H
+
+typedef struct
+{
+       uint16_t magic;
+       uint16_t control;
+       uint16_t rev_maj;
+       uint16_t rev_min;
+       uint32_t build_date;
+       uint32_t filelen;
+       uint32_t ldaddress;
+       char filename[64];
+       uint16_t hcs;
+       uint16_t her_znaet_chto; //v dushe ne ebu
+       uint32_t crc;
+} ldr_header_t;
+
+
+/**
+ * Reverses endianess of a 32bit int, if the ENDIAN_REVERSE_NEEDED defined at compile-time
+ * @param data
+ * @return
+ */
+uint32_t reverse_endian32 ( uint32_t data );
+
+/**
+ * Reverses endianess of a 16bit int, if the ENDIAN_REVERSE_NEEDED defined at compile-time
+ * @param data
+ * @return
+ */
+uint16_t reverse_endian16 ( uint16_t data );
+/**
+ * Calculates the strange crc (used by bcm modems) of the file. Thnx fly out to Vector for the algorithm.
+ * @param filename
+ * @return
+ */
+uint32_t get_file_crc ( char* filename );
+
+/**
+ * Calculates HCS of the header.
+ * @param hd
+ * @return
+ */
+uint16_t get_hcs ( ldr_header_t* hd );
+
+/**
+ * Constructs the header of the image with the information given It also automagically calculates HCS and writes it there.
+ * @param magic - magic device bytes
+ * @param rev_maj - major revision
+ * @param rev_min - minor revision
+ * @param build_date - build date (seconds from EPOCH UTC)
+ * @param filelen - file length in bytes
+ * @param ldaddress - Load adress
+ * @param filename - filename
+ * @param crc_data - the crc of the data
+ * @return
+ */
+ldr_header_t* construct_header ( uint32_t magic, uint16_t rev_maj,uint16_t rev_min, uint32_t build_date, uint32_t filelen, uint32_t ldaddress, const char* filename, uint32_t crc_data );
+
+/**
+ * Dumps header information to stdout.
+ * @param hd
+ */
+int dump_header ( ldr_header_t* hd );
+
+
+/**
+ * Returns a null terminated string describing what the control number meens
+ * DO NOT FREE IT!!!
+ * @param control
+ * @return
+ */
+char* get_control_info ( uint16_t control );
+#endif
+
+/**
+ * Calculates bcmCRC of a data buffer.
+ * @param filebuffer - pointer to buffer
+ * @param size - buffer size
+ * @return
+ */
+uint32_t get_buffer_crc ( char* filebuffer, size_t size );
diff --git a/trunk/tools/firmware-utils/src/buffalo-enc.c b/trunk/tools/firmware-utils/src/buffalo-enc.c
new file mode 100644 (file)
index 0000000..59b66ab
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <libgen.h>
+#include <getopt.h>     /* for getopt() */
+#include <stdarg.h>
+
+#include "buffalo-lib.h"
+
+#define ERR(fmt, args...) do { \
+       fflush(0); \
+       fprintf(stderr, "[%s] *** error: " fmt "\n", \
+                       progname, ## args ); \
+} while (0)
+
+static char *progname;
+static char *ifname;
+static char *ofname;
+static char *crypt_key = "Buffalo";
+static char *magic = "start";
+static int longstate;
+static unsigned char seed = 'O';
+
+static char *product;
+static char *version;
+static int do_decrypt;
+
+void usage(int status)
+{
+       FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+
+       fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+       fprintf(stream,
+"\n"
+"Options:\n"
+"  -d              decrypt instead of encrypt\n"
+"  -i <file>       read input from the file <file>\n"
+"  -o <file>       write output to the file <file>\n"
+"  -l              use longstate {en,de}cryption method\n"
+"  -k <key>        use <key> for encryption (default: Buffalo)\n"
+"  -m <magic>      set magic to <magic>\n"
+"  -p <product>    set product name to <product>\n"
+"  -v <version>    set version to <version>\n"
+"  -h              show this screen\n"
+       );
+
+       exit(status);
+}
+
+static int decrypt_file(void)
+{
+       struct enc_param ep;
+       ssize_t src_len;
+       unsigned char *buf = NULL;
+       int err;
+       int ret = -1;
+
+       src_len = get_file_size(ifname);
+       if (src_len < 0) {
+               ERR("unable to get size of '%s'", ifname);
+               goto out;
+       }
+
+       buf = malloc(src_len);
+       if (buf == NULL) {
+               ERR("no memory for the buffer");
+               goto out;
+       }
+
+       err = read_file_to_buf(ifname, buf, src_len);
+       if (err) {
+               ERR("unable to read from file '%s'", ifname);
+               goto out;
+       }
+
+       memset(&ep, '\0', sizeof(ep));
+       ep.key = (unsigned char *) crypt_key;
+       ep.longstate = longstate;
+
+       err = decrypt_buf(&ep, buf, src_len);
+       if (err) {
+               ERR("unable to decrypt '%s'", ifname);
+               goto out;
+       }
+
+       printf("Magic\t\t: '%s'\n", ep.magic);
+       printf("Seed\t\t: 0x%02x\n", ep.seed);
+       printf("Product\t\t: '%s'\n", ep.product);
+       printf("Version\t\t: '%s'\n", ep.version);
+       printf("Data len\t: %u\n", ep.datalen);
+       printf("Checksum\t: 0x%08x\n", ep.csum);
+
+       err = write_buf_to_file(ofname, buf, ep.datalen);
+       if (err) {
+               ERR("unable to write to file '%s'", ofname);
+               goto out;
+       }
+
+       ret = 0;
+
+out:
+       free(buf);
+       return ret;
+}
+
+static int encrypt_file(void)
+{
+       struct enc_param ep;
+       ssize_t src_len;
+       unsigned char *buf;
+       uint32_t hdrlen;
+       ssize_t totlen = 0;
+       int err;
+       int ret = -1;
+
+       src_len = get_file_size(ifname);
+       if (src_len < 0) {
+               ERR("unable to get size of '%s'", ifname);
+               goto out;
+       }
+
+       totlen = enc_compute_buf_len(product, version, src_len);
+       hdrlen = enc_compute_header_len(product, version);
+
+       buf = malloc(totlen);
+       if (buf == NULL) {
+               ERR("no memory for the buffer");
+               goto out;
+       }
+
+       err = read_file_to_buf(ifname, &buf[hdrlen], src_len);
+       if (err) {
+               ERR("unable to read from file '%s'", ofname);
+               goto free_buf;
+       }
+
+       memset(&ep, '\0', sizeof(ep));
+       ep.key = (unsigned char *) crypt_key;
+       ep.seed = seed;
+       ep.longstate = longstate;
+       ep.csum = buffalo_csum(src_len, &buf[hdrlen], src_len);
+       ep.datalen = src_len;
+       strcpy((char *) ep.magic, magic);
+       strcpy((char *) ep.product, product);
+       strcpy((char *) ep.version, version);
+
+       err = encrypt_buf(&ep, buf, &buf[hdrlen]);
+       if (err) {
+               ERR("invalid input file");
+               goto free_buf;
+       }
+
+       err = write_buf_to_file(ofname, buf, totlen);
+       if (err) {
+               ERR("unable to write to file '%s'", ofname);
+               goto free_buf;
+       }
+
+       ret = 0;
+
+free_buf:
+       free(buf);
+out:
+       return ret;
+}
+
+static int check_params(void)
+{
+       int ret = -1;
+
+       if (ifname == NULL) {
+               ERR("no input file specified");
+               goto out;
+       }
+
+       if (ofname == NULL) {
+               ERR("no output file specified");
+               goto out;
+       }
+
+       if (crypt_key == NULL) {
+               ERR("no key specified");
+               goto out;
+       } else if (strlen(crypt_key) > BCRYPT_MAX_KEYLEN) {
+               ERR("key '%s' is too long", crypt_key);
+               goto out;
+       }
+
+       if (strlen(magic) != (ENC_MAGIC_LEN - 1)) {
+               ERR("length of magic must be %d", ENC_MAGIC_LEN - 1);
+               goto out;
+       }
+
+       if (!do_decrypt) {
+               if (product == NULL) {
+                       ERR("no product specified");
+                       goto out;
+               }
+
+               if (version == NULL) {
+                       ERR("no version specified");
+                       goto out;
+               }
+
+               if (strlen(product) > (ENC_PRODUCT_LEN - 1)) {
+                       ERR("product name '%s' is too long", product);
+                       goto out;
+               }
+
+               if (strlen(version) > (ENC_VERSION_LEN - 1)) {
+                       ERR("version '%s' is too long", version);
+                       goto out;
+               }
+       }
+
+       ret = 0;
+
+out:
+       return ret;
+}
+
+int main(int argc, char *argv[])
+{
+       int res = EXIT_FAILURE;
+       int err;
+
+       progname = basename(argv[0]);
+
+       while ( 1 ) {
+               int c;
+
+               c = getopt(argc, argv, "adi:m:o:hlp:v:k:r:s:");
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'd':
+                       do_decrypt = 1;
+                       break;
+               case 'i':
+                       ifname = optarg;
+                       break;
+               case 'l':
+                       longstate = 1;
+                       break;
+               case 'm':
+                       magic = optarg;
+                       break;
+               case 'o':
+                       ofname = optarg;
+                       break;
+               case 'p':
+                       product = optarg;
+                       break;
+               case 'v':
+                       version = optarg;
+                       break;
+               case 'k':
+                       crypt_key = optarg;
+                       break;
+               case 's':
+                       seed = strtoul(optarg, NULL, 16);
+                       break;
+               case 'h':
+                       usage(EXIT_SUCCESS);
+                       break;
+               default:
+                       usage(EXIT_FAILURE);
+                       break;
+               }
+       }
+
+       err = check_params();
+       if (err)
+               goto out;
+
+       if (do_decrypt)
+               err = decrypt_file();
+       else
+               err = encrypt_file();
+
+       if (err)
+               goto out;
+
+       res = EXIT_SUCCESS;
+
+out:
+       return res;
+}
diff --git a/trunk/tools/firmware-utils/src/buffalo-lib.c b/trunk/tools/firmware-utils/src/buffalo-lib.c
new file mode 100644 (file)
index 0000000..add3a7e
--- /dev/null
@@ -0,0 +1,480 @@
+/*
+ * Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include "buffalo-lib.h"
+
+static uint32_t crc32_table[256] =
+{
+       0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
+       0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
+       0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
+       0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
+       0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
+       0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
+       0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,
+       0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
+       0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
+       0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
+       0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,
+       0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
+       0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,
+       0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
+       0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
+       0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
+       0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,
+       0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
+       0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
+       0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
+       0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
+       0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
+       0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,
+       0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
+       0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
+       0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
+       0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
+       0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
+       0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
+       0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
+       0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686,
+       0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
+       0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
+       0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
+       0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
+       0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
+       0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47,
+       0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
+       0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
+       0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
+       0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,
+       0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
+       0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,
+       0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
+       0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
+       0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
+       0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,
+       0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
+       0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
+       0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
+       0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
+       0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
+       0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,
+       0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
+       0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
+       0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
+       0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
+       0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
+       0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
+       0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
+       0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0,
+       0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
+       0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
+       0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
+};
+
+int bcrypt_init(struct bcrypt_ctx *ctx, void *key, int keylen,
+               unsigned long state_len)
+{
+       unsigned char *state;
+       unsigned char *p = key;
+       unsigned long i, j;
+       unsigned long k = 0;
+
+       state = malloc(state_len);
+       if (state == NULL)
+               return -1;
+
+       ctx->i = 0;
+       ctx->j = 0;
+       ctx->state = state;
+       ctx->state_len = state_len;
+
+       for (i = 0; i < state_len; i++)
+               state[i] = i;
+
+       for(i = 0, j = 0; i < state_len; i++, j = (j + 1) % keylen) {
+               unsigned char t;
+
+               t = state[i];
+               k = (k + p[j] + t) % state_len;
+               state[i] = state[k];
+               state[k] = t;
+       }
+
+       return 0;
+}
+
+int bcrypt_process(struct bcrypt_ctx *ctx, unsigned char *src,
+                  unsigned char *dst, unsigned long len)
+{
+       unsigned char *state = ctx->state;
+       unsigned long state_len = ctx->state_len;
+       unsigned char i, j;
+       unsigned long k;
+
+       i = ctx->i;
+       j = ctx->j;
+
+       for (k = 0; k < len; k++) {
+               unsigned char t;
+
+               i = (i + 1) % state_len;
+               j = (j + state[i]) % state_len;
+               t = state[j];
+               state[j] = state[i];
+               state[i] = t;
+
+               dst[k] = src[k] ^ state[(state[i] + state[j]) % state_len];
+       }
+
+       ctx->i = i;
+       ctx->j = j;
+
+       return len;
+}
+
+void bcrypt_finish(struct bcrypt_ctx *ctx)
+{
+       if (ctx->state)
+               free(ctx->state);
+}
+
+int bcrypt_buf(unsigned char seed, unsigned char *key, unsigned char *src,
+              unsigned char *dst, unsigned long len, int longstate)
+{
+       unsigned char bckey[BCRYPT_MAX_KEYLEN + 1];
+       unsigned int keylen;
+       struct bcrypt_ctx ctx;
+       int ret;
+
+       /* setup decryption key */
+       keylen = strlen((char *) key);
+       bckey[0] = seed;
+       memcpy(&bckey[1], key, keylen);
+
+       keylen++;
+
+       ret = bcrypt_init(&ctx, bckey, keylen,
+                         (longstate) ? len : BCRYPT_DEFAULT_STATE_LEN);
+       if (ret)
+               return ret;
+
+       bcrypt_process(&ctx, src, dst, len);
+       bcrypt_finish(&ctx);
+
+       return 0;
+}
+
+uint32_t buffalo_csum(uint32_t csum, void *buf, unsigned long len)
+{
+       char *p = buf;
+
+       while (len--) {
+               int i;
+
+               csum ^= *p++;
+               for (i = 0; i < 8; i++)
+                       csum = (csum >> 1) ^ ((csum & 1) ? 0xedb88320ul : 0);
+       }
+
+       return csum;
+}
+
+uint32_t buffalo_crc(void *buf, unsigned long len)
+{
+       unsigned char *p = buf;
+       unsigned long t = len;
+       uint32_t crc = 0;
+
+       while (len--)
+               crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ *p++) & 0xFF];
+
+       while (t) {
+               crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ t) & 0xFF];
+               t >>= 8;
+       }
+
+       return ~crc;
+}
+
+unsigned long enc_compute_header_len(char *product, char *version)
+{
+       return ENC_MAGIC_LEN + 1 + strlen(product) + 1 +
+              strlen(version) + 1 + 3 * sizeof(uint32_t);
+}
+
+unsigned long enc_compute_buf_len(char *product, char *version,
+                                 unsigned long datalen)
+{
+       unsigned long ret;
+
+       ret = enc_compute_header_len(product, version);
+       ret += datalen + sizeof(uint32_t);
+       ret += (4 - ret % 4);
+
+       return ret;
+}
+
+static void put_be32(void *data, uint32_t val)
+{
+       unsigned char *p = data;
+
+       p[0] = (val >> 24) & 0xff;
+       p[1] = (val >> 16) & 0xff;
+       p[2] = (val >> 8) & 0xff;
+       p[3] = val & 0xff;
+}
+
+static uint32_t get_be32(void *data)
+{
+       unsigned char *p = data;
+
+       return (((uint32_t)p[0]) << 24) |
+              (((uint32_t)p[1]) << 16) |
+              (((uint32_t)p[2]) << 8) |
+              ((uint32_t)p[3]);
+}
+
+static int check_magic(void *magic)
+{
+       if (!memcmp("start", magic, ENC_MAGIC_LEN))
+               return 0;
+
+       if (!memcmp("asar1", magic, ENC_MAGIC_LEN))
+               return 0;
+
+       return -1;
+}
+
+int encrypt_buf(struct enc_param *ep, unsigned char *hdr,
+               unsigned char *data)
+{
+       unsigned char *p;
+       uint32_t len;
+       int err;
+       int ret = -1;
+       unsigned char s;
+
+       p = (unsigned char *) hdr;
+
+       /* setup magic */
+       len = strlen((char *) ep->magic) + 1;
+       memcpy(p, ep->magic, len);
+       p += len;
+
+       /* setup seed */
+       *p++ = ep->seed;
+
+       /* put product len */
+       len = strlen((char *) ep->product) + 1;
+       put_be32(p, len);
+       p += sizeof(uint32_t);
+
+       /* copy and crypt product name */
+       memcpy(p, ep->product, len);
+       err = bcrypt_buf(ep->seed, ep->key, p, p, len, ep->longstate);
+       if (err)
+               goto out;
+       s = *p;
+       p += len;
+
+       /* put version length */
+       len = strlen((char *) ep->version) + 1;
+       put_be32(p, len);
+       p += sizeof(uint32_t);
+
+       /* copy and crypt version */
+       memcpy(p, ep->version, len);
+       err = bcrypt_buf(s, ep->key, p, p, len, ep->longstate);
+       if (err)
+               goto out;
+       s = *p;
+       p += len;
+
+       /* put data length */
+       put_be32(p, ep->datalen);
+
+       /* encrypt data */
+       err = bcrypt_buf(s, ep->key, data, data, ep->datalen, ep->longstate);
+       if (err)
+               goto out;
+
+       /* put checksum */
+       put_be32(&data[ep->datalen], ep->csum);
+
+       ret = 0;
+
+out:
+       return ret;
+}
+
+int decrypt_buf(struct enc_param *ep, unsigned char *data,
+               unsigned long datalen)
+{
+       unsigned char *p;
+       uint32_t prod_len;
+       uint32_t ver_len;
+       uint32_t len;
+       uint32_t csum;
+       ssize_t remain;
+       int err;
+       int ret = -1;
+
+#define CHECKLEN(_l) do {              \
+       len = (_l);                     \
+       if (remain < len) {             \
+               goto out;               \
+       }                               \
+} while (0)
+
+#define INCP() do {                    \
+       p += len;                       \
+       remain -= len;                  \
+} while (0)
+
+       remain = datalen;
+       p = data;
+
+       CHECKLEN(ENC_MAGIC_LEN);
+       err = check_magic(p);
+       if (err)
+               goto out;
+       memcpy(ep->magic, p, ENC_MAGIC_LEN);
+       INCP();
+
+       CHECKLEN(1);
+       ep->seed = *p;
+       INCP();
+
+       CHECKLEN(sizeof(uint32_t));
+       prod_len = get_be32(p);
+       if (prod_len > ENC_PRODUCT_LEN)
+               goto out;
+       INCP();
+
+       CHECKLEN(prod_len);
+       memcpy(ep->product, p, prod_len);
+       INCP();
+
+       CHECKLEN(sizeof(uint32_t));
+       ver_len = get_be32(p);
+       if (ver_len > ENC_VERSION_LEN)
+               goto out;
+       INCP();
+
+       CHECKLEN(ver_len);
+       memcpy(ep->version, p, ver_len);
+       INCP();
+
+       CHECKLEN(sizeof(uint32_t));
+       ep->datalen = get_be32(p);
+       INCP();
+
+       /* decrypt data */
+       CHECKLEN(ep->datalen);
+       err = bcrypt_buf(ep->version[0], ep->key, p, data, ep->datalen,
+                        ep->longstate);
+       if (err)
+               goto out;
+       INCP();
+
+       CHECKLEN(sizeof(uint32_t));
+       ep->csum = get_be32(p);
+       INCP();
+
+       csum = buffalo_csum(ep->datalen, data, ep->datalen);
+       if (csum != ep->csum)
+               goto out;
+
+       /* decrypt product name */
+       err = bcrypt_buf(ep->product[0], ep->key, ep->version, ep->version,
+                        ver_len, ep->longstate);
+       if (err)
+               goto out;
+
+       /* decrypt version */
+       err = bcrypt_buf(ep->seed, ep->key, ep->product, ep->product, prod_len,
+                        ep->longstate);
+       if (err)
+               goto out;
+
+       ret = 0;
+out:
+       return ret;
+
+#undef CHECKLEN
+#undef INCP
+}
+
+ssize_t get_file_size(char *name)
+{
+       struct stat st;
+       int err;
+
+       err = stat(name, &st);
+       if (err)
+               return -1;
+
+       return st.st_size;
+}
+
+int read_file_to_buf(char *name, void *buf, ssize_t buflen)
+{
+       FILE *f;
+       size_t done;
+       int ret = -1;
+
+       f = fopen(name, "r");
+       if (f == NULL)
+               goto out;
+
+       errno = 0;
+       done = fread(buf, buflen, 1, f);
+       if (done != 1)
+               goto close;
+
+       ret = 0;
+
+close:
+       fclose(f);
+out:
+       return ret;
+}
+
+int write_buf_to_file(char *name, void *buf, ssize_t buflen)
+{
+       FILE *f;
+       size_t done;
+       int ret = -1;
+
+       f = fopen(name, "w");
+       if (f == NULL)
+               goto out;
+
+       errno = 0;
+       done = fwrite(buf, buflen, 1, f);
+       if (done != 1)
+               goto close;
+
+       ret = 0;
+
+close:
+       fflush(f);
+       fclose(f);
+       if (ret)
+               unlink(name);
+out:
+       return ret;
+}
diff --git a/trunk/tools/firmware-utils/src/buffalo-lib.h b/trunk/tools/firmware-utils/src/buffalo-lib.h
new file mode 100644 (file)
index 0000000..ba8a508
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ *  Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ *
+ */
+
+#ifndef _BUFFALO_LIB_H
+#define _BUFFALO_LIB_H
+
+#include <stdint.h>
+
+#define ARRAY_SIZE(_a) (sizeof((_a)) / sizeof((_a)[0]))
+#define BIT(_x)                (1UL << (_x))
+
+#define TAG_BRAND_LEN          32
+#define TAG_PRODUCT_LEN                32
+#define TAG_VERSION_LEN                8
+#define TAG_REGION_LEN         2
+#define TAG_LANGUAGE_LEN       8
+#define TAG_PLATFORM_LEN       8
+#define TAG_HWVER_LEN          4
+#define TAG_HWVER_VAL_LEN      4
+
+struct buffalo_tag {
+       unsigned char   product[TAG_PRODUCT_LEN];
+       unsigned char   brand[TAG_BRAND_LEN];
+       unsigned char   ver_major[TAG_VERSION_LEN];
+       unsigned char   ver_minor[TAG_VERSION_LEN];
+       unsigned char   region_code[2];
+       uint32_t        region_mask;
+       unsigned char   unknown0[2];
+       unsigned char   language[TAG_LANGUAGE_LEN];
+       unsigned char   platform[TAG_PLATFORM_LEN];
+       unsigned char   hwv[TAG_HWVER_LEN];
+       unsigned char   hwv_val[TAG_HWVER_VAL_LEN];
+       uint8_t         unknown1[24];
+
+       uint32_t        len;
+       uint32_t        crc;
+       uint32_t        base1;
+       uint32_t        base2;
+       uint32_t        data_len;
+       uint8_t         flag;
+       uint8_t         unknown2[3];
+} __attribute ((packed));
+
+struct buffalo_tag2 {
+       unsigned char   product[TAG_PRODUCT_LEN];
+       unsigned char   brand[TAG_BRAND_LEN];
+       unsigned char   ver_major[TAG_VERSION_LEN];
+       unsigned char   ver_minor[TAG_VERSION_LEN];
+       unsigned char   region_code[2];
+       uint32_t        region_mask;
+       unsigned char   unknown0[2];
+       unsigned char   language[TAG_LANGUAGE_LEN];
+       unsigned char   platform[TAG_PLATFORM_LEN];
+       unsigned char   hwv[TAG_HWVER_LEN];
+       unsigned char   hwv_val[TAG_HWVER_VAL_LEN];
+       uint8_t         unknown1[24];
+
+       uint32_t        total_len;
+       uint32_t        crc;
+       uint32_t        len1;
+       uint32_t        len2;
+       uint8_t         flag;
+       uint8_t         unknown2[3];
+} __attribute ((packed));
+
+#define ENC_PRODUCT_LEN                32
+#define ENC_VERSION_LEN                8
+#define ENC_MAGIC_LEN          6
+
+unsigned long enc_compute_header_len(char *product, char *version);
+unsigned long enc_compute_buf_len(char *product, char *version,
+                                 unsigned long datalen);
+
+struct enc_param {
+       unsigned char *key;
+       unsigned char magic[ENC_MAGIC_LEN];
+       unsigned char product[ENC_PRODUCT_LEN];
+       unsigned char version[ENC_VERSION_LEN];
+       unsigned char seed;
+       int longstate;
+       unsigned datalen;
+       uint32_t csum;
+};
+
+int encrypt_buf(struct enc_param *ep, unsigned char *hdr,
+               unsigned char *data);
+int decrypt_buf(struct enc_param *ep, unsigned char *data,
+               unsigned long datalen);
+
+#define BCRYPT_DEFAULT_STATE_LEN       256
+#define BCRYPT_MAX_KEYLEN              254
+
+struct bcrypt_ctx {
+       unsigned long i;
+       unsigned long j;
+       unsigned char *state;
+       unsigned long state_len;
+};
+
+int bcrypt_init(struct bcrypt_ctx *ctx, void *key, int keylen,
+               unsigned long state_len);
+int bcrypt_process(struct bcrypt_ctx *ctx, unsigned char *src,
+                  unsigned char *dst, unsigned long len);
+void bcrypt_finish(struct bcrypt_ctx *ctx);
+int bcrypt_buf(unsigned char seed, unsigned char *key, unsigned char *src,
+              unsigned char *dst, unsigned long len, int longstate);
+
+uint32_t buffalo_csum(uint32_t csum, void *buf, unsigned long len);
+uint32_t buffalo_crc(void *buf, unsigned long len);
+
+ssize_t get_file_size(char *name);
+int read_file_to_buf(char *name, void *buf, ssize_t buflen);
+int write_buf_to_file(char *name, void *buf, ssize_t buflen);
+
+#endif /* _BUFFALO_LIB_H */
diff --git a/trunk/tools/firmware-utils/src/buffalo-tag.c b/trunk/tools/firmware-utils/src/buffalo-tag.c
new file mode 100644 (file)
index 0000000..b5db72e
--- /dev/null
@@ -0,0 +1,374 @@
+/*
+ *  Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <libgen.h>
+#include <getopt.h>     /* for getopt() */
+#include <netinet/in.h>
+
+#include "buffalo-lib.h"
+
+#define ERR(fmt, ...) do { \
+       fflush(0); \
+       fprintf(stderr, "[%s] *** error: " fmt "\n", \
+                       progname, ## __VA_ARGS__ ); \
+} while (0)
+
+static char *region_table[] = {
+       "JP", "US", "EU", "AP", "TW", "KR"
+};
+
+#define MAX_INPUT_FILES        2
+
+static char *progname;
+static char *ifname[MAX_INPUT_FILES];
+static ssize_t fsize[MAX_INPUT_FILES];
+static int num_files;
+static char *ofname;
+static char *product;
+static char *brand;
+static char *language;
+static char *hwver;
+static char *platform;
+static int flag;
+static char *major;
+static char *minor = "1.01";
+static int skipcrc;
+static uint32_t base1;
+static uint32_t base2;
+static char *region_code;
+static uint32_t region_mask;
+static int num_regions;
+
+void usage(int status)
+{
+       FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+
+       fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+       fprintf(stream,
+"\n"
+"Options:\n"
+"  -a <platform>   set platform to <platform>\n"
+"  -b <brand>      set brand to <brand>\n"
+"  -c <base1>\n"
+"  -d <base2>\n"
+"  -f <flag>       set flag to <flag>\n"
+"  -i <file>       read input from the file <file>\n"
+"  -l <language>   set language to <language>\n"
+"  -m <version>    set minor version to <version>\n"
+"  -o <file>       write output to the file <file>\n"
+"  -p <product>    set product to <product>\n"
+"  -r <region>     set image region to <region>\n"
+"                 valid regions: JP, US, EU, AP, TW, KR, M_\n"
+"  -s              skip CRC calculation\n"
+"  -v <version>    set major version to <version>\n"
+"  -w <version>    set harwdware version to <version>\n"
+"  -h              show this screen\n"
+       );
+
+       exit(status);
+}
+
+static int check_params(void)
+{
+
+#define CHECKSTR(_var, _name, _len)    do {            \
+       if ((_var) == NULL) {                           \
+               ERR("no %s specified", (_name));        \
+               return -1;                              \
+       }                                               \
+       if ((_len) > 0 &&                               \
+           strlen((_var)) > ((_len) - 1)) {            \
+               ERR("%s is too long", (_name));         \
+               return -1;                              \
+       }                                               \
+} while (0)
+
+       if (num_files == 0)
+               ERR("no input files specified");
+
+       CHECKSTR(ofname, "output file", 0);
+       CHECKSTR(brand, "brand", TAG_BRAND_LEN);
+       CHECKSTR(product, "product", TAG_PRODUCT_LEN);
+       CHECKSTR(platform, "platform", TAG_PLATFORM_LEN);
+       CHECKSTR(major, "major version", TAG_VERSION_LEN);
+       CHECKSTR(minor, "minor version", TAG_VERSION_LEN);
+       CHECKSTR(language, "language", TAG_LANGUAGE_LEN);
+
+       if (hwver)
+               CHECKSTR(hwver, "hardware version", 2);
+
+       if (num_regions == 0) {
+               ERR("no region code specified");
+               return -1;
+       }
+
+       return 0;
+
+#undef CHECKSTR
+}
+
+static int process_region(char *reg)
+{
+       int i;
+
+       if (strlen(reg) != 2) {
+               ERR("invalid region code '%s'", reg);
+               return -1;
+       }
+
+       if (strcmp(reg, "M_") == 0) {
+               region_code = reg;
+               region_mask |= ~0;
+               num_regions = 32;
+               return 0;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(region_table); i++)
+               if (strcmp(reg, region_table[i]) == 0) {
+                       region_code = reg;
+                       region_mask |= 1 << i;
+                       num_regions++;
+                       return 0;
+               }
+
+       ERR("unknown region code '%s'", reg);
+       return -1;
+}
+
+static int process_ifname(char *name)
+{
+       if (num_files >= ARRAY_SIZE(ifname)) {
+               ERR("too many input files specified");
+               return -1;
+       }
+
+       ifname[num_files++] = name;
+       return 0;
+}
+
+static void fixup_tag(unsigned char *buf, ssize_t buflen)
+{
+       struct buffalo_tag *tag = (struct buffalo_tag *) buf;
+
+       memset(tag, '\0', sizeof(*tag));
+
+       memcpy(tag->brand, brand, strlen(brand));
+       memcpy(tag->product, product, strlen(product));
+       memcpy(tag->platform, platform, strlen(platform));
+       memcpy(tag->ver_major, major, strlen(major));
+       memcpy(tag->ver_minor, minor, strlen(minor));
+       memcpy(tag->language, language, strlen(language));
+
+       if (num_regions > 1) {
+               tag->region_code[0] = 'M';
+               tag->region_code[1] = '_';
+               tag->region_mask = htonl(region_mask);
+       } else {
+               memcpy(tag->region_code, region_code, 2);
+       }
+
+       tag->len = htonl(buflen);
+       tag->data_len = htonl(fsize[0]);
+       tag->base1 = htonl(base1);
+       tag->base2 = htonl(base2);
+       tag->flag = flag;
+
+       if (hwver) {
+               memcpy(tag->hwv, "hwv", 3);
+               memcpy(tag->hwv_val, hwver, strlen(hwver));
+       }
+
+       if (!skipcrc)
+               tag->crc = htonl(buffalo_crc(buf, buflen));
+}
+
+static void fixup_tag2(unsigned char *buf, ssize_t buflen)
+{
+       struct buffalo_tag2 *tag = (struct buffalo_tag2 *) buf;
+
+       memset(tag, '\0', sizeof(*tag));
+
+       memcpy(tag->brand, brand, strlen(brand));
+       memcpy(tag->product, product, strlen(product));
+       memcpy(tag->platform, platform, strlen(platform));
+       memcpy(tag->ver_major, major, strlen(major));
+       memcpy(tag->ver_minor, minor, strlen(minor));
+       memcpy(tag->language, language, strlen(language));
+
+       if (num_regions > 1) {
+               tag->region_code[0] = 'M';
+               tag->region_code[1] = '_';
+               tag->region_mask = htonl(region_mask);
+       } else {
+               memcpy(tag->region_code, region_code, 2);
+       }
+
+       tag->total_len = htonl(buflen);
+       tag->len1 = htonl(fsize[0]);
+       tag->len2 = htonl(fsize[1]);
+       tag->flag = flag;
+
+       if (hwver) {
+               memcpy(tag->hwv, "hwv", 3);
+               memcpy(tag->hwv_val, hwver, strlen(hwver));
+       }
+
+       if (!skipcrc)
+               tag->crc = htonl(buffalo_crc(buf, buflen));
+}
+
+static int tag_file(void)
+{
+       unsigned char *buf;
+       ssize_t offset;
+       ssize_t hdrlen;
+       ssize_t buflen;
+       int err;
+       int ret = -1;
+       int i;
+
+       if (num_files == 1)
+               hdrlen = sizeof(struct buffalo_tag);
+       else
+               hdrlen = sizeof(struct buffalo_tag2);
+
+       buflen = hdrlen;
+
+       for (i = 0; i < num_files; i++) {
+               fsize[i] = get_file_size(ifname[i]);
+               if (fsize[i] < 0) {
+                       ERR("unable to get size of '%s'", ifname[i]);
+                       goto out;
+               }
+               buflen += fsize[i];
+       }
+
+       buf = malloc(buflen);
+       if (!buf) {
+               ERR("no memory for buffer\n");
+               goto out;
+       }
+
+       offset = hdrlen;
+       for (i = 0; i < num_files; i++) {
+               err = read_file_to_buf(ifname[i], buf + offset, fsize[i]);
+               if (err) {
+                       ERR("unable to read from file '%s'", ifname[i]);
+                       goto free_buf;
+               }
+
+               offset += fsize[i];
+       }
+
+       if (num_files == 1)
+               fixup_tag(buf, buflen);
+       else
+               fixup_tag2(buf, buflen);
+
+       err = write_buf_to_file(ofname, buf, buflen);
+       if (err) {
+               ERR("unable to write to file '%s'", ofname);
+               goto free_buf;
+       }
+
+       ret = 0;
+
+free_buf:
+       free(buf);
+out:
+       return ret;
+}
+
+int main(int argc, char *argv[])
+{
+       int res = EXIT_FAILURE;
+       int err;
+
+       progname = basename(argv[0]);
+
+       while ( 1 ) {
+               int c;
+
+               c = getopt(argc, argv, "a:b:c:d:f:hi:l:m:o:p:r:sv:w:");
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'a':
+                       platform = optarg;
+                       break;
+               case 'b':
+                       brand = optarg;
+                       break;
+               case 'c':
+                       base1 = strtoul(optarg, NULL, 16);
+                       break;
+               case 'd':
+                       base2 = strtoul(optarg, NULL, 16);
+                       break;
+               case 'f':
+                       flag = strtoul(optarg, NULL, 2);
+                       break;
+               case 'i':
+                       err = process_ifname(optarg);
+                       if (err)
+                               goto out;
+                       break;
+               case 'l':
+                       language = optarg;
+                       break;
+               case 'm':
+                       minor = optarg;
+                       break;
+               case 'o':
+                       ofname = optarg;
+                       break;
+               case 'p':
+                       product = optarg;
+                       break;
+               case 'r':
+                       err = process_region(optarg);
+                       if (err)
+                               goto out;
+                       break;
+               case 's':
+                       skipcrc = 1;
+                       break;
+               case 'v':
+                       major = optarg;
+                       break;
+               case 'w':
+                       hwver = optarg;
+                       break;
+               case 'h':
+                       usage(EXIT_SUCCESS);
+                       break;
+               default:
+                       usage(EXIT_FAILURE);
+                       break;
+               }
+       }
+
+       err = check_params();
+       if (err)
+               goto out;
+
+       err = tag_file();
+       if (err)
+               goto out;
+
+       res = EXIT_SUCCESS;
+
+out:
+       return res;
+}
diff --git a/trunk/tools/firmware-utils/src/buffalo-tftp.c b/trunk/tools/firmware-utils/src/buffalo-tftp.c
new file mode 100644 (file)
index 0000000..087f995
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <libgen.h>
+#include <getopt.h>     /* for getopt() */
+#include <stdarg.h>
+
+#include "buffalo-lib.h"
+
+#define ERR(fmt, args...) do { \
+       fflush(0); \
+       fprintf(stderr, "[%s] *** error: " fmt "\n", \
+                       progname, ## args ); \
+} while (0)
+
+static char *progname;
+static char *ifname;
+static char *ofname;
+static int do_decrypt;
+
+void usage(int status)
+{
+       FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+
+       fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+       fprintf(stream,
+"\n"
+"Options:\n"
+"  -d              decrypt instead of encrypt\n"
+"  -i <file>       read input from the file <file>\n"
+"  -o <file>       write output to the file <file>\n"
+"  -h              show this screen\n"
+       );
+
+       exit(status);
+}
+
+static const unsigned char *crypt_key1 = (unsigned char *)
+       "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+static const unsigned char *crypt_key2 = (unsigned char *)
+       "XYZ0123hijklmnopqABCDEFGHrstuvabcdefgwxyzIJKLMSTUVW456789NOPQR";
+
+static void crypt_header(unsigned char *buf, ssize_t len,
+                        const unsigned char *key1, const unsigned char *key2)
+{
+       ssize_t i;
+
+       for (i = 0; i < len; i++) {
+               unsigned int j;
+
+               for (j = 0; key1[j]; j++)
+                       if (buf[i] == key1[j]) {
+                               buf[i] = key2[j];
+                               break;
+                       }
+       }
+}
+
+static int crypt_file(void)
+{
+       unsigned char *buf = NULL;
+       ssize_t src_len;
+       int err;
+       int ret = -1;
+
+       src_len = get_file_size(ifname);
+       if (src_len < 0) {
+               ERR("unable to get size of '%s'", ifname);
+               goto out;
+       }
+
+       buf = malloc(src_len);
+       if (buf == NULL) {
+               ERR("no memory for the buffer");
+               goto out;
+       }
+
+       err = read_file_to_buf(ifname, buf, src_len);
+       if (err) {
+               ERR("unable to read from file '%s'", ifname);
+               goto out;
+       }
+
+       if (do_decrypt)
+               crypt_header(buf, 512, crypt_key2, crypt_key1);
+       else
+               crypt_header(buf, 512, crypt_key1, crypt_key2);
+
+       err = write_buf_to_file(ofname, buf, src_len);
+       if (err) {
+               ERR("unable to write to file '%s'", ofname);
+               goto out;
+       }
+
+       ret = 0;
+
+out:
+       free(buf);
+       return ret;
+}
+
+static int check_params(void)
+{
+       int ret = -1;
+
+       if (ifname == NULL) {
+               ERR("no input file specified");
+               goto out;
+       }
+
+       if (ofname == NULL) {
+               ERR("no output file specified");
+               goto out;
+       }
+
+       ret = 0;
+
+out:
+       return ret;
+}
+
+int main(int argc, char *argv[])
+{
+       int res = EXIT_FAILURE;
+       int err;
+
+       progname = basename(argv[0]);
+
+       while ( 1 ) {
+               int c;
+
+               c = getopt(argc, argv, "di:o:h");
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'd':
+                       do_decrypt = 1;
+                       break;
+               case 'i':
+                       ifname = optarg;
+                       break;
+               case 'o':
+                       ofname = optarg;
+                       break;
+               case 'h':
+                       usage(EXIT_SUCCESS);
+                       break;
+               default:
+                       usage(EXIT_FAILURE);
+                       break;
+               }
+       }
+
+       err = check_params();
+       if (err)
+               goto out;
+
+       err = crypt_file();
+       if (err)
+               goto out;
+
+       res = EXIT_SUCCESS;
+
+out:
+       return res;
+}
diff --git a/trunk/tools/firmware-utils/src/csysimg.h b/trunk/tools/firmware-utils/src/csysimg.h
new file mode 100644 (file)
index 0000000..65ab062
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ *
+ *  Copyright (C) 2007,2009 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  This program was based on the code found in various Linux
+ *  source tarballs released by Edimax for it's devices.
+ *  Original author: David Hsu <davidhsu@realtek.com.tw>
+ *
+ *  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., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA  02110-1301, USA.
+ */
+
+#define SIG_LEN                4
+
+#define ADM_CODE_ADDR  0x80500000
+#define ADM_WEBP_ADDR  0x10000
+#define ADM_WEBP_SIZE  0x10000
+#define ADM_BOOT_SIZE  0x8000
+#define ADM_CONF_SIZE  0x8000
+#define ADM_BOOT_SIG   "\x00\x60\x1A\x40"
+
+
+/*
+ * Generic signatures
+ */
+#define SIG_CSYS       "CSYS"
+#define SIG_CONF       "HS\x00\x00"
+#define SIG_BOOT_RTL   "\x00\x00\x40\x21"
+
+/*
+ * Web page signatures
+ */
+#define SIG_BR6104K    "WB4K"
+#define SIG_BR6104KP   "WBKP"
+#define SIG_BR6104Wg   "WBGW"
+#define SIG_BR6104IPC  "WBIP"
+#define SIG_BR6114WG   SIG_BR6104IPC
+#define SIG_BR6524K    "2-K-"
+#define SIG_BR6524KP   "2-KP"  /* FIXME: valid? */
+#define SIG_BR6524N    "WNRA"
+#define SIG_BR6524WG   "2-WG"  /* FIXME: valid? */
+#define SIG_BR6524WP   "2-WP"  /* FIXME: valid? */
+#define SIG_BR6541K    "4--K"
+#define SIG_BR6541KP   "4-KP"  /* FIXME: valid? */
+#define SIG_BR6541WP   "4-WP"  /* FIXME: valid? */
+#define SIG_C54BSR4    SIG_BR6104IPC
+#define SIG_EW7207APg  "EWAS"
+#define SIG_PS1205UWg  "4000"
+#define SIG_PS3205U    "5010"
+#define SIG_PS3205UWg  "5011"
+#define SIG_RALINK     "RNRA"
+#define SIG_5GXI       "5GXI"  /* fake signature */
+
+#define SIG_H2BR4      SIG_BR6524K
+#define SIG_H2WR54G    SIG_BR6524WG
+
+#define SIG_XRT401D    SIG_BR6104K
+#define SIG_XRT402D    SIG_BR6524K
+
+/*
+ * CSYS image file header
+ */
+struct csys_header {
+       unsigned char sig[SIG_LEN];
+       uint32_t addr;
+       uint32_t size;
+};
diff --git a/trunk/tools/firmware-utils/src/cyg_crc.h b/trunk/tools/firmware-utils/src/cyg_crc.h
new file mode 100644 (file)
index 0000000..7b59803
--- /dev/null
@@ -0,0 +1,109 @@
+//==========================================================================
+//
+//      crc.h
+//
+//      Interface for the CRC algorithms.
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2002 Andrew Lunn
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    Andrew Lunn
+// Contributors: Andrew Lunn
+// Date:         2002-08-06
+// Purpose:
+// Description:
+//
+// This code is part of eCos (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#ifndef _SERVICES_CRC_CRC_H_
+#define _SERVICES_CRC_CRC_H_
+
+#if 0
+#include <cyg/infra/cyg_type.h>
+#else
+#include <stdint.h>
+typedef uint32_t cyg_uint32;
+typedef uint16_t cyg_uint16;
+#endif
+
+#ifndef __externC
+# ifdef __cplusplus
+#  define __externC extern "C"
+# else
+#  define __externC extern
+# endif
+#endif
+
+// Compute a CRC, using the POSIX 1003 definition
+
+__externC cyg_uint32
+cyg_posix_crc32(unsigned char *s, int len);
+
+// Gary S. Brown's 32 bit CRC
+
+__externC cyg_uint32
+cyg_crc32(unsigned char *s, int len);
+
+// Gary S. Brown's 32 bit CRC, but accumulate the result from a
+// previous CRC calculation
+
+__externC cyg_uint32
+cyg_crc32_accumulate(cyg_uint32 crc, unsigned char *s, int len);
+
+// Ethernet FCS Algorithm
+
+__externC cyg_uint32
+cyg_ether_crc32(unsigned char *s, int len);
+
+// Ethernet FCS algorithm, but accumulate the result from a previous
+// CRC calculation.
+
+__externC cyg_uint32
+cyg_ether_crc32_accumulate(cyg_uint32 crc, unsigned char *s, int len);
+
+// 16 bit CRC with polynomial x^16+x^12+x^5+1
+
+__externC cyg_uint16
+cyg_crc16(unsigned char *s, int len);
+
+#endif // _SERVICES_CRC_CRC_H_
+
+
+
diff --git a/trunk/tools/firmware-utils/src/cyg_crc16.c b/trunk/tools/firmware-utils/src/cyg_crc16.c
new file mode 100644 (file)
index 0000000..8b37352
--- /dev/null
@@ -0,0 +1,110 @@
+//==========================================================================
+//
+//      crc16.c
+//
+//      16 bit CRC with polynomial x^16+x^12+x^5+1
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002 Gary Thomas
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    gthomas
+// Contributors: gthomas,asl
+// Date:         2001-01-31
+// Purpose:      
+// Description:  
+//              
+// This code is part of eCos (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#if 0
+#include <cyg/crc/crc.h>
+#else
+#include "cyg_crc.h"
+#endif
+
+// Table of CRC constants - implements x^16+x^12+x^5+1
+static const cyg_uint16 crc16_tab[] = {
+    0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 
+    0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 
+    0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 
+    0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 
+    0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 
+    0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 
+    0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 
+    0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 
+    0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 
+    0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 
+    0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 
+    0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 
+    0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 
+    0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 
+    0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 
+    0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 
+    0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 
+    0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, 
+    0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 
+    0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 
+    0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 
+    0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 
+    0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 
+    0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 
+    0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 
+    0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 
+    0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 
+    0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 
+    0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 
+    0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 
+    0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 
+    0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0, 
+};
+
+cyg_uint16
+cyg_crc16(unsigned char *buf, int len)
+{
+    int i;
+    cyg_uint16 cksum;
+
+    cksum = 0;
+    for (i = 0;  i < len;  i++) {
+        cksum = crc16_tab[((cksum>>8) ^ *buf++) & 0xFF] ^ (cksum << 8);
+    }
+    return cksum;
+}
+
diff --git a/trunk/tools/firmware-utils/src/cyg_crc32.c b/trunk/tools/firmware-utils/src/cyg_crc32.c
new file mode 100644 (file)
index 0000000..9462598
--- /dev/null
@@ -0,0 +1,172 @@
+//==========================================================================
+//
+//      crc32.c
+//
+//      Gary S. Brown's 32 bit CRC
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002 Gary Thomas
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    gthomas
+// Contributors: gthomas,asl
+// Date:         2001-01-31
+// Purpose:      
+// Description:  
+//              
+// This code is part of eCos (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#if 0
+#include <cyg/crc/crc.h>
+#else
+#include "cyg_crc.h"
+#endif
+
+  /* ====================================================================== */
+  /*  COPYRIGHT (C) 1986 Gary S. Brown.  You may use this program, or       */
+  /*  code or tables extracted from it, as desired without restriction.     */
+  /*                                                                        */
+  /*  First, the polynomial itself and its table of feedback terms.  The    */
+  /*  polynomial is                                                         */
+  /*  X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0   */
+  /*                                                                        */
+  /* ====================================================================== */
+
+static const cyg_uint32 crc32_tab[] = {
+      0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+      0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+      0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+      0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+      0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+      0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+      0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+      0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+      0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+      0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+      0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+      0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+      0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+      0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+      0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+      0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+      0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+      0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+      0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+      0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+      0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+      0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+      0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+      0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+      0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+      0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+      0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+      0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+      0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+      0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+      0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+      0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+      0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+      0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+      0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+      0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+      0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+      0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+      0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+      0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+      0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+      0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+      0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+      0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+      0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+      0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+      0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+      0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+      0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+      0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+      0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+      0x2d02ef8dL
+   };
+
+/* This is the standard Gary S. Brown's 32 bit CRC algorithm, but
+   accumulate the CRC into the result of a previous CRC. */
+cyg_uint32 
+cyg_crc32_accumulate(cyg_uint32 crc32val, unsigned char *s, int len)
+{
+  int i;
+
+  for (i = 0;  i < len;  i++) {
+    crc32val = crc32_tab[(crc32val ^ s[i]) & 0xff] ^ (crc32val >> 8);
+  }
+  return crc32val;
+}
+
+/* This is the standard Gary S. Brown's 32 bit CRC algorithm */
+cyg_uint32
+cyg_crc32(unsigned char *s, int len)
+{
+  return (cyg_crc32_accumulate(0,s,len));
+}
+
+/* Return a 32-bit CRC of the contents of the buffer accumulating the
+   result from a previous CRC calculation. This uses the Ethernet FCS
+   algorithm.*/
+cyg_uint32
+cyg_ether_crc32_accumulate(cyg_uint32 crc32val, unsigned char *s, int len)
+{
+  int i;
+
+  if (s == 0) return 0L;
+  
+  crc32val = crc32val ^ 0xffffffff;
+  for (i = 0;  i < len;  i++) {
+      crc32val = crc32_tab[(crc32val ^ s[i]) & 0xff] ^ (crc32val >> 8);
+  }
+  return crc32val ^ 0xffffffff;
+}
+
+/* Return a 32-bit CRC of the contents of the buffer, using the
+   Ethernet FCS algorithm. */
+cyg_uint32
+cyg_ether_crc32(unsigned char *s, int len)
+{
+  return cyg_ether_crc32_accumulate(0,s,len);
+}
+
+
diff --git a/trunk/tools/firmware-utils/src/dgfirmware.c b/trunk/tools/firmware-utils/src/dgfirmware.c
new file mode 100644 (file)
index 0000000..5ff3b69
--- /dev/null
@@ -0,0 +1,376 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+
+#define IMG_SIZE     0x3e0000
+
+#define KERNEL_START 0x020000
+#define KERNEL_SIZE  0x0b0000
+
+#define ROOTFS_START 0x0d0000
+#define ROOTFS_SIZE  0x30ffb2
+
+char* app_name;
+
+
+
+
+void print_usage(void)
+{
+  fprintf(stderr, "usage: dgfirmware [<opts>] <img>\n");
+  fprintf(stderr, "  <img>               firmware image filename\n");
+  fprintf(stderr, "  <opts>  -h          print this message\n");
+  fprintf(stderr, "          -f          fix the checksum\n");
+  fprintf(stderr, "          -x  <file>  extract the rootfs file to <file>\n");
+  fprintf(stderr, "          -xk <file>  extract the kernel to <file>\n");
+  fprintf(stderr, "          -m  <file>  merge in rootfs fil\e from <file>\n");
+  fprintf(stderr, "          -k  <file>  merge in kernel from <file>\n");
+  fprintf(stderr, "          -w  <file>  write back the modified firmware\n");
+}
+
+
+unsigned char* read_img(const char *fname)
+{
+  FILE *fp;
+  int size;
+  unsigned char *img;
+
+  fp = fopen(fname, "rb");
+  if (fp == NULL) {
+    perror(app_name);
+    exit(-1);
+  }
+
+  fseek(fp, 0, SEEK_END);
+  size = ftell(fp);
+  
+  if (size != IMG_SIZE) {
+    fprintf(stderr, "%s: image file has wrong size\n", app_name);
+    fclose(fp);
+    exit(-1);
+  }
+
+  rewind(fp);
+
+  img = malloc(IMG_SIZE);
+  if (img == NULL) {
+    perror(app_name);
+    fclose(fp);
+    exit(-1);
+  }
+
+  if (fread(img, 1, IMG_SIZE, fp) != IMG_SIZE) {
+    fprintf(stderr, "%s: can't read image file\n", app_name);
+    fclose(fp);
+    exit(-1);
+  }
+
+  fclose(fp);
+  return img;
+}
+
+
+void write_img(unsigned char* img, const char *fname)
+{
+  FILE *fp;
+
+  fp = fopen(fname, "wb");
+  if (fp == NULL) {
+    perror(app_name);
+    exit(-1);
+  }
+
+  if (fwrite(img, 1, IMG_SIZE, fp) != IMG_SIZE) {
+    fprintf(stderr, "%s: can't write image file\n", app_name);
+    fclose(fp);
+    exit(-1);
+  }
+}
+
+
+void write_rootfs(unsigned char* img, const char *fname)
+{
+  FILE *fp;
+
+  fp = fopen(fname, "wb");
+  if (fp == NULL) {
+    perror(app_name);
+    exit(-1);
+  }
+  
+  if (fwrite(img+ROOTFS_START, 1, ROOTFS_SIZE, fp) != ROOTFS_SIZE) {
+    fprintf(stderr, "%s: can't write image file\n", app_name);
+    fclose(fp);
+    exit(-1);
+  }
+}
+
+
+void write_kernel(unsigned char* img, const char *fname)
+{
+  FILE *fp;
+
+  fp = fopen(fname, "wb");
+  if (fp == NULL) {
+    perror(app_name);
+    exit(-1);
+  }
+  
+  if (fwrite(img+KERNEL_START, 1, KERNEL_SIZE, fp) != KERNEL_SIZE) {
+    fprintf(stderr, "%s: can't write kernel file\n", app_name);
+    fclose(fp);
+    exit(-1);
+  }
+}
+
+
+unsigned char* read_rootfs(unsigned char* img, const char *fname)
+{
+  FILE *fp;
+  int size;
+  int i;
+
+  for (i=ROOTFS_START; i<ROOTFS_START+ROOTFS_SIZE; i++)
+    img[i] = 0xff;
+
+  fp = fopen(fname, "rb");
+  if (fp == NULL) {
+    perror(app_name);
+    exit(-1);
+  }
+
+  fseek(fp, 0, SEEK_END);
+  size = ftell(fp);
+  
+  if (size > ROOTFS_SIZE) {
+    fprintf(stderr, "%s: rootfs image file is too big\n", app_name);
+    fclose(fp);
+    exit(-1);
+  }
+
+  rewind(fp);
+
+  if (fread(img+ROOTFS_START, 1, size, fp) != size) {
+    fprintf(stderr, "%s: can't read rootfs image file\n", app_name);
+    fclose(fp);
+    exit(-1);
+  }
+
+  fclose(fp);
+  return img;
+}
+
+
+unsigned char* read_kernel(unsigned char* img, const char *fname)
+{
+  FILE *fp;
+  int size;
+  int i;
+
+  for (i=KERNEL_START; i<KERNEL_START+KERNEL_SIZE; i++)
+    img[i] = 0xff;
+
+  fp = fopen(fname, "rb");
+  if (fp == NULL) {
+    perror(app_name);
+    exit(-1);
+  }
+
+  fseek(fp, 0, SEEK_END);
+  size = ftell(fp);
+  
+  if (size > KERNEL_SIZE) {
+    fprintf(stderr, "%s: kernel binary file is too big\n", app_name);
+    fclose(fp);
+    exit(-1);
+  }
+
+  rewind(fp);
+
+  if (fread(img+KERNEL_START, 1, size, fp) != size) {
+    fprintf(stderr, "%s: can't read kernel file\n", app_name);
+    fclose(fp);
+    exit(-1);
+  }
+
+  fclose(fp);
+  return img;
+}
+
+
+int get_checksum(unsigned char* img)
+{
+  short unsigned s;
+
+  s = img[0x3dfffc] + (img[0x3dfffd]<<8);
+
+  return s;
+}
+
+
+void set_checksum(unsigned char*img, unsigned short sum)
+{
+  img[0x3dfffc] = sum & 0xff;
+  img[0x3dfffd] = (sum>>8) & 0xff;
+}
+
+
+int compute_checksum(unsigned char* img)
+{
+  int i;
+  short s=0;
+
+  for (i=0; i<0x3dfffc; i++)
+    s += img[i];
+
+  return s;
+}
+
+
+int main(int argc, char* argv[])
+{
+  char *img_fname     = NULL;
+  char *rootfs_fname  = NULL;
+  char *kernel_fname  = NULL;
+  char *new_img_fname = NULL;
+
+  int do_fix_checksum = 0;
+  int do_write        = 0;
+  int do_write_rootfs = 0;
+  int do_read_rootfs  = 0;
+  int do_write_kernel = 0;
+  int do_read_kernel  = 0;
+
+  int i;
+  unsigned char *img;
+  unsigned short img_checksum;
+  unsigned short real_checksum;
+
+  app_name = argv[0];
+
+  for (i=1; i<argc; i++) {
+    if (!strcmp(argv[i], "-h")) {
+      print_usage();
+      return 0;
+    }
+    else if (!strcmp(argv[i], "-f")) {
+      do_fix_checksum = 1;
+    }
+    else if (!strcmp(argv[i], "-x")) {
+      if (i+1 >= argc) {
+       fprintf(stderr, "%s: missing argument\n", app_name);
+       return -1;
+      }
+      do_write_rootfs = 1;
+      rootfs_fname = argv[i+1];
+      i++;
+    }
+    else if (!strcmp(argv[i], "-xk")) {
+      if (i+1 >= argc) {
+       fprintf(stderr, "%s: missing argument\n", app_name);
+       return -1;
+      }
+      do_write_kernel = 1;
+      kernel_fname = argv[i+1];
+      i++;
+    }
+    else if (!strcmp(argv[i], "-m")) {
+      if (i+1 >= argc) {
+       fprintf(stderr, "%s: missing argument\n", app_name);
+       return -1;
+      }
+      do_read_rootfs = 1;
+      rootfs_fname = argv[i+1];
+      i++;
+    }
+    else if (!strcmp(argv[i], "-k")) {
+      if (i+1 >= argc) {
+       fprintf(stderr, "%s: missing argument\n", app_name);
+       return -1;
+      }
+      do_read_kernel = 1;
+      kernel_fname = argv[i+1];
+      i++;
+    }
+    else if (!strcmp(argv[i], "-w")) {
+      if (i+1 >= argc) {
+       fprintf(stderr, "%s: missing argument\n", app_name);
+       return -1;
+      }
+      do_write = 1;
+      new_img_fname = argv[i+1];
+      i++;
+    }
+    else if (img_fname != 0) {
+      fprintf(stderr, "%s: too many arguments\n", app_name);
+      return -1;
+    }
+    else {
+      img_fname = argv[i];
+    }
+  }
+
+  if (img_fname == NULL) {
+    fprintf(stderr, "%s: missing argument\n", app_name);
+    return -1;
+  }
+
+  if ((do_read_rootfs && do_write_rootfs) ||
+      (do_read_kernel && do_write_kernel)) {
+    fprintf(stderr, "%s: conflictuous options\n", app_name);
+    return -1;
+  }
+
+  printf ("** Read firmware file\n");
+  img = read_img(img_fname);
+
+  printf ("Firmware product: %s\n", img+0x3dffbd);
+  printf ("Firmware version: 1.%02d.%02d\n", (img[0x3dffeb] & 0x7f), img[0x3dffec]);
+
+  if (do_write_rootfs) {
+    printf ("** Write rootfs file\n");
+    write_rootfs(img, rootfs_fname);
+  }
+
+  if (do_write_kernel) {
+    printf ("** Write kernel file\n");
+    write_kernel(img, kernel_fname);
+  }
+
+  if (do_read_rootfs) {
+    printf ("** Read rootfs file\n");
+    read_rootfs(img, rootfs_fname);
+    do_fix_checksum = 1;
+  }
+
+  if (do_read_kernel) {
+    printf ("** Read kernel file\n");
+    read_kernel(img, kernel_fname);
+    do_fix_checksum = 1;
+  }
+
+  img_checksum = get_checksum(img);
+  real_checksum = compute_checksum(img);
+  
+  printf ("image checksum = %04x\n", img_checksum);
+  printf ("real checksum  = %04x\n", real_checksum);
+
+  if (do_fix_checksum) {
+    if (img_checksum != real_checksum) {
+      printf ("** Bad Checksum, fix it\n");
+      set_checksum(img, real_checksum);
+    }
+    else {
+      printf ("** Checksum is correct, good\n");
+    }
+  }
+
+  if (do_write) {
+    printf ("** Write image file\n");
+    write_img(img, new_img_fname);
+  }
+
+  free(img);
+  return 0;
+}
+
diff --git a/trunk/tools/firmware-utils/src/dgn3500sum.c b/trunk/tools/firmware-utils/src/dgn3500sum.c
new file mode 100644 (file)
index 0000000..00a0c5f
--- /dev/null
@@ -0,0 +1,167 @@
+/* **************************************************************************
+
+   This program creates a modified 16bit checksum used for the Netgear
+   DGN3500 series routers. The difference between this and a standard
+   checksum is that every 0x100 bytes added 0x100 have to be subtracted
+   from the sum.
+
+   (C) 2013 Marco Antonio Mauro <marcus90 at gmail.com>
+
+   Based on previous unattributed work.
+
+   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
+
+ ************************************************************************* */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+unsigned char PidDataWW[70] =
+{
+    0x73, 0x45, 0x72, 0x43, 0x6F, 0x4D, 0x6D, 0x00, 0x00, 0x00, 0x00, 0x59, 0x50, 0x35, 0x37, 0x32,
+    0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x37,
+    0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73,
+    0x45, 0x72, 0x43, 0x6F, 0x4D, 0x6D,
+} ;
+
+unsigned char PidDataDE[70] =
+{
+    0x73, 0x45, 0x72, 0x43, 0x6F, 0x4D, 0x6D, 0x00, 0x00, 0x00, 0x00, 0x59, 0x50, 0x35, 0x37, 0x32,
+    0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x37,
+    0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73,
+    0x45, 0x72, 0x43, 0x6F, 0x4D, 0x6D,
+} ;
+
+unsigned char PidDataNA[70] =
+{
+    0x73, 0x45, 0x72, 0x43, 0x6F, 0x4D, 0x6D, 0x00, 0x00, 0x00, 0x00, 0x59, 0x50, 0x35, 0x37, 0x32,
+    0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x37,
+    0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73,
+    0x45, 0x72, 0x43, 0x6F, 0x4D, 0x6D,
+} ;
+
+/* *******************************************************************
+   Reads the file into memory and returns pointer to the buffer. */
+static char *readfile(char *filename, int *size)
+{
+       FILE            *fp;
+       char            *buffer;
+       struct stat     info;
+
+       if (stat(filename,&info)!=0)
+               return NULL;
+
+       if ((fp=fopen(filename,"r"))==NULL)
+               return NULL;
+
+       buffer=NULL;
+       for (;;)
+       {
+               if ((buffer=(char *)malloc(info.st_size+1))==NULL)
+                       break;
+
+               if (fread(buffer,1,info.st_size,fp)!=info.st_size)
+               {
+                       free(buffer);
+                       buffer=NULL;
+                       break;
+               }
+
+               buffer[info.st_size]='\0';
+               if(size) *size = info.st_size;
+
+               break;
+       }
+
+       (void)fclose(fp);
+
+       return buffer;
+}
+
+
+/* ******************************************************************* */
+int main(int argc, char** argv)
+{
+  unsigned long start, i;
+  char *endptr, *buffer, *p;
+  int count;  // size of file in bytes
+  unsigned short sum, sum1;
+  char sumbuf[9];
+
+  if(argc < 3) {
+    printf("ERROR: Argument missing!\n\nUsage %s filename starting offset in hex [PID code]\n\n", argv[0]);
+    return 1;
+  }
+
+
+  FILE *fp = fopen(argv[1], "a");
+  if(!fp) {
+    printf("ERROR: File not writeable!\n");
+    return 1;
+  }
+  if(argc = 4)
+  {
+    printf("%s: PID type: %s\n", argv[0], argv[3]);
+    if(strcmp(argv[3], "DE")==0)
+      fwrite(PidDataDE, sizeof(PidDataDE), sizeof(char), fp);  /* write DE pid */
+    else if(strcmp(argv[3], "NA")==0)
+      fwrite(PidDataNA, sizeof(PidDataNA), sizeof(char), fp);  /* write NA pid */
+    else /* if(strcmp(argv[3], "WW")) */
+      fwrite(PidDataWW, sizeof(PidDataWW), sizeof(char), fp);  /* write WW pid */
+  }
+  else
+    fwrite(PidDataWW, sizeof(PidDataWW), sizeof(char), fp);  /* write WW pid if unspecified */
+
+  fclose(fp);
+
+  /* Read the file to calculate the checksums */
+  buffer = readfile(argv[1], &count);
+  if(!buffer) {
+    printf("ERROR: File %s not found!\n", argv[1]);
+    return 1;
+  }
+
+  p = buffer;
+  for(i = 0; i < count; i++)
+  {
+       sum += p[i];
+  }
+
+  start = strtol(argv[2], &endptr, 16);
+  p = buffer+start;
+  sum1 = 0;
+  for(i = 0; i < count - start; i++)
+  {
+       sum1 += p[i];
+  }
+
+  sprintf(sumbuf,"%04X%04X",sum1,sum);
+  /* Append the 2 checksums to end of file */
+  fp = fopen(argv[1], "a");
+  if(!fp) {
+    printf("ERROR: File not writeable!\n");
+    return 1;
+  }
+  fwrite(sumbuf, 8, sizeof(char), fp);
+  fclose(fp);
+  free(buffer);
+  return 0;
+}
diff --git a/trunk/tools/firmware-utils/src/edimax_fw_header.c b/trunk/tools/firmware-utils/src/edimax_fw_header.c
new file mode 100644 (file)
index 0000000..b85e3a1
--- /dev/null
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2014 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>     /* for unlink() */
+#include <libgen.h>
+#include <getopt.h>     /* for getopt() */
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#define MAX_MAGIC_LEN          16
+#define MAX_MODEL_LEN          32
+#define MAX_VERSION_LEN                14
+#define MAX_MTD_NAME_LEN       16
+
+#define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
+
+struct edimax_header {
+       char            magic[MAX_MAGIC_LEN];
+       char            model[MAX_MODEL_LEN];
+       unsigned char   force;
+       unsigned char   header_csum;
+       unsigned char   data_csum;
+       uint32_t        data_size;
+       uint32_t        start_addr;
+       uint32_t        end_addr;
+       char            fw_version[MAX_VERSION_LEN];
+       unsigned char   type;
+       char            mtd_name[MAX_MTD_NAME_LEN];
+} __attribute__ ((packed));
+
+/*
+ * Globals
+ */
+static char *ofname;
+static char *ifname;
+static char *progname;
+
+static char *model;
+static char *magic = "eDiMaX";
+static char *fw_version = "";
+static char *mtd_name;
+static int force;
+static uint32_t start_addr;
+static uint32_t end_addr;
+static uint8_t image_type;
+static int data_size;
+
+/*
+ * Message macros
+ */
+#define ERR(fmt, ...) do { \
+       fflush(0); \
+       fprintf(stderr, "[%s] *** error: " fmt "\n", \
+                       progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERRS(fmt, ...) do { \
+       int save = errno; \
+       fflush(0); \
+       fprintf(stderr, "[%s] *** error: " fmt " (%s)\n", \
+                       progname, ## __VA_ARGS__, strerror(save)); \
+} while (0)
+
+#define DBG(fmt, ...) do { \
+       fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
+} while (0)
+
+static void usage(int status)
+{
+       FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+
+       fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+       fprintf(stream,
+"\n"
+"Options:\n"
+"  -e <addr>       set end addr to <addr>\n"
+"  -f              set force flag\n"
+"  -h              show this screen\n"
+"  -i <file>       read input data from the file <file>\n"
+"  -o <file>       write output to the file <file>\n"
+"  -m <model>      set model to <model>\n"
+"  -M <magic>      set image magic to <magic>\n"
+"  -n <name>       set MTD device name to <name>\n"
+"  -s <addr>       set start address to <addr>\n"
+"  -t <type>       set image type to <type>\n"
+"  -v <version>    set firmware version to <version>\n"
+       );
+
+       exit(status);
+}
+
+int
+str2u32(char *arg, uint32_t *val)
+{
+       char *err = NULL;
+       uint32_t t;
+
+       errno=0;
+       t = strtoul(arg, &err, 0);
+       if (errno || (err==arg) || ((err != NULL) && *err)) {
+               return -1;
+       }
+
+       *val = t;
+       return 0;
+}
+
+int
+str2u8(char *arg, uint8_t *val)
+{
+       char *err = NULL;
+       uint32_t t;
+
+       errno=0;
+       t = strtoul(arg, &err, 0);
+       if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x100)) {
+               return -1;
+       }
+
+       *val = t & 0xFF;
+       return 0;
+}
+
+static int get_file_size(char *name)
+{
+       struct stat st;
+       int res;
+
+       res = stat(name, &st);
+       if (res){
+               ERRS("stat failed on %s", name);
+               return -1;
+       }
+
+       return st.st_size;
+}
+
+static int read_to_buf(char *name, char *buf, int buflen)
+{
+       FILE *f;
+       int ret = EXIT_FAILURE;
+
+       f = fopen(name, "r");
+       if (f == NULL) {
+               ERRS("could not open \"%s\" for reading", name);
+               goto out;
+       }
+
+       errno = 0;
+       fread(buf, buflen, 1, f);
+       if (errno != 0) {
+               ERRS("unable to read from file \"%s\"", name);
+               goto out_close;
+       }
+
+       ret = EXIT_SUCCESS;
+
+out_close:
+       fclose(f);
+out:
+       return ret;
+}
+
+static int check_options(void)
+{
+#define CHKSTR(_name, _msg)                            \
+       do {                                            \
+               if (_name == NULL) {                    \
+                       ERR("no %s specified", _msg);   \
+                       return -1;                      \
+               }                                       \
+       } while (0)
+
+#define CHKSTRLEN(_name, _msg)                                         \
+       do {                                                            \
+               int field_len;                                          \
+               CHKSTR(_name, _msg);                                    \
+               field_len = FIELD_SIZEOF(struct edimax_header, _name) - 1; \
+               if (strlen(_name) > field_len) {                        \
+                       ERR("'%s' is too long, max %s length is %d",    \
+                           _name, _msg, field_len);                    \
+                       return -1;                                      \
+               }                                                       \
+       } while (0)
+
+       CHKSTR(ofname, "output file");
+       CHKSTR(ifname, "input file");
+
+       CHKSTRLEN(magic, "magic");
+       CHKSTRLEN(model, "model");
+       CHKSTRLEN(mtd_name, "MTD device name");
+       CHKSTRLEN(fw_version, "firware version");
+
+       data_size = get_file_size(ifname);
+       if (data_size < 0)
+               return -1;
+
+       return 0;
+}
+
+static int write_fw(char *data, int len)
+{
+       FILE *f;
+       int ret = EXIT_FAILURE;
+
+       f = fopen(ofname, "w");
+       if (f == NULL) {
+               ERRS("could not open \"%s\" for writing", ofname);
+               goto out;
+       }
+
+       errno = 0;
+       fwrite(data, len, 1, f);
+       if (errno) {
+               ERRS("unable to write output file");
+               goto out_flush;
+       }
+
+       DBG("firmware file \"%s\" completed", ofname);
+
+       ret = EXIT_SUCCESS;
+
+out_flush:
+       fflush(f);
+       fclose(f);
+       if (ret != EXIT_SUCCESS) {
+               unlink(ofname);
+       }
+out:
+       return ret;
+}
+
+static unsigned char checksum(unsigned char *p, unsigned len)
+{
+       unsigned char csum = 0;
+
+       while (len--)
+               csum += *p++;
+
+       csum ^= 0xb9;
+
+       return csum;
+}
+
+static int build_fw(void)
+{
+       int buflen;
+       char *buf;
+       char *data;
+       struct edimax_header *hdr;
+       int ret = EXIT_FAILURE;
+
+       buflen = sizeof(struct edimax_header) + data_size;
+
+       buf = malloc(buflen);
+       if (!buf) {
+               ERR("no memory for buffer\n");
+               goto out;
+       }
+
+       data = buf + sizeof(struct edimax_header);
+
+       /* read input file */
+       ret = read_to_buf(ifname, data, data_size);
+       if (ret)
+               goto out_free_buf;
+
+       /* fill firmware header */
+       hdr = (struct edimax_header *)buf;
+       memset(hdr, 0, sizeof(struct edimax_header));
+
+       strncpy(hdr->model, model, sizeof(hdr->model));
+       strncpy(hdr->magic, magic, sizeof(hdr->magic));
+       strncpy(hdr->fw_version, fw_version, sizeof(hdr->fw_version));
+       strncpy(hdr->mtd_name, mtd_name, sizeof(hdr->mtd_name));
+
+       hdr->force = force;
+       hdr->start_addr = htonl(start_addr);
+       hdr->end_addr = htonl(end_addr);
+       hdr->data_size = htonl(data_size);
+       hdr->type = image_type;
+
+       hdr->data_csum = checksum((unsigned char *)data, data_size);
+       hdr->header_csum = checksum((unsigned char *)hdr,
+                                   sizeof(struct edimax_header));
+
+       ret = write_fw(buf, buflen);
+       if (ret)
+               goto out_free_buf;
+
+       ret = EXIT_SUCCESS;
+
+out_free_buf:
+       free(buf);
+out:
+       return ret;
+}
+
+int main(int argc, char *argv[])
+{
+       int ret = EXIT_FAILURE;
+
+       progname = basename(argv[0]);
+
+       while (1) {
+               int c;
+
+               c = getopt(argc, argv, "e:fhi:o:m:M:n:s:t:v:");
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'e':
+                       if (str2u32(optarg, &end_addr)) {
+                               ERR("%s is invalid '%s'",
+                                   "end address", optarg);
+                               goto out;
+                       }
+                       break;
+               case 'f':
+                       force = 1;
+                       break;
+               case 'i':
+                       ifname = optarg;
+                       break;
+               case 'h':
+                       usage(EXIT_SUCCESS);
+                       break;
+               case 'o':
+                       ofname = optarg;
+                       break;
+               case 'm':
+                       model = optarg;
+                       break;
+               case 'M':
+                       magic = optarg;
+                       break;
+               case 'n':
+                       mtd_name = optarg;
+                       break;
+               case 's':
+                       if (str2u32(optarg, &start_addr)) {
+                               ERR("%s is invalid '%s'",
+                                   "start address", optarg);
+                               goto out;
+                       }
+                       break;
+               case 't':
+                       if (str2u8(optarg, &image_type)) {
+                               ERR("%s is invalid '%s'",
+                                   "image type", optarg);
+                               goto out;
+                       }
+                       break;
+               case 'v':
+                       fw_version = optarg;
+                       break;
+               default:
+                       usage(EXIT_FAILURE);
+                       break;
+               }
+       }
+
+       ret = check_options();
+       if (ret)
+               goto out;
+
+       ret = build_fw();
+
+out:
+       return ret;
+}
diff --git a/trunk/tools/firmware-utils/src/encode_crc.c b/trunk/tools/firmware-utils/src/encode_crc.c
new file mode 100644 (file)
index 0000000..647fb92
--- /dev/null
@@ -0,0 +1,151 @@
+/* **************************************************************************
+
+   This program creates a CRC checksum and encodes the file that is named
+   in the command line.
+   
+   Compile with:  gcc encode_crc.c -Wall -o encode_crc
+
+   Author:     Michael Margraf  (michael.margraf@freecom.com)
+   Copyright:  Freecom Technology GmbH, Berlin, 2004
+               www.freecom.com
+
+  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
+
+ ************************************************************************* */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+// *******************************************************************
+// CCITT polynom G(x)=x^16+x^12+x^5+1
+#define POLYNOM  0x1021
+
+// CRC algorithm with MSB first
+int make_crc16(int crc, char new)
+{
+  int i;
+  crc = crc ^ (((int)new) << 8);
+  
+  for(i=0; i<8; i++) {  // work on 8 bits in "new"
+    crc <<= 1;          // MSBs first
+    if(crc & 0x10000)  crc ^= POLYNOM;
+  }
+  return crc & 0xFFFF;
+}
+
+// *******************************************************************
+// Reads the file "filename" into memory and returns pointer to the buffer.
+static char *readfile(char *filename, int *size)
+{
+       FILE            *fp;
+       char            *buffer;
+       struct stat     info;
+       
+       if (stat(filename,&info)!=0)
+               return NULL;
+
+       if ((fp=fopen(filename,"r"))==NULL)
+               return NULL;
+
+       buffer=NULL;
+       for (;;)
+       {
+               if ((buffer=(char *)malloc(info.st_size+1))==NULL)
+                       break;
+
+               if (fread(buffer,1,info.st_size,fp)!=info.st_size)
+               {
+                       free(buffer);
+                       buffer=NULL;
+                       break;
+               }
+
+               buffer[info.st_size]='\0';
+               if(size) *size = info.st_size;
+
+               break;
+       }
+
+       (void)fclose(fp);
+
+       return buffer;
+}
+
+
+// *******************************************************************
+int main(int argc, char** argv)
+{
+  if(argc < 3) {
+    printf("ERROR: Argument missing!\n\n");
+    return 1;
+  }
+
+  int count;  // size of file in bytes
+  char *p, *master = readfile(argv[1], &count);
+  if(!master) {
+    printf("ERROR: File not found!\n");
+    return 1;
+  }
+
+  int crc = 0xFFFF, z;
+
+  p = master;
+  for(z=0; z<count; z++)
+    crc = make_crc16(crc, *(p++));  // calculate CRC
+  short crc16 = (short)crc;
+
+       /*
+  if(argc > 2) {   // with flag for device recognition ?
+    p = argv[2];
+    for(z=strlen(p); z>0; z--) {
+      crc ^= (int)(*p);
+      *(p++) = (char)crc;  // encode device flag
+    }
+  }
+       */
+
+  p = master;
+  for(z=0; z<count; z++) {
+    crc ^= (int)(*p);
+    *(p++) = (char)crc;  // encode file
+  }
+
+
+  // write encoded file...
+  FILE *fp = fopen(argv[2], "w");
+  if(!fp) {
+    printf("ERROR: File not writeable!\n");
+    return 1;
+  }
+
+  if(argc > 3) {  // add flag for device recognition ?
+    fwrite(argv[3], strlen(argv[3]), sizeof(char), fp);
+  }
+  else {
+    // Device is an FSG, so byte swap (IXP4xx is big endian)
+    crc16 = ((crc16 >> 8) & 0xFF) | ((crc16 << 8) & 0xFF00);
+  }
+
+  fwrite(&crc16, 1, sizeof(short), fp);     // first write CRC
+
+  fwrite(master, count, sizeof(char), fp);  // write content
+  fclose(fp);
+
+  free(master);
+  return 0;
+}
diff --git a/trunk/tools/firmware-utils/src/fix-u-media-header.c b/trunk/tools/firmware-utils/src/fix-u-media-header.c
new file mode 100644 (file)
index 0000000..21f184e
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ *  Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>     /* for unlink() */
+#include <libgen.h>
+#include <getopt.h>     /* for getopt() */
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include "cyg_crc.h"
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#define IH_MAGIC       0x27051956      /* Image Magic Number           */
+#define IH_NMLEN       32              /* Image Name Length            */
+
+#define UM_MAGIC       0x55525F46
+#define UM_HEADER_LEN  12
+
+/*
+ * all data in network byte order (aka natural aka bigendian)
+ */
+struct u_media_header {
+       uint32_t        ih_magic;       /* Image Header Magic Number    */
+       uint32_t        ih_hcrc;        /* Image Header CRC Checksum    */
+       uint32_t        ih_time;        /* Image Creation Timestamp     */
+       uint32_t        ih_size;        /* Image Data Size              */
+       uint32_t        ih_load;        /* Data  Load  Address          */
+       uint32_t        ih_ep;          /* Entry Point Address          */
+       uint32_t        ih_dcrc;        /* Image Data CRC Checksum      */
+       uint8_t         ih_os;          /* Operating System             */
+       uint8_t         ih_arch;        /* CPU architecture             */
+       uint8_t         ih_type;        /* Image Type                   */
+       uint8_t         ih_comp;        /* Compression Type             */
+       uint8_t         ih_name[IH_NMLEN - UM_HEADER_LEN]; /* Image Name                */
+
+       uint32_t        ih_UMedia_magic;        /* U-Media magic number */
+       uint32_t        ih_UMedia_boardID;      /* U-Media board ID     */
+       uint8_t         ih_UMedia_imageType;    /* U-Media image type */
+       uint8_t         ih_UMedia_LoadDefault;  /* U-Media load to factory default setting */
+       uint8_t         ih_UMedia_temp1;        /* U-Media didn't use this tag */
+       uint8_t         ih_UMedia_temp2;        /* U-Media didn't use this tag */
+} __attribute__ ((packed));
+
+struct if_info {
+       char            *file_name;     /* name of the file */
+       uint32_t        file_size;      /* length of the file */
+};
+
+static char *progname;
+static char *ofname;
+static struct if_info if_info;
+static int factory_defaults;
+static uint32_t board_id;
+static uint8_t image_type;
+
+/*
+ * Message macros
+ */
+#define ERR(fmt, ...) do { \
+       fflush(0); \
+       fprintf(stderr, "[%s] *** error: " fmt "\n", \
+                       progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERRS(fmt, ...) do { \
+       int save = errno; \
+       fflush(0); \
+       fprintf(stderr, "[%s] *** error: " fmt " (%s)\n", \
+                       progname, ## __VA_ARGS__, strerror(save)); \
+} while (0)
+
+#define DBG(fmt, ...) do { \
+       fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
+} while (0)
+
+static void usage(int status)
+{
+       FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+
+       fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+       fprintf(stream,
+"\n"
+"Options:\n"
+"  -B <board_id>   set board ID to <board_id>\n"
+"  -i <file>       read input from the file <file>\n"
+"  -F              load factory defaults\n"
+"  -o <file>       write output to the file <file>\n"
+"  -T <type>       set image type to <type>\n"
+"  -h              show this screen\n"
+       );
+
+       exit(status);
+}
+
+static int str2u32(char *arg, uint32_t *val)
+{
+       char *err = NULL;
+       uint32_t t;
+
+       errno=0;
+       t = strtoul(arg, &err, 0);
+       if (errno || (err==arg) || ((err != NULL) && *err)) {
+               return -1;
+       }
+
+       *val = t;
+       return 0;
+}
+
+static int str2u8(char *arg, uint8_t *val)
+{
+       char *err = NULL;
+       uint32_t t;
+
+       errno=0;
+       t = strtoul(arg, &err, 0);
+       if (errno || (err==arg) || ((err != NULL) && *err)) {
+               return -1;
+       }
+
+       if (t > 255)
+               return -1;
+
+       *val = t;
+       return 0;
+}
+
+static int get_file_stat(struct if_info *fdata)
+{
+       struct stat st;
+       int res;
+
+       if (fdata->file_name == NULL)
+               return 0;
+
+       res = stat(fdata->file_name, &st);
+       if (res){
+               ERRS("stat failed on %s", fdata->file_name);
+               return res;
+       }
+
+       fdata->file_size = st.st_size;
+       return 0;
+}
+
+static int read_to_buf(struct if_info *fdata, char *buf)
+{
+       FILE *f;
+       int ret = EXIT_FAILURE;
+
+       f = fopen(fdata->file_name, "r");
+       if (f == NULL) {
+               ERRS("could not open \"%s\" for reading", fdata->file_name);
+               goto out;
+       }
+
+       errno = 0;
+       fread(buf, fdata->file_size, 1, f);
+       if (errno != 0) {
+               ERRS("unable to read from file \"%s\"", fdata->file_name);
+               goto out_close;
+       }
+
+       ret = EXIT_SUCCESS;
+
+out_close:
+       fclose(f);
+out:
+       return ret;
+}
+
+static int check_options(void)
+{
+       int ret;
+
+       if (ofname == NULL) {
+               ERR("no %s specified", "output file");
+               return -1;
+       }
+
+       if (if_info.file_name == NULL) {
+               ERR("no %s specified", "input file");
+               return -1;
+       }
+
+       ret = get_file_stat(&if_info);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int write_fw(char *data, int len)
+{
+       FILE *f;
+       int ret = EXIT_FAILURE;
+
+       f = fopen(ofname, "w");
+       if (f == NULL) {
+               ERRS("could not open \"%s\" for writing", ofname);
+               goto out;
+       }
+
+       errno = 0;
+       fwrite(data, len, 1, f);
+       if (errno) {
+               ERRS("unable to write output file");
+               goto out_flush;
+       }
+
+       ret = EXIT_SUCCESS;
+
+out_flush:
+       fflush(f);
+       fclose(f);
+       if (ret != EXIT_SUCCESS) {
+               unlink(ofname);
+       }
+out:
+       return ret;
+}
+
+static int fix_header(void)
+{
+       int buflen;
+       char *buf;
+       uint32_t crc, crc_orig;
+       struct u_media_header *hdr;
+       int ret = EXIT_FAILURE;
+
+       buflen = if_info.file_size;
+       if (buflen < sizeof(*hdr)) {
+               ERR("invalid input file\n");
+               return ret;
+       }
+
+       buf = malloc(buflen);
+       if (!buf) {
+               ERR("no memory for buffer\n");
+               goto out;
+       }
+
+       ret = read_to_buf(&if_info, buf);
+       if (ret)
+               goto out_free_buf;
+
+       hdr = (struct u_media_header *) buf;
+       if (ntohl(hdr->ih_magic) != IH_MAGIC) {
+               ERR("invalid input file, bad magic\n");
+               goto out_free_buf;
+       }
+
+       /* verify header CRC */
+       crc_orig = ntohl(hdr->ih_hcrc);
+       hdr->ih_hcrc = 0;
+       crc = cyg_ether_crc32((unsigned char *)hdr, sizeof(*hdr));
+       if (crc != crc_orig) {
+               ERR("invalid input file, bad header CRC\n");
+               goto out_free_buf;
+       }
+
+       hdr->ih_name[IH_NMLEN - UM_HEADER_LEN - 1] = '\0';
+
+       /* set U-Media specific fields */
+       hdr->ih_UMedia_magic = htonl(UM_MAGIC);
+       hdr->ih_UMedia_boardID = htonl(board_id);
+       hdr->ih_UMedia_imageType = image_type;
+       hdr->ih_UMedia_LoadDefault = (factory_defaults) ? 1 : 0;
+
+       /* update header CRC */
+       crc = cyg_ether_crc32((unsigned char *)hdr, sizeof(*hdr));
+       hdr->ih_hcrc = htonl(crc);
+
+       ret = write_fw(buf, buflen);
+       if (ret)
+               goto out_free_buf;
+
+       DBG("U-Media header fixed in \"%s\"", ofname);
+
+       ret = EXIT_SUCCESS;
+
+out_free_buf:
+       free(buf);
+out:
+       return ret;
+}
+
+int main(int argc, char *argv[])
+{
+       int ret = EXIT_FAILURE;
+
+       progname = basename(argv[0]);
+
+       while (1) {
+               int c;
+
+               c = getopt(argc, argv, "B:Fi:o:T:h");
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'B':
+                       if (str2u32(optarg, &board_id)) {
+                               ERR("%s is invalid '%s'",
+                                   "board ID", optarg);
+                               goto out;
+                       }
+                       break;
+               case 'T':
+                       if (str2u8(optarg, &image_type)) {
+                               ERR("%s is invalid '%s'",
+                                   "image type", optarg);
+                               goto out;
+                       }
+                       break;
+               case 'F':
+                       factory_defaults = 1;
+                       break;
+               case 'i':
+                       if_info.file_name = optarg;
+                       break;
+               case 'o':
+                       ofname = optarg;
+                       break;
+               case 'h':
+                       usage(EXIT_SUCCESS);
+                       break;
+               default:
+                       usage(EXIT_FAILURE);
+                       break;
+               }
+       }
+
+       ret = check_options();
+       if (ret)
+               goto out;
+
+       ret = fix_header();
+
+out:
+       return ret;
+}
diff --git a/trunk/tools/firmware-utils/src/fw.h b/trunk/tools/firmware-utils/src/fw.h
new file mode 100644 (file)
index 0000000..e37859c
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ *  * Copyright (C) 2007 Ubiquiti Networks, Inc.
+ *   *
+ *    * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *                 */
+
+#ifndef FW_INCLUDED
+#define FW_INCLUDED
+
+#include <sys/types.h>
+
+#define MAGIC_HEADER   "OPEN"
+#define MAGIC_PART     "PART"
+#define MAGIC_END      "END."
+
+#define MAGIC_LENGTH   4
+
+typedef struct header {
+       char magic[MAGIC_LENGTH];
+       char version[256];
+       u_int32_t crc;
+       u_int32_t pad;
+} __attribute__ ((packed)) header_t;
+
+typedef struct part {
+       char magic[MAGIC_LENGTH];
+       char name[16];
+       char pad[12];
+       u_int32_t memaddr;
+       u_int32_t index;
+       u_int32_t baseaddr;
+       u_int32_t entryaddr;
+       u_int32_t data_size;
+       u_int32_t part_size;
+} __attribute__ ((packed)) part_t;
+
+typedef struct part_crc {
+       u_int32_t crc;
+       u_int32_t pad;
+} __attribute__ ((packed)) part_crc_t;
+
+typedef struct signature {
+       char magic[MAGIC_LENGTH];
+       u_int32_t crc;
+       u_int32_t pad;
+} __attribute__ ((packed)) signature_t;
+
+#define VERSION "1.2"
+
+#define INFO(...) fprintf(stdout, __VA_ARGS__)
+#define ERROR(...) fprintf(stderr, "ERROR: "__VA_ARGS__)
+#define WARN(...) fprintf(stderr, "WARN: "__VA_ARGS__)
+#define DEBUG(...) do {\
+        if (debug) \
+                fprintf(stdout, "DEBUG: "__VA_ARGS__); \
+} while (0);
+
+#endif
diff --git a/trunk/tools/firmware-utils/src/hcsmakeimage.c b/trunk/tools/firmware-utils/src/hcsmakeimage.c
new file mode 100644 (file)
index 0000000..603ea88
--- /dev/null
@@ -0,0 +1,181 @@
+#include <stdlib.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <string.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <libgen.h>
+#include "bcmalgo.h"
+
+
+int flag_print_version;
+int flag_print_help;
+int flag_compress;
+
+uint16_t sa2100_magic  = 0x2100;
+uint16_t sa3349_magic  = 0x3349;
+uint32_t default_date = 0x00000000; //A long time ago in a galaxy far far away....
+uint32_t default_load_address = 0x80010000; //The default load_address for the firmware image
+
+static void print_help ( const char* ename )
+{
+       printf ( "Firmware image packer and calculator for broadcom-based modems.\n" );
+       printf ( "Part of bcm-utils package.\n" );
+       printf ( "(c) 2009 Necromant (http://necromant.ath.cx). Thanks to Luke-jr for his initial work.\n" );
+       printf ( "usage: %s [options]\n", ename );
+       printf ( "Valid options are:\n" );
+       printf ( "--magic_bytes=value \t- specify magic bytes at the beginning of the image. default - 3349\n" );
+       printf ( "\t\t\t these can be sa2100 (for DPC2100 modem),\n\t\t\t sa3349 (haxorware guys use this one for some reason),\n\t\t\t or a custom hex value e.g. 0xFFFF\n" );
+       printf ( "--compress \t\t - Make use of LZMA (weird!) compression (Doesn't work yet).\n" );
+       printf ( "--rev_maj=value\t\t - major revision number. default 0\n" );
+       printf ( "--rev_min=value\t\t - minor revision number default 0\n" );
+       printf ( "--filename=value\t - use this filename in header instead of default (input filename)\n" );
+       printf ( "--ldaddress=value\t - hex value of the target load address. defaults to 0x80010000\n" );
+       printf ( "--input_file=value\t - What file are we packing?\n" );
+       printf ( "--output_file=value\t - What file shall we write? (default: image.bin)\n" );
+#ifdef _HAX0RSTYLE
+       printf ( "--credz\t - Give some credz!\n" );
+#endif
+       printf ( "\n" );
+}
+
+
+int main ( int argc, char** argv )
+{
+       if ( argc<2 )
+       {
+               print_help ( argv[0] );
+       }
+
+       static struct option long_options[] =
+       {
+               {"magic_bytes",          required_argument,   0,        'm'},
+               {"rev_maj",        required_argument,   0,      'j'},
+               {"rev_min",       required_argument,   0,     'n'},
+               {"ldaddress",       required_argument,   0,     'l'},
+               {"filename",       required_argument,   0,     'f'},
+               {"input_file",       required_argument,   0,     'i'},
+               {"output_file",       required_argument,   0,     'o'},
+               {"compress",     no_argument,       &flag_compress,    'c'},
+               {"version",     no_argument,       &flag_print_version,    'v'},
+               {"help",        no_argument,       &flag_print_help,    'h'},
+               {0, 0, 0, 0}
+       };
+       int option_index = 0;
+       int opt_result=0;
+       char* filename=NULL;
+       char* input=NULL;
+       char* magic=NULL;
+       char* major=NULL;
+       char* minor=NULL;
+       char* ldaddr=NULL;
+       char* output=NULL;
+
+       while ( opt_result>=0 )
+       {
+               opt_result = getopt_long ( argc, argv, "m:j:n:f:i:o:vh", long_options, &option_index );
+               switch ( opt_result )
+               {
+                       case 0:
+                               printf ( "o!\n" );
+                               break;
+                       case 'h':
+                               print_help ( argv[0] );
+                               break;
+                       case 'l':
+                               ldaddr=optarg;
+                               break;
+                       case 'f':
+                               filename=optarg;
+                               break;
+                       case 'i':
+                               input=optarg;
+                               break;
+                       case 'o':
+                               output=optarg;
+                               break;
+                       case 'm':
+                               magic=optarg;
+                               break;
+                       case 'j':
+                               major=optarg;
+                               break;
+                       case 'n':
+                               minor=optarg;
+                               break;
+               }
+       }
+       if ( input==NULL )
+       {
+               printf ( "Telepaths are still on holidays. I guess you should tell me what file should I process.\n\n" );
+               exit ( 1 );
+       }
+       if ( access ( input,R_OK ) !=0 )
+       {
+               printf ( "I cannot access the file %s. Is it there? Am I allowed?\n\n", input );
+               exit ( 1 );
+       }
+       uint32_t magicnum=sa2100_magic;
+
+       if ( magic )
+       {
+               if ( strcmp ( magic,"sa2100" ) ==0 ) magicnum=sa2100_magic; else
+                               if ( strcmp ( magic,"sa3349" ) ==0 ) magicnum=sa3349_magic; else
+                       {
+                               sscanf ( magic, "0x%04X", &magicnum );
+                       }
+       }
+       unsigned int majrev=0;
+       if ( major )
+       {
+               sscanf ( major, "%d", &majrev );
+       }
+       unsigned int minrev=0;
+       if ( minor )
+       {
+               sscanf ( minor, "%d", &minrev );
+       }
+       uint32_t ldaddress = default_load_address;
+       if ( ldaddr )
+       {
+               sscanf ( ldaddr, "0x%08X", &ldaddress );
+       }
+       char* dupe = strdup(input);
+       char* fname = basename ( dupe );
+       if ( filename )
+       {
+               fname = filename;
+       }
+       struct timeval tm;
+       gettimeofday ( &tm,NULL );
+       struct stat buf;
+       stat ( input,&buf );
+       ldr_header_t* head = construct_header ( magicnum, (uint16_t) majrev, (uint16_t) minrev, ( uint32_t ) tm.tv_sec, ( uint32_t ) buf.st_size, ldaddress, fname, get_file_crc ( input ) );
+       free(dupe);
+       //uint32_t magic, uint16_t rev_maj,uint16_t rev_min, uint32_t build_date, uint32_t filelen, uint32_t ldaddress, const char* filename, uint32_t crc
+       //FILE* fd = fopen ("/tftpboot/haxorware11rev32.bin","r");
+       //fread(head,sizeof(ldr_header_t),1,fd);
+       char* filebuffer = malloc ( buf.st_size+10 );
+       FILE* fd = fopen ( input,"r" );
+       fread ( filebuffer, 1, buf.st_size,fd );
+       if (!output)
+               {
+               output = malloc(strlen(input+5));
+               strcpy(output,input);
+               strcat(output,".bin");
+               }
+       dump_header ( head );
+       FILE* fd_out = fopen ( output,"w+" );
+       if (!fd_out)
+               {
+               fprintf(stderr, "Failed to open output file: %s\n", output);
+               exit(1);
+               }
+       fwrite ( head,1,sizeof ( ldr_header_t ),fd_out );
+       fwrite ( filebuffer,1,buf.st_size,fd_out );
+       printf("Firmware image %s is ready\n", output);
+       return 0;
+}
diff --git a/trunk/tools/firmware-utils/src/imagetag.c b/trunk/tools/firmware-utils/src/imagetag.c
new file mode 100644 (file)
index 0000000..e34890f
--- /dev/null
@@ -0,0 +1,489 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2008 Axel Gembe <ago@bastart.eu.org>
+ * Copyright (C) 2009-2010 Daniel Dickinson <librecmc@cshore.neomailbox.net>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+
+#include "bcm_tag.h"
+#include "imagetag_cmdline.h"
+#include "cyg_crc.h"
+
+#define DEADCODE                       0xDEADC0DE
+
+/* Kernel header */
+struct kernelhdr {
+       uint32_t                loadaddr;       /* Kernel load address */
+       uint32_t                entry;          /* Kernel entry point address */
+       uint32_t                lzmalen;        /* Compressed length of the LZMA data that follows */
+};
+
+static char pirellitab[NUM_PIRELLI][BOARDID_LEN] = PIRELLI_BOARDS;
+
+void int2tag(char *tag, uint32_t value) {
+  uint32_t network = htonl(value);
+  memcpy(tag, (char *)(&network), 4);
+}
+
+uint32_t compute_crc32(uint32_t crc, FILE *binfile, size_t compute_start, size_t compute_len)
+{
+       uint8_t readbuf[1024];
+       size_t read;
+
+       fseek(binfile, compute_start, SEEK_SET);
+
+       /* read block of 1024 bytes */
+       while (binfile && !feof(binfile) && !ferror(binfile) && (compute_len >= sizeof(readbuf))) {
+               read = fread(readbuf, sizeof(uint8_t), sizeof(readbuf), binfile);
+               crc = cyg_crc32_accumulate(crc, readbuf, read);
+               compute_len = compute_len - read;
+       }
+
+       /* Less than 1024 bytes remains, read compute_len bytes */
+       if (binfile && !feof(binfile) && !ferror(binfile) && (compute_len > 0)) {
+               read = fread(readbuf, sizeof(uint8_t), compute_len, binfile);
+               crc = cyg_crc32_accumulate(crc, readbuf, read);
+       }
+
+       return crc;
+}
+
+size_t getlen(FILE *fp)
+{
+       size_t retval, curpos;
+
+       if (!fp)
+               return 0;
+
+       curpos = ftell(fp);
+       fseek(fp, 0, SEEK_END);
+       retval = ftell(fp);
+       fseek(fp, curpos, SEEK_SET);
+
+       return retval;
+}
+
+int tagfile(const char *kernel, const char *rootfs, const char *bin, \
+                       const struct gengetopt_args_info *args, \
+                       uint32_t flash_start, uint32_t image_offset, \
+                       uint32_t block_size, uint32_t load_address, uint32_t entry)
+{
+       struct bcm_tag tag;
+       struct kernelhdr khdr;
+       FILE *kernelfile = NULL, *rootfsfile = NULL, *binfile = NULL, *cfefile = NULL;
+       size_t cfeoff, cfelen, kerneloff, kernellen, rootfsoff, rootfslen, \
+         read, imagelen, rootfsoffpadlen = 0, kernelfslen, kerneloffpadlen = 0, oldrootfslen, \
+         rootfsend;
+       uint8_t readbuf[1024];
+       uint32_t imagecrc = IMAGETAG_CRC_START;
+       uint32_t kernelcrc = IMAGETAG_CRC_START;
+       uint32_t rootfscrc = IMAGETAG_CRC_START;
+       uint32_t kernelfscrc = IMAGETAG_CRC_START;
+       uint32_t fwaddr = 0;
+       uint8_t crc_val;
+       const uint32_t deadcode = htonl(DEADCODE);
+       int i;
+       int is_pirelli = 0;
+
+
+       memset(&tag, 0, sizeof(struct bcm_tag));
+
+       if (!kernel || !rootfs) {
+               fprintf(stderr, "imagetag can't create an image without both kernel and rootfs\n");
+       }
+
+       if (kernel && !(kernelfile = fopen(kernel, "rb"))) {
+               fprintf(stderr, "Unable to open kernel \"%s\"\n", kernel);
+               return 1;
+       }
+
+       if (rootfs && !(rootfsfile = fopen(rootfs, "rb"))) {
+               fprintf(stderr, "Unable to open rootfs \"%s\"\n", rootfs);
+               return 1;
+       }
+
+       if (!bin || !(binfile = fopen(bin, "wb+"))) {
+               fprintf(stderr, "Unable to open output file \"%s\"\n", bin);
+               return 1;
+       }
+
+       if ((args->cfe_given) && (args->cfe_arg)) {
+         if (!(cfefile = fopen(args->cfe_arg, "rb"))) {
+               fprintf(stderr, "Unable to open CFE file \"%s\"\n", args->cfe_arg);
+         }
+       }
+
+       fwaddr = flash_start + image_offset;
+       if (cfefile) {
+         cfeoff = flash_start;           
+         cfelen = getlen(cfefile);
+         /* Seek to the start of the file after tag */
+         fseek(binfile, sizeof(tag), SEEK_SET);
+         
+         /* Write the cfe */
+         while (cfefile && !feof(cfefile) && !ferror(cfefile)) {
+               read = fread(readbuf, sizeof(uint8_t), sizeof(readbuf), cfefile);
+               fwrite(readbuf, sizeof(uint8_t), read, binfile);
+         }
+
+       } else {
+         cfeoff = 0;
+         cfelen = 0;
+       }
+
+       if (!args->root_first_flag) {
+         /* Build the kernel address and length (doesn't need to be aligned, read only) */
+         kerneloff = fwaddr + sizeof(tag);
+         
+         kernellen = getlen(kernelfile);
+         
+         if (!args->kernel_file_has_header_flag) {
+               /* Build the kernel header */
+               khdr.loadaddr   = htonl(load_address);
+               khdr.entry      = htonl(entry);
+               khdr.lzmalen    = htonl(kernellen);
+               
+               /* Increase the kernel size by the header size */
+               kernellen += sizeof(khdr);        
+         }
+         
+         /* Build the rootfs address and length */
+         rootfsoff = kerneloff + kernellen;
+         /* align the start if requested */
+         if (args->align_rootfs_flag)
+               rootfsoff = (rootfsoff % block_size) > 0 ? (((rootfsoff / block_size) + 1) * block_size) : rootfsoff;
+
+         /* align the end */
+         rootfsend = rootfsoff + getlen(rootfsfile);
+         if ((rootfsend % block_size) > 0)
+               rootfsend = (((rootfsend / block_size) + 1) * block_size);
+         rootfslen = rootfsend - rootfsoff;
+         imagelen = rootfsoff + rootfslen - kerneloff + sizeof(deadcode);
+         rootfsoffpadlen = rootfsoff - (kerneloff + kernellen);
+         
+         /* Seek to the start of the kernel */
+         fseek(binfile, kerneloff - fwaddr + cfelen, SEEK_SET);
+         
+         /* Write the kernel header */
+         fwrite(&khdr, sizeof(khdr), 1, binfile);
+         
+         /* Write the kernel */
+         while (kernelfile && !feof(kernelfile) && !ferror(kernelfile)) {
+               read = fread(readbuf, sizeof(uint8_t), sizeof(readbuf), kernelfile);
+               fwrite(readbuf, sizeof(uint8_t), read, binfile);
+         }
+
+         /* Write the RootFS */
+         fseek(binfile, rootfsoff - fwaddr + cfelen, SEEK_SET);
+         while (rootfsfile && !feof(rootfsfile) && !ferror(rootfsfile)) {
+               read = fread(readbuf, sizeof(uint8_t), sizeof(readbuf), rootfsfile);
+               fwrite(readbuf, sizeof(uint8_t), read, binfile);
+         }
+
+         /* Align image to specified erase block size and append deadc0de */
+         printf("Data alignment to %dk with 'deadc0de' appended\n", block_size/1024);
+         fseek(binfile, rootfsoff + rootfslen - fwaddr + cfelen, SEEK_SET);
+         fwrite(&deadcode, sizeof(uint32_t), 1, binfile);
+
+         oldrootfslen = rootfslen;
+         if (args->pad_given) {
+               uint32_t allfs = 0xffffffff;
+               uint32_t pad_size = args->pad_arg * 1024 * 1024;
+
+               printf("Padding image to %d bytes ...\n", pad_size);
+               while (imagelen < pad_size) {
+                       fwrite(&allfs, sizeof(uint32_t), 1, binfile);
+                       imagelen += 4;
+                       rootfslen += 4;
+               }
+         }
+
+         /* Flush the binfile buffer so that when we read from file, it contains
+          * everything in the buffer
+          */
+         fflush(binfile);
+
+         /* Compute the crc32 of the entire image (deadC0de included) */
+         imagecrc = compute_crc32(imagecrc, binfile, kerneloff - fwaddr + cfelen, imagelen);
+         /* Compute the crc32 of the kernel and padding between kernel and rootfs) */
+         kernelcrc = compute_crc32(kernelcrc, binfile, kerneloff - fwaddr + cfelen, kernellen + rootfsoffpadlen);
+         /* Compute the crc32 of the kernel and padding between kernel and rootfs) */
+         kernelfscrc = compute_crc32(kernelfscrc, binfile, kerneloff - fwaddr + cfelen, kernellen + rootfsoffpadlen + rootfslen + sizeof(deadcode));
+         /* Compute the crc32 of the flashImageStart to rootLength.
+          * The broadcom firmware assumes the rootfs starts the image,
+          * therefore uses the rootfs start to determine where to flash
+          * the image.  Since we have the kernel first we have to give
+          * it the kernel address, but the crc uses the length
+          * associated with this address, which is added to the kernel
+          * length to determine the length of image to flash and thus
+          * needs to be rootfs + deadcode
+          */
+         rootfscrc = compute_crc32(rootfscrc, binfile, kerneloff - fwaddr + cfelen, rootfslen + sizeof(deadcode));
+
+       } else {
+         /* Build the kernel address and length (doesn't need to be aligned, read only) */
+         rootfsoff = fwaddr + sizeof(tag);
+         oldrootfslen = getlen(rootfsfile);
+         rootfslen = oldrootfslen;
+         rootfslen = ( (rootfslen % block_size) > 0 ? (((rootfslen / block_size) + 1) * block_size) : rootfslen );
+         kerneloffpadlen = rootfslen - oldrootfslen;
+         oldrootfslen = rootfslen;
+
+         kerneloff = rootfsoff + rootfslen;
+         kernellen = getlen(kernelfile);
+
+         imagelen = cfelen + rootfslen + kernellen;
+         
+         /* Seek to the start of the kernel */
+         fseek(binfile, kerneloff - fwaddr + cfelen, SEEK_SET);
+         
+         if (!args->kernel_file_has_header_flag) {
+               /* Build the kernel header */
+               khdr.loadaddr   = htonl(load_address);
+               khdr.entry      = htonl(entry);
+               khdr.lzmalen    = htonl(kernellen);
+               
+               /* Write the kernel header */
+               fwrite(&khdr, sizeof(khdr), 1, binfile);
+         
+               /* Increase the kernel size by the header size */
+               kernellen += sizeof(khdr);        
+         }
+         
+         /* Write the kernel */
+         while (kernelfile && !feof(kernelfile) && !ferror(kernelfile)) {
+               read = fread(readbuf, sizeof(uint8_t), sizeof(readbuf), kernelfile);
+               fwrite(readbuf, sizeof(uint8_t), read, binfile);
+         }
+
+         /* Write the RootFS */
+         fseek(binfile, rootfsoff - fwaddr + cfelen, SEEK_SET);
+         while (rootfsfile && !feof(rootfsfile) && !ferror(rootfsfile)) {
+               read = fread(readbuf, sizeof(uint8_t), sizeof(readbuf), rootfsfile);
+               fwrite(readbuf, sizeof(uint8_t), read, binfile);
+         }
+
+         /* Flush the binfile buffer so that when we read from file, it contains
+          * everything in the buffer
+          */
+         fflush(binfile);
+
+         /* Compute the crc32 of the entire image (deadC0de included) */
+         imagecrc = compute_crc32(imagecrc, binfile, sizeof(tag), imagelen);
+         /* Compute the crc32 of the kernel and padding between kernel and rootfs) */
+         kernelcrc = compute_crc32(kernelcrc, binfile, kerneloff - fwaddr + cfelen, kernellen + rootfsoffpadlen);
+         kernelfscrc = compute_crc32(kernelfscrc, binfile, rootfsoff - fwaddr + cfelen, kernellen + rootfslen);
+         rootfscrc = compute_crc32(rootfscrc, binfile, rootfsoff - fwaddr + cfelen, rootfslen);
+       }
+
+       /* Close the files */
+       if (cfefile) {
+         fclose(cfefile);
+       }
+       fclose(kernelfile);
+       fclose(rootfsfile);
+
+       /* Build the tag */
+       strncpy(tag.tagVersion, args->tag_version_arg, sizeof(tag.tagVersion) - 1);
+       strncpy(tag.sig_1, args->signature_arg, sizeof(tag.sig_1) - 1);
+       strncpy(tag.sig_2, args->signature2_arg, sizeof(tag.sig_2) - 1);
+       strncpy(tag.chipid, args->chipid_arg, sizeof(tag.chipid) - 1);
+       strncpy(tag.boardid, args->boardid_arg, sizeof(tag.boardid) - 1);
+       strcpy(tag.big_endian, "1");
+       sprintf(tag.totalLength, "%lu", imagelen);
+
+       if (args->cfe_given) {
+         sprintf(tag.cfeAddress, "%lu", flash_start);
+         sprintf(tag.cfeLength, "%lu", cfelen);
+       } else {
+         /* We don't include CFE */
+         strcpy(tag.cfeAddress, "0");
+         strcpy(tag.cfeLength, "0");
+       }
+
+       sprintf(tag.kernelAddress, "%lu", kerneloff);
+       sprintf(tag.kernelLength, "%lu", kernellen + rootfsoffpadlen);
+
+       if (args->root_first_flag) {
+         sprintf(tag.flashImageStart, "%lu", rootfsoff);
+         sprintf(tag.flashRootLength, "%lu", rootfslen);         
+       } else {
+         sprintf(tag.flashImageStart, "%lu", kerneloff);
+         sprintf(tag.flashRootLength, "%lu", rootfslen + sizeof(deadcode));
+       }
+       int2tag(tag.rootLength, oldrootfslen + sizeof(deadcode));
+
+       if (args->rsa_signature_given) {
+           strncpy(tag.rsa_signature, args->rsa_signature_arg, RSASIG_LEN);
+       }
+
+       if (args->layoutver_given) {
+           strncpy(tag.flashLayoutVer, args->layoutver_arg, TAGLAYOUT_LEN);
+       }
+
+       if (args->info1_given) {
+         strncpy(tag.information1, args->info1_arg, TAGINFO1_LEN);
+       }
+
+       if (args->info2_given) {
+         strncpy(tag.information2, args->info2_arg, TAGINFO2_LEN);
+       }
+
+       if (args->reserved2_given) {
+         strncpy(tag.reserved2, args->reserved2_arg, 16);
+       }
+
+       if (args->altinfo_given) {
+         strncpy(&tag.information1[0], args->altinfo_arg, ALTTAGINFO_LEN);
+       }
+
+       if (args->second_image_flag_given) {
+         if (strncmp(args->second_image_flag_arg, "2", DUALFLAG_LEN) != 0) {           
+               strncpy(tag.dualImage, args->second_image_flag_arg, DUALFLAG_LEN);
+         }
+       }
+
+       if (args->inactive_given) {
+         if (strncmp(args->inactive_arg, "2", INACTIVEFLAG_LEN) != 0) {                
+               strncpy(tag.inactiveFlag, args->second_image_flag_arg, INACTIVEFLAG_LEN);
+         }
+       }
+
+       for (i = 0; i < NUM_PIRELLI; i++) {
+               if (strncmp(args->boardid_arg, pirellitab[i], BOARDID_LEN) == 0) {
+                       is_pirelli = 1;
+                       break;
+               }
+       }
+
+       if ( !is_pirelli ) {
+         int2tag(tag.imageCRC, kernelfscrc);
+       } else {
+         int2tag(tag.imageCRC, kernelcrc);
+       }
+
+       int2tag(&(tag.rootfsCRC[0]), rootfscrc);
+       int2tag(tag.kernelCRC, kernelcrc);
+       int2tag(tag.fskernelCRC, kernelfscrc);
+       int2tag(tag.headerCRC, cyg_crc32_accumulate(IMAGETAG_CRC_START, (uint8_t*)&tag, sizeof(tag) - 20));
+
+       fseek(binfile, 0L, SEEK_SET);
+       fwrite(&tag, sizeof(uint8_t), sizeof(tag), binfile);
+
+    fflush(binfile);
+       fclose(binfile);
+
+       return 0;
+}
+
+int main(int argc, char **argv)
+{
+    int c, i;
+       char *kernel, *rootfs, *bin;
+       uint32_t flash_start, image_offset, block_size, load_address, entry;
+       flash_start = image_offset = block_size = load_address = entry = 0;
+       struct gengetopt_args_info parsed_args;
+
+       kernel = rootfs = bin = NULL;
+
+       if (imagetag_cmdline(argc, argv, &parsed_args)) {
+         exit(1);
+       }
+
+       printf("Broadcom 63xx image tagger - v2.0.0\n");
+       printf("Copyright (C) 2008 Axel Gembe\n");
+       printf("Copyright (C) 2009-2010 Daniel Dickinson\n");
+       printf("Licensed under the terms of the Gnu General Public License\n");
+
+       kernel = parsed_args.kernel_arg;
+       rootfs = parsed_args.rootfs_arg;
+       bin = parsed_args.output_arg;
+       if (strlen(parsed_args.tag_version_arg) >= TAGVER_LEN) {
+         fprintf(stderr, "Error: Tag Version (tag_version,v) too long.\n");
+         exit(1);
+       }
+       if (strlen(parsed_args.boardid_arg) >= BOARDID_LEN) {
+         fprintf(stderr, "Error: Board ID (boardid,b) too long.\n");
+         exit(1);
+       }
+       if (strlen(parsed_args.chipid_arg) >= CHIPID_LEN) {
+         fprintf(stderr, "Error: Chip ID (chipid,c) too long.\n");
+         exit(1);
+       }
+       if (strlen(parsed_args.signature_arg) >= SIG1_LEN) {
+         fprintf(stderr, "Error: Magic string (signature,a) too long.\n");
+         exit(1);
+       }
+       if (strlen(parsed_args.signature2_arg) >= SIG2_LEN) {
+         fprintf(stderr, "Error: Second magic string (signature2,m) too long.\n");
+         exit(1);
+       }
+       if (parsed_args.layoutver_given) {
+         if (strlen(parsed_args.layoutver_arg) > FLASHLAYOUTVER_LEN) {
+               fprintf(stderr, "Error: Flash layout version (layoutver,y) too long.\n");
+               exit(1);
+         }
+       }
+       if (parsed_args.rsa_signature_given) {
+         if (strlen(parsed_args.rsa_signature_arg) > RSASIG_LEN) {
+               fprintf(stderr, "Error: RSA Signature (rsa_signature,r) too long.\n");
+               exit(1);
+         }
+       }
+
+       if (parsed_args.info1_given) {
+         if (strlen(parsed_args.info1_arg) >= TAGINFO1_LEN) {
+               fprintf(stderr, "Error: Vendor Information 1 (info1) too long.\n");
+               exit(1);
+         }
+       }
+
+       if (parsed_args.info2_given) {
+         if (strlen(parsed_args.info2_arg) >= TAGINFO2_LEN) {
+               fprintf(stderr, "Error: Vendor Information 2 (info2) too long.\n");
+               exit(1);
+         }
+       }
+
+       if (parsed_args.altinfo_given) {
+         if (strlen(parsed_args.altinfo_arg) >= ALTTAGINFO_LEN) {
+               fprintf(stderr, "Error: Vendor Information 1 (info1) too long.\n");
+               exit(1);
+         }
+       }
+
+       if (parsed_args.pad_given) {
+         if (parsed_args.pad_arg < 0) {
+               fprintf(stderr, "Error: pad size must be positive.\r");
+               exit(1);
+         }
+       }
+
+       flash_start = strtoul(parsed_args.flash_start_arg, NULL, 16);
+       image_offset = strtoul(parsed_args.image_offset_arg, NULL, 16);
+       block_size = strtoul(parsed_args.block_size_arg, NULL, 16);
+
+       if (!parsed_args.kernel_file_has_header_flag) {
+         load_address = strtoul(parsed_args.load_addr_arg, NULL, 16);
+         entry = strtoul(parsed_args.entry_arg, NULL, 16);
+         if (load_address == 0) {
+               fprintf(stderr, "Error: Invalid value for load address\n");
+         }
+         if (entry == 0) {
+               fprintf(stderr, "Error: Invalid value for entry\n");
+         }
+       }
+       
+       return tagfile(kernel, rootfs, bin, &parsed_args, flash_start, image_offset, block_size, load_address, entry);
+}
diff --git a/trunk/tools/firmware-utils/src/imagetag.ggo b/trunk/tools/firmware-utils/src/imagetag.ggo
new file mode 100644 (file)
index 0000000..04f608e
--- /dev/null
@@ -0,0 +1,46 @@
+# Command line option parsing generator file for imagetag
+# Supplied-To: gengetopt
+#
+# Copyright 2010 Daniel Dickinson <librecmc@cshore.neomailbox.net>
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License.  See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+
+package "imagetag"
+version "2.0.0"
+purpose "Generate image with CFE imagetag for Broadcom 63xx routers."
+description "Copyright (C) 2008 Axel Gembe
+Copyright (C) 2009-2010 Daniel Dickinson
+Licensed unter the terms of the Gnu General Public License.
+
+Given a root filesystem, a linux kernel, and an optional CFE, generates an image with an imagetag for a Broadcom 63xx-based router.  Additional parameters to be specified depend on the specfic brand and model of router."
+args "--file-name=imagetag_cmdline"
+
+option "kernel" i "File with LZMA compressed kernel to include in the image." string typestr="filename"  required
+option "rootfs" f "File with RootFS to include in the image." string typestr="filename" required
+option "output" o "Name of output file." string typestr="filename" required
+option "cfe" - "File with CFE to include in the image." string typestr="filename" optional
+option "boardid" b "Board ID to set in the image (must match what router expects, e.g. \"96345GW2\")." string required
+option "chipid" c "Chip ID to set in the image (must match the actual hardware, e.g. \"6345\")." string required
+option "flash-start" s "Flash start address." string typestr="address" optional default="0xBFC00000"
+option "image-offset" n "Offset from start address for the first byte after the CFE (in memory)." string typestr="offset" default="0x10000" optional
+option "tag-version" v "Version number for imagetag format." string default="6" optional
+option "signature" a "Magic string (signature), for boards that need it." string default="Broadcom Corporatio" optional
+option "signature2" m "Second magic string (signature2)." string default="ver. 2.0" optional
+option "block-size" k "Flash erase block size." string optional default="0x10000"
+option "load-addr" l "Kernel load address." string typestr="address" required
+option "entry" e "Address where the kernel entry point will be for booting." string typestr="address" required
+option "layoutver" y "Flash layout version (version 2.2x of the Broadcom code requires this)." string optional
+option "info1" 1 "String for first vendor information section." string optional
+option "altinfo" - "String for vendor information section (alternate/pirelli)." string optional
+option "info2" 2 "String for second vendor information section." string optional
+option "root-first" - "Put the rootfs before the kernel (only for stock images, e.g. captured from the router's flash memory)." flag off
+option "rsa-signature" r "String for RSA Signature section." string optional
+option "second-image-flag" - "Dual Image Flag (2=not-specified)." values="0", "1", "2" default="2" typestr="flag-value" optional
+option "inactive" - "Inactive Flag (2=not-specified)." values="0", "1", "2" default="2" typestr="flag-value" optional
+option "reserved2" - "String for second reserved section." string optional
+option "kernel-file-has-header" - "Indicates that the kernel file includes the kernel header with correct load address and entry point, so no changes are needed" flag off
+option "pad" p "Pad the image to this size if smaller (in MiB)" int typestr="size (in MiB)" optional
+option "align-rootfs" - "Align the rootfs start to erase block size" flag off
diff --git a/trunk/tools/firmware-utils/src/imagetag_cmdline.c b/trunk/tools/firmware-utils/src/imagetag_cmdline.c
new file mode 100644 (file)
index 0000000..86c90bb
--- /dev/null
@@ -0,0 +1,1193 @@
+/*
+  File autogenerated by gengetopt version 2.22.5
+  generated with the following command:
+  gengetopt -i imagetag.ggo -f imagetag_cmdline --file-name=imagetag_cmdline
+
+  The developers of gengetopt consider the fixed text that goes in all
+  gengetopt output files to be in the public domain:
+  we make no copyright claims on it.
+*/
+
+/* If we use autoconf.  */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef FIX_UNUSED
+#define FIX_UNUSED(X) (void) (X) /* avoid warnings for unused params */
+#endif
+
+#include <getopt.h>
+
+#include "imagetag_cmdline.h"
+
+const char *gengetopt_args_info_purpose = "Generate image with CFE imagetag for Broadcom 63xx routers.";
+
+const char *gengetopt_args_info_usage = "Usage: imagetag [OPTIONS]...";
+
+const char *gengetopt_args_info_description = "Copyright (C) 2008 Axel Gembe\nCopyright (C) 2009-2010 Daniel Dickinson\nLicensed unter the terms of the Gnu General Public License.\n\nGiven a root filesystem, a linux kernel, and an optional CFE, generates an \nimage with an imagetag for a Broadcom 63xx-based router.  Additional parameters \nto be specified depend on the specfic brand and model of router.";
+
+const char *gengetopt_args_info_help[] = {
+  "  -h, --help                    Print help and exit",
+  "  -V, --version                 Print version and exit",
+  "  -i, --kernel=filename         File with LZMA compressed kernel to include in \n                                  the image.",
+  "  -f, --rootfs=filename         File with RootFS to include in the image.",
+  "  -o, --output=filename         Name of output file.",
+  "      --cfe=filename            File with CFE to include in the image.",
+  "  -b, --boardid=STRING          Board ID to set in the image (must match what \n                                  router expects, e.g. \"96345GW2\").",
+  "  -c, --chipid=STRING           Chip ID to set in the image (must match the \n                                  actual hardware, e.g. \"6345\").",
+  "  -s, --flash-start=address     Flash start address.  (default=`0xBFC00000')",
+  "  -n, --image-offset=offset     Offset from start address for the first byte \n                                  after the CFE (in memory).  \n                                  (default=`0x10000')",
+  "  -v, --tag-version=STRING      Version number for imagetag format.  \n                                  (default=`6')",
+  "  -a, --signature=STRING        Magic string (signature), for boards that need \n                                  it.  (default=`Broadcom Corporatio')",
+  "  -m, --signature2=STRING       Second magic string (signature2).  \n                                  (default=`ver. 2.0')",
+  "  -k, --block-size=STRING       Flash erase block size.  (default=`0x10000')",
+  "  -l, --load-addr=address       Kernel load address.",
+  "  -e, --entry=address           Address where the kernel entry point will be \n                                  for booting.",
+  "  -y, --layoutver=STRING        Flash layout version (version 2.2x of the \n                                  Broadcom code requires this).",
+  "  -1, --info1=STRING            String for first vendor information section.",
+  "      --altinfo=STRING          String for vendor information section \n                                  (alternate/pirelli).",
+  "  -2, --info2=STRING            String for second vendor information section.",
+  "      --root-first              Put the rootfs before the kernel (only for \n                                  stock images, e.g. captured from the router's \n                                  flash memory).  (default=off)",
+  "  -r, --rsa-signature=STRING    String for RSA Signature section.",
+  "      --second-image-flag=flag-value\n                                Dual Image Flag (2=not-specified).  (possible \n                                  values=\"0\", \"1\", \"2\" default=`2')",
+  "      --inactive=flag-value     Inactive Flag (2=not-specified).  (possible \n                                  values=\"0\", \"1\", \"2\" default=`2')",
+  "      --reserved2=STRING        String for second reserved section.",
+  "      --kernel-file-has-header  Indicates that the kernel file includes the \n                                  kernel header with correct load address and \n                                  entry point, so no changes are needed  \n                                  (default=off)",
+  "  -p, --pad=size (in MiB)       Pad the image to this size if smaller (in MiB)",
+  "      --align-rootfs            Align the rootfs start to erase block size  \n                                  (default=off)",
+    0
+};
+
+typedef enum {ARG_NO
+  , ARG_FLAG
+  , ARG_STRING
+  , ARG_INT
+} imagetag_cmdline_arg_type;
+
+static
+void clear_given (struct gengetopt_args_info *args_info);
+static
+void clear_args (struct gengetopt_args_info *args_info);
+
+static int
+imagetag_cmdline_internal (int argc, char **argv, struct gengetopt_args_info *args_info,
+                        struct imagetag_cmdline_params *params, const char *additional_error);
+
+static int
+imagetag_cmdline_required2 (struct gengetopt_args_info *args_info, const char *prog_name, const char *additional_error);
+
+const char *imagetag_cmdline_second_image_flag_values[] = {"0", "1", "2", 0}; /*< Possible values for second-image-flag. */
+const char *imagetag_cmdline_inactive_values[] = {"0", "1", "2", 0}; /*< Possible values for inactive. */
+
+static char *
+gengetopt_strdup (const char *s);
+
+static
+void clear_given (struct gengetopt_args_info *args_info)
+{
+  args_info->help_given = 0 ;
+  args_info->version_given = 0 ;
+  args_info->kernel_given = 0 ;
+  args_info->rootfs_given = 0 ;
+  args_info->output_given = 0 ;
+  args_info->cfe_given = 0 ;
+  args_info->boardid_given = 0 ;
+  args_info->chipid_given = 0 ;
+  args_info->flash_start_given = 0 ;
+  args_info->image_offset_given = 0 ;
+  args_info->tag_version_given = 0 ;
+  args_info->signature_given = 0 ;
+  args_info->signature2_given = 0 ;
+  args_info->block_size_given = 0 ;
+  args_info->load_addr_given = 0 ;
+  args_info->entry_given = 0 ;
+  args_info->layoutver_given = 0 ;
+  args_info->info1_given = 0 ;
+  args_info->altinfo_given = 0 ;
+  args_info->info2_given = 0 ;
+  args_info->root_first_given = 0 ;
+  args_info->rsa_signature_given = 0 ;
+  args_info->second_image_flag_given = 0 ;
+  args_info->inactive_given = 0 ;
+  args_info->reserved2_given = 0 ;
+  args_info->kernel_file_has_header_given = 0 ;
+  args_info->pad_given = 0 ;
+  args_info->align_rootfs_given = 0 ;
+}
+
+static
+void clear_args (struct gengetopt_args_info *args_info)
+{
+  FIX_UNUSED (args_info);
+  args_info->kernel_arg = NULL;
+  args_info->kernel_orig = NULL;
+  args_info->rootfs_arg = NULL;
+  args_info->rootfs_orig = NULL;
+  args_info->output_arg = NULL;
+  args_info->output_orig = NULL;
+  args_info->cfe_arg = NULL;
+  args_info->cfe_orig = NULL;
+  args_info->boardid_arg = NULL;
+  args_info->boardid_orig = NULL;
+  args_info->chipid_arg = NULL;
+  args_info->chipid_orig = NULL;
+  args_info->flash_start_arg = gengetopt_strdup ("0xBFC00000");
+  args_info->flash_start_orig = NULL;
+  args_info->image_offset_arg = gengetopt_strdup ("0x10000");
+  args_info->image_offset_orig = NULL;
+  args_info->tag_version_arg = gengetopt_strdup ("6");
+  args_info->tag_version_orig = NULL;
+  args_info->signature_arg = gengetopt_strdup ("Broadcom Corporatio");
+  args_info->signature_orig = NULL;
+  args_info->signature2_arg = gengetopt_strdup ("ver. 2.0");
+  args_info->signature2_orig = NULL;
+  args_info->block_size_arg = gengetopt_strdup ("0x10000");
+  args_info->block_size_orig = NULL;
+  args_info->load_addr_arg = NULL;
+  args_info->load_addr_orig = NULL;
+  args_info->entry_arg = NULL;
+  args_info->entry_orig = NULL;
+  args_info->layoutver_arg = NULL;
+  args_info->layoutver_orig = NULL;
+  args_info->info1_arg = NULL;
+  args_info->info1_orig = NULL;
+  args_info->altinfo_arg = NULL;
+  args_info->altinfo_orig = NULL;
+  args_info->info2_arg = NULL;
+  args_info->info2_orig = NULL;
+  args_info->root_first_flag = 0;
+  args_info->rsa_signature_arg = NULL;
+  args_info->rsa_signature_orig = NULL;
+  args_info->second_image_flag_arg = gengetopt_strdup ("2");
+  args_info->second_image_flag_orig = NULL;
+  args_info->inactive_arg = gengetopt_strdup ("2");
+  args_info->inactive_orig = NULL;
+  args_info->reserved2_arg = NULL;
+  args_info->reserved2_orig = NULL;
+  args_info->kernel_file_has_header_flag = 0;
+  args_info->pad_orig = NULL;
+  args_info->align_rootfs_flag = 0;
+  
+}
+
+static
+void init_args_info(struct gengetopt_args_info *args_info)
+{
+
+
+  args_info->help_help = gengetopt_args_info_help[0] ;
+  args_info->version_help = gengetopt_args_info_help[1] ;
+  args_info->kernel_help = gengetopt_args_info_help[2] ;
+  args_info->rootfs_help = gengetopt_args_info_help[3] ;
+  args_info->output_help = gengetopt_args_info_help[4] ;
+  args_info->cfe_help = gengetopt_args_info_help[5] ;
+  args_info->boardid_help = gengetopt_args_info_help[6] ;
+  args_info->chipid_help = gengetopt_args_info_help[7] ;
+  args_info->flash_start_help = gengetopt_args_info_help[8] ;
+  args_info->image_offset_help = gengetopt_args_info_help[9] ;
+  args_info->tag_version_help = gengetopt_args_info_help[10] ;
+  args_info->signature_help = gengetopt_args_info_help[11] ;
+  args_info->signature2_help = gengetopt_args_info_help[12] ;
+  args_info->block_size_help = gengetopt_args_info_help[13] ;
+  args_info->load_addr_help = gengetopt_args_info_help[14] ;
+  args_info->entry_help = gengetopt_args_info_help[15] ;
+  args_info->layoutver_help = gengetopt_args_info_help[16] ;
+  args_info->info1_help = gengetopt_args_info_help[17] ;
+  args_info->altinfo_help = gengetopt_args_info_help[18] ;
+  args_info->info2_help = gengetopt_args_info_help[19] ;
+  args_info->root_first_help = gengetopt_args_info_help[20] ;
+  args_info->rsa_signature_help = gengetopt_args_info_help[21] ;
+  args_info->second_image_flag_help = gengetopt_args_info_help[22] ;
+  args_info->inactive_help = gengetopt_args_info_help[23] ;
+  args_info->reserved2_help = gengetopt_args_info_help[24] ;
+  args_info->kernel_file_has_header_help = gengetopt_args_info_help[25] ;
+  args_info->pad_help = gengetopt_args_info_help[26] ;
+  args_info->align_rootfs_help = gengetopt_args_info_help[27] ;
+  
+}
+
+void
+imagetag_cmdline_print_version (void)
+{
+  printf ("%s %s\n",
+     (strlen(IMAGETAG_CMDLINE_PACKAGE_NAME) ? IMAGETAG_CMDLINE_PACKAGE_NAME : IMAGETAG_CMDLINE_PACKAGE),
+     IMAGETAG_CMDLINE_VERSION);
+}
+
+static void print_help_common(void) {
+  imagetag_cmdline_print_version ();
+
+  if (strlen(gengetopt_args_info_purpose) > 0)
+    printf("\n%s\n", gengetopt_args_info_purpose);
+
+  if (strlen(gengetopt_args_info_usage) > 0)
+    printf("\n%s\n", gengetopt_args_info_usage);
+
+  printf("\n");
+
+  if (strlen(gengetopt_args_info_description) > 0)
+    printf("%s\n\n", gengetopt_args_info_description);
+}
+
+void
+imagetag_cmdline_print_help (void)
+{
+  int i = 0;
+  print_help_common();
+  while (gengetopt_args_info_help[i])
+    printf("%s\n", gengetopt_args_info_help[i++]);
+}
+
+void
+imagetag_cmdline_init (struct gengetopt_args_info *args_info)
+{
+  clear_given (args_info);
+  clear_args (args_info);
+  init_args_info (args_info);
+}
+
+void
+imagetag_cmdline_params_init(struct imagetag_cmdline_params *params)
+{
+  if (params)
+    { 
+      params->override = 0;
+      params->initialize = 1;
+      params->check_required = 1;
+      params->check_ambiguity = 0;
+      params->print_errors = 1;
+    }
+}
+
+struct imagetag_cmdline_params *
+imagetag_cmdline_params_create(void)
+{
+  struct imagetag_cmdline_params *params = 
+    (struct imagetag_cmdline_params *)malloc(sizeof(struct imagetag_cmdline_params));
+  imagetag_cmdline_params_init(params);  
+  return params;
+}
+
+static void
+free_string_field (char **s)
+{
+  if (*s)
+    {
+      free (*s);
+      *s = 0;
+    }
+}
+
+
+static void
+imagetag_cmdline_release (struct gengetopt_args_info *args_info)
+{
+
+  free_string_field (&(args_info->kernel_arg));
+  free_string_field (&(args_info->kernel_orig));
+  free_string_field (&(args_info->rootfs_arg));
+  free_string_field (&(args_info->rootfs_orig));
+  free_string_field (&(args_info->output_arg));
+  free_string_field (&(args_info->output_orig));
+  free_string_field (&(args_info->cfe_arg));
+  free_string_field (&(args_info->cfe_orig));
+  free_string_field (&(args_info->boardid_arg));
+  free_string_field (&(args_info->boardid_orig));
+  free_string_field (&(args_info->chipid_arg));
+  free_string_field (&(args_info->chipid_orig));
+  free_string_field (&(args_info->flash_start_arg));
+  free_string_field (&(args_info->flash_start_orig));
+  free_string_field (&(args_info->image_offset_arg));
+  free_string_field (&(args_info->image_offset_orig));
+  free_string_field (&(args_info->tag_version_arg));
+  free_string_field (&(args_info->tag_version_orig));
+  free_string_field (&(args_info->signature_arg));
+  free_string_field (&(args_info->signature_orig));
+  free_string_field (&(args_info->signature2_arg));
+  free_string_field (&(args_info->signature2_orig));
+  free_string_field (&(args_info->block_size_arg));
+  free_string_field (&(args_info->block_size_orig));
+  free_string_field (&(args_info->load_addr_arg));
+  free_string_field (&(args_info->load_addr_orig));
+  free_string_field (&(args_info->entry_arg));
+  free_string_field (&(args_info->entry_orig));
+  free_string_field (&(args_info->layoutver_arg));
+  free_string_field (&(args_info->layoutver_orig));
+  free_string_field (&(args_info->info1_arg));
+  free_string_field (&(args_info->info1_orig));
+  free_string_field (&(args_info->altinfo_arg));
+  free_string_field (&(args_info->altinfo_orig));
+  free_string_field (&(args_info->info2_arg));
+  free_string_field (&(args_info->info2_orig));
+  free_string_field (&(args_info->rsa_signature_arg));
+  free_string_field (&(args_info->rsa_signature_orig));
+  free_string_field (&(args_info->second_image_flag_arg));
+  free_string_field (&(args_info->second_image_flag_orig));
+  free_string_field (&(args_info->inactive_arg));
+  free_string_field (&(args_info->inactive_orig));
+  free_string_field (&(args_info->reserved2_arg));
+  free_string_field (&(args_info->reserved2_orig));
+  free_string_field (&(args_info->pad_orig));
+  
+  
+
+  clear_given (args_info);
+}
+
+/**
+ * @param val the value to check
+ * @param values the possible values
+ * @return the index of the matched value:
+ * -1 if no value matched,
+ * -2 if more than one value has matched
+ */
+static int
+check_possible_values(const char *val, const char *values[])
+{
+  int i, found, last;
+  size_t len;
+
+  if (!val)   /* otherwise strlen() crashes below */
+    return -1; /* -1 means no argument for the option */
+
+  found = last = 0;
+
+  for (i = 0, len = strlen(val); values[i]; ++i)
+    {
+      if (strncmp(val, values[i], len) == 0)
+        {
+          ++found;
+          last = i;
+          if (strlen(values[i]) == len)
+            return i; /* exact macth no need to check more */
+        }
+    }
+
+  if (found == 1) /* one match: OK */
+    return last;
+
+  return (found ? -2 : -1); /* return many values or none matched */
+}
+
+
+static void
+write_into_file(FILE *outfile, const char *opt, const char *arg, const char *values[])
+{
+  int found = -1;
+  if (arg) {
+    if (values) {
+      found = check_possible_values(arg, values);      
+    }
+    if (found >= 0)
+      fprintf(outfile, "%s=\"%s\" # %s\n", opt, arg, values[found]);
+    else
+      fprintf(outfile, "%s=\"%s\"\n", opt, arg);
+  } else {
+    fprintf(outfile, "%s\n", opt);
+  }
+}
+
+
+int
+imagetag_cmdline_dump(FILE *outfile, struct gengetopt_args_info *args_info)
+{
+  int i = 0;
+
+  if (!outfile)
+    {
+      fprintf (stderr, "%s: cannot dump options to stream\n", IMAGETAG_CMDLINE_PACKAGE);
+      return EXIT_FAILURE;
+    }
+
+  if (args_info->help_given)
+    write_into_file(outfile, "help", 0, 0 );
+  if (args_info->version_given)
+    write_into_file(outfile, "version", 0, 0 );
+  if (args_info->kernel_given)
+    write_into_file(outfile, "kernel", args_info->kernel_orig, 0);
+  if (args_info->rootfs_given)
+    write_into_file(outfile, "rootfs", args_info->rootfs_orig, 0);
+  if (args_info->output_given)
+    write_into_file(outfile, "output", args_info->output_orig, 0);
+  if (args_info->cfe_given)
+    write_into_file(outfile, "cfe", args_info->cfe_orig, 0);
+  if (args_info->boardid_given)
+    write_into_file(outfile, "boardid", args_info->boardid_orig, 0);
+  if (args_info->chipid_given)
+    write_into_file(outfile, "chipid", args_info->chipid_orig, 0);
+  if (args_info->flash_start_given)
+    write_into_file(outfile, "flash-start", args_info->flash_start_orig, 0);
+  if (args_info->image_offset_given)
+    write_into_file(outfile, "image-offset", args_info->image_offset_orig, 0);
+  if (args_info->tag_version_given)
+    write_into_file(outfile, "tag-version", args_info->tag_version_orig, 0);
+  if (args_info->signature_given)
+    write_into_file(outfile, "signature", args_info->signature_orig, 0);
+  if (args_info->signature2_given)
+    write_into_file(outfile, "signature2", args_info->signature2_orig, 0);
+  if (args_info->block_size_given)
+    write_into_file(outfile, "block-size", args_info->block_size_orig, 0);
+  if (args_info->load_addr_given)
+    write_into_file(outfile, "load-addr", args_info->load_addr_orig, 0);
+  if (args_info->entry_given)
+    write_into_file(outfile, "entry", args_info->entry_orig, 0);
+  if (args_info->layoutver_given)
+    write_into_file(outfile, "layoutver", args_info->layoutver_orig, 0);
+  if (args_info->info1_given)
+    write_into_file(outfile, "info1", args_info->info1_orig, 0);
+  if (args_info->altinfo_given)
+    write_into_file(outfile, "altinfo", args_info->altinfo_orig, 0);
+  if (args_info->info2_given)
+    write_into_file(outfile, "info2", args_info->info2_orig, 0);
+  if (args_info->root_first_given)
+    write_into_file(outfile, "root-first", 0, 0 );
+  if (args_info->rsa_signature_given)
+    write_into_file(outfile, "rsa-signature", args_info->rsa_signature_orig, 0);
+  if (args_info->second_image_flag_given)
+    write_into_file(outfile, "second-image-flag", args_info->second_image_flag_orig, imagetag_cmdline_second_image_flag_values);
+  if (args_info->inactive_given)
+    write_into_file(outfile, "inactive", args_info->inactive_orig, imagetag_cmdline_inactive_values);
+  if (args_info->reserved2_given)
+    write_into_file(outfile, "reserved2", args_info->reserved2_orig, 0);
+  if (args_info->kernel_file_has_header_given)
+    write_into_file(outfile, "kernel-file-has-header", 0, 0 );
+  if (args_info->pad_given)
+    write_into_file(outfile, "pad", args_info->pad_orig, 0);
+  if (args_info->align_rootfs_given)
+    write_into_file(outfile, "align-rootfs", 0, 0 );
+  
+
+  i = EXIT_SUCCESS;
+  return i;
+}
+
+int
+imagetag_cmdline_file_save(const char *filename, struct gengetopt_args_info *args_info)
+{
+  FILE *outfile;
+  int i = 0;
+
+  outfile = fopen(filename, "w");
+
+  if (!outfile)
+    {
+      fprintf (stderr, "%s: cannot open file for writing: %s\n", IMAGETAG_CMDLINE_PACKAGE, filename);
+      return EXIT_FAILURE;
+    }
+
+  i = imagetag_cmdline_dump(outfile, args_info);
+  fclose (outfile);
+
+  return i;
+}
+
+void
+imagetag_cmdline_free (struct gengetopt_args_info *args_info)
+{
+  imagetag_cmdline_release (args_info);
+}
+
+/** @brief replacement of strdup, which is not standard */
+char *
+gengetopt_strdup (const char *s)
+{
+  char *result = 0;
+  if (!s)
+    return result;
+
+  result = (char*)malloc(strlen(s) + 1);
+  if (result == (char*)0)
+    return (char*)0;
+  strcpy(result, s);
+  return result;
+}
+
+int
+imagetag_cmdline (int argc, char **argv, struct gengetopt_args_info *args_info)
+{
+  return imagetag_cmdline2 (argc, argv, args_info, 0, 1, 1);
+}
+
+int
+imagetag_cmdline_ext (int argc, char **argv, struct gengetopt_args_info *args_info,
+                   struct imagetag_cmdline_params *params)
+{
+  int result;
+  result = imagetag_cmdline_internal (argc, argv, args_info, params, 0);
+
+  if (result == EXIT_FAILURE)
+    {
+      imagetag_cmdline_free (args_info);
+      exit (EXIT_FAILURE);
+    }
+  
+  return result;
+}
+
+int
+imagetag_cmdline2 (int argc, char **argv, struct gengetopt_args_info *args_info, int override, int initialize, int check_required)
+{
+  int result;
+  struct imagetag_cmdline_params params;
+  
+  params.override = override;
+  params.initialize = initialize;
+  params.check_required = check_required;
+  params.check_ambiguity = 0;
+  params.print_errors = 1;
+
+  result = imagetag_cmdline_internal (argc, argv, args_info, &params, 0);
+
+  if (result == EXIT_FAILURE)
+    {
+      imagetag_cmdline_free (args_info);
+      exit (EXIT_FAILURE);
+    }
+  
+  return result;
+}
+
+int
+imagetag_cmdline_required (struct gengetopt_args_info *args_info, const char *prog_name)
+{
+  int result = EXIT_SUCCESS;
+
+  if (imagetag_cmdline_required2(args_info, prog_name, 0) > 0)
+    result = EXIT_FAILURE;
+
+  if (result == EXIT_FAILURE)
+    {
+      imagetag_cmdline_free (args_info);
+      exit (EXIT_FAILURE);
+    }
+  
+  return result;
+}
+
+int
+imagetag_cmdline_required2 (struct gengetopt_args_info *args_info, const char *prog_name, const char *additional_error)
+{
+  int error = 0;
+  FIX_UNUSED (additional_error);
+
+  /* checks for required options */
+  if (! args_info->kernel_given)
+    {
+      fprintf (stderr, "%s: '--kernel' ('-i') option required%s\n", prog_name, (additional_error ? additional_error : ""));
+      error = 1;
+    }
+  
+  if (! args_info->rootfs_given)
+    {
+      fprintf (stderr, "%s: '--rootfs' ('-f') option required%s\n", prog_name, (additional_error ? additional_error : ""));
+      error = 1;
+    }
+  
+  if (! args_info->output_given)
+    {
+      fprintf (stderr, "%s: '--output' ('-o') option required%s\n", prog_name, (additional_error ? additional_error : ""));
+      error = 1;
+    }
+  
+  if (! args_info->boardid_given)
+    {
+      fprintf (stderr, "%s: '--boardid' ('-b') option required%s\n", prog_name, (additional_error ? additional_error : ""));
+      error = 1;
+    }
+  
+  if (! args_info->chipid_given)
+    {
+      fprintf (stderr, "%s: '--chipid' ('-c') option required%s\n", prog_name, (additional_error ? additional_error : ""));
+      error = 1;
+    }
+  
+  if (! args_info->load_addr_given)
+    {
+      fprintf (stderr, "%s: '--load-addr' ('-l') option required%s\n", prog_name, (additional_error ? additional_error : ""));
+      error = 1;
+    }
+  
+  if (! args_info->entry_given)
+    {
+      fprintf (stderr, "%s: '--entry' ('-e') option required%s\n", prog_name, (additional_error ? additional_error : ""));
+      error = 1;
+    }
+  
+  
+  /* checks for dependences among options */
+
+  return error;
+}
+
+
+static char *package_name = 0;
+
+/**
+ * @brief updates an option
+ * @param field the generic pointer to the field to update
+ * @param orig_field the pointer to the orig field
+ * @param field_given the pointer to the number of occurrence of this option
+ * @param prev_given the pointer to the number of occurrence already seen
+ * @param value the argument for this option (if null no arg was specified)
+ * @param possible_values the possible values for this option (if specified)
+ * @param default_value the default value (in case the option only accepts fixed values)
+ * @param arg_type the type of this option
+ * @param check_ambiguity @see imagetag_cmdline_params.check_ambiguity
+ * @param override @see imagetag_cmdline_params.override
+ * @param no_free whether to free a possible previous value
+ * @param multiple_option whether this is a multiple option
+ * @param long_opt the corresponding long option
+ * @param short_opt the corresponding short option (or '-' if none)
+ * @param additional_error possible further error specification
+ */
+static
+int update_arg(void *field, char **orig_field,
+               unsigned int *field_given, unsigned int *prev_given, 
+               char *value, const char *possible_values[],
+               const char *default_value,
+               imagetag_cmdline_arg_type arg_type,
+               int check_ambiguity, int override,
+               int no_free, int multiple_option,
+               const char *long_opt, char short_opt,
+               const char *additional_error)
+{
+  char *stop_char = 0;
+  const char *val = value;
+  int found;
+  char **string_field;
+  FIX_UNUSED (field);
+
+  stop_char = 0;
+  found = 0;
+
+  if (!multiple_option && prev_given && (*prev_given || (check_ambiguity && *field_given)))
+    {
+      if (short_opt != '-')
+        fprintf (stderr, "%s: `--%s' (`-%c') option given more than once%s\n", 
+               package_name, long_opt, short_opt,
+               (additional_error ? additional_error : ""));
+      else
+        fprintf (stderr, "%s: `--%s' option given more than once%s\n", 
+               package_name, long_opt,
+               (additional_error ? additional_error : ""));
+      return 1; /* failure */
+    }
+
+  if (possible_values && (found = check_possible_values((value ? value : default_value), possible_values)) < 0)
+    {
+      if (short_opt != '-')
+        fprintf (stderr, "%s: %s argument, \"%s\", for option `--%s' (`-%c')%s\n", 
+          package_name, (found == -2) ? "ambiguous" : "invalid", value, long_opt, short_opt,
+          (additional_error ? additional_error : ""));
+      else
+        fprintf (stderr, "%s: %s argument, \"%s\", for option `--%s'%s\n", 
+          package_name, (found == -2) ? "ambiguous" : "invalid", value, long_opt,
+          (additional_error ? additional_error : ""));
+      return 1; /* failure */
+    }
+    
+  if (field_given && *field_given && ! override)
+    return 0;
+  if (prev_given)
+    (*prev_given)++;
+  if (field_given)
+    (*field_given)++;
+  if (possible_values)
+    val = possible_values[found];
+
+  switch(arg_type) {
+  case ARG_FLAG:
+    *((int *)field) = !*((int *)field);
+    break;
+  case ARG_INT:
+    if (val) *((int *)field) = strtol (val, &stop_char, 0);
+    break;
+  case ARG_STRING:
+    if (val) {
+      string_field = (char **)field;
+      if (!no_free && *string_field)
+        free (*string_field); /* free previous string */
+      *string_field = gengetopt_strdup (val);
+    }
+    break;
+  default:
+    break;
+  };
+
+  /* check numeric conversion */
+  switch(arg_type) {
+  case ARG_INT:
+    if (val && !(stop_char && *stop_char == '\0')) {
+      fprintf(stderr, "%s: invalid numeric value: %s\n", package_name, val);
+      return 1; /* failure */
+    }
+    break;
+  default:
+    ;
+  };
+
+  /* store the original value */
+  switch(arg_type) {
+  case ARG_NO:
+  case ARG_FLAG:
+    break;
+  default:
+    if (value && orig_field) {
+      if (no_free) {
+        *orig_field = value;
+      } else {
+        if (*orig_field)
+          free (*orig_field); /* free previous string */
+        *orig_field = gengetopt_strdup (value);
+      }
+    }
+  };
+
+  return 0; /* OK */
+}
+
+
+int
+imagetag_cmdline_internal (
+  int argc, char **argv, struct gengetopt_args_info *args_info,
+                        struct imagetag_cmdline_params *params, const char *additional_error)
+{
+  int c;       /* Character of the parsed option.  */
+
+  int error = 0;
+  struct gengetopt_args_info local_args_info;
+  
+  int override;
+  int initialize;
+  int check_required;
+  int check_ambiguity;
+  
+  package_name = argv[0];
+  
+  override = params->override;
+  initialize = params->initialize;
+  check_required = params->check_required;
+  check_ambiguity = params->check_ambiguity;
+
+  if (initialize)
+    imagetag_cmdline_init (args_info);
+
+  imagetag_cmdline_init (&local_args_info);
+
+  optarg = 0;
+  optind = 0;
+  opterr = params->print_errors;
+  optopt = '?';
+
+  while (1)
+    {
+      int option_index = 0;
+
+      static struct option long_options[] = {
+        { "help",      0, NULL, 'h' },
+        { "version",   0, NULL, 'V' },
+        { "kernel",    1, NULL, 'i' },
+        { "rootfs",    1, NULL, 'f' },
+        { "output",    1, NULL, 'o' },
+        { "cfe",       1, NULL, 0 },
+        { "boardid",   1, NULL, 'b' },
+        { "chipid",    1, NULL, 'c' },
+        { "flash-start",       1, NULL, 's' },
+        { "image-offset",      1, NULL, 'n' },
+        { "tag-version",       1, NULL, 'v' },
+        { "signature", 1, NULL, 'a' },
+        { "signature2",        1, NULL, 'm' },
+        { "block-size",        1, NULL, 'k' },
+        { "load-addr", 1, NULL, 'l' },
+        { "entry",     1, NULL, 'e' },
+        { "layoutver", 1, NULL, 'y' },
+        { "info1",     1, NULL, '1' },
+        { "altinfo",   1, NULL, 0 },
+        { "info2",     1, NULL, '2' },
+        { "root-first",        0, NULL, 0 },
+        { "rsa-signature",     1, NULL, 'r' },
+        { "second-image-flag", 1, NULL, 0 },
+        { "inactive",  1, NULL, 0 },
+        { "reserved2", 1, NULL, 0 },
+        { "kernel-file-has-header",    0, NULL, 0 },
+        { "pad",       1, NULL, 'p' },
+        { "align-rootfs",      0, NULL, 0 },
+        { 0,  0, 0, 0 }
+      };
+
+      c = getopt_long (argc, argv, "hVi:f:o:b:c:s:n:v:a:m:k:l:e:y:1:2:r:p:", long_options, &option_index);
+
+      if (c == -1) break;      /* Exit from `while (1)' loop.  */
+
+      switch (c)
+        {
+        case 'h':      /* Print help and exit.  */
+          imagetag_cmdline_print_help ();
+          imagetag_cmdline_free (&local_args_info);
+          exit (EXIT_SUCCESS);
+
+        case 'V':      /* Print version and exit.  */
+          imagetag_cmdline_print_version ();
+          imagetag_cmdline_free (&local_args_info);
+          exit (EXIT_SUCCESS);
+
+        case 'i':      /* File with LZMA compressed kernel to include in the image..  */
+        
+        
+          if (update_arg( (void *)&(args_info->kernel_arg), 
+               &(args_info->kernel_orig), &(args_info->kernel_given),
+              &(local_args_info.kernel_given), optarg, 0, 0, ARG_STRING,
+              check_ambiguity, override, 0, 0,
+              "kernel", 'i',
+              additional_error))
+            goto failure;
+        
+          break;
+        case 'f':      /* File with RootFS to include in the image..  */
+        
+        
+          if (update_arg( (void *)&(args_info->rootfs_arg), 
+               &(args_info->rootfs_orig), &(args_info->rootfs_given),
+              &(local_args_info.rootfs_given), optarg, 0, 0, ARG_STRING,
+              check_ambiguity, override, 0, 0,
+              "rootfs", 'f',
+              additional_error))
+            goto failure;
+        
+          break;
+        case 'o':      /* Name of output file..  */
+        
+        
+          if (update_arg( (void *)&(args_info->output_arg), 
+               &(args_info->output_orig), &(args_info->output_given),
+              &(local_args_info.output_given), optarg, 0, 0, ARG_STRING,
+              check_ambiguity, override, 0, 0,
+              "output", 'o',
+              additional_error))
+            goto failure;
+        
+          break;
+        case 'b':      /* Board ID to set in the image (must match what router expects, e.g. \"96345GW2\")..  */
+        
+        
+          if (update_arg( (void *)&(args_info->boardid_arg), 
+               &(args_info->boardid_orig), &(args_info->boardid_given),
+              &(local_args_info.boardid_given), optarg, 0, 0, ARG_STRING,
+              check_ambiguity, override, 0, 0,
+              "boardid", 'b',
+              additional_error))
+            goto failure;
+        
+          break;
+        case 'c':      /* Chip ID to set in the image (must match the actual hardware, e.g. \"6345\")..  */
+        
+        
+          if (update_arg( (void *)&(args_info->chipid_arg), 
+               &(args_info->chipid_orig), &(args_info->chipid_given),
+              &(local_args_info.chipid_given), optarg, 0, 0, ARG_STRING,
+              check_ambiguity, override, 0, 0,
+              "chipid", 'c',
+              additional_error))
+            goto failure;
+        
+          break;
+        case 's':      /* Flash start address..  */
+        
+        
+          if (update_arg( (void *)&(args_info->flash_start_arg), 
+               &(args_info->flash_start_orig), &(args_info->flash_start_given),
+              &(local_args_info.flash_start_given), optarg, 0, "0xBFC00000", ARG_STRING,
+              check_ambiguity, override, 0, 0,
+              "flash-start", 's',
+              additional_error))
+            goto failure;
+        
+          break;
+        case 'n':      /* Offset from start address for the first byte after the CFE (in memory)..  */
+        
+        
+          if (update_arg( (void *)&(args_info->image_offset_arg), 
+               &(args_info->image_offset_orig), &(args_info->image_offset_given),
+              &(local_args_info.image_offset_given), optarg, 0, "0x10000", ARG_STRING,
+              check_ambiguity, override, 0, 0,
+              "image-offset", 'n',
+              additional_error))
+            goto failure;
+        
+          break;
+        case 'v':      /* Version number for imagetag format..  */
+        
+        
+          if (update_arg( (void *)&(args_info->tag_version_arg), 
+               &(args_info->tag_version_orig), &(args_info->tag_version_given),
+              &(local_args_info.tag_version_given), optarg, 0, "6", ARG_STRING,
+              check_ambiguity, override, 0, 0,
+              "tag-version", 'v',
+              additional_error))
+            goto failure;
+        
+          break;
+        case 'a':      /* Magic string (signature), for boards that need it..  */
+        
+        
+          if (update_arg( (void *)&(args_info->signature_arg), 
+               &(args_info->signature_orig), &(args_info->signature_given),
+              &(local_args_info.signature_given), optarg, 0, "Broadcom Corporatio", ARG_STRING,
+              check_ambiguity, override, 0, 0,
+              "signature", 'a',
+              additional_error))
+            goto failure;
+        
+          break;
+        case 'm':      /* Second magic string (signature2)..  */
+        
+        
+          if (update_arg( (void *)&(args_info->signature2_arg), 
+               &(args_info->signature2_orig), &(args_info->signature2_given),
+              &(local_args_info.signature2_given), optarg, 0, "ver. 2.0", ARG_STRING,
+              check_ambiguity, override, 0, 0,
+              "signature2", 'm',
+              additional_error))
+            goto failure;
+        
+          break;
+        case 'k':      /* Flash erase block size..  */
+        
+        
+          if (update_arg( (void *)&(args_info->block_size_arg), 
+               &(args_info->block_size_orig), &(args_info->block_size_given),
+              &(local_args_info.block_size_given), optarg, 0, "0x10000", ARG_STRING,
+              check_ambiguity, override, 0, 0,
+              "block-size", 'k',
+              additional_error))
+            goto failure;
+        
+          break;
+        case 'l':      /* Kernel load address..  */
+        
+        
+          if (update_arg( (void *)&(args_info->load_addr_arg), 
+               &(args_info->load_addr_orig), &(args_info->load_addr_given),
+              &(local_args_info.load_addr_given), optarg, 0, 0, ARG_STRING,
+              check_ambiguity, override, 0, 0,
+              "load-addr", 'l',
+              additional_error))
+            goto failure;
+        
+          break;
+        case 'e':      /* Address where the kernel entry point will be for booting..  */
+        
+        
+          if (update_arg( (void *)&(args_info->entry_arg), 
+               &(args_info->entry_orig), &(args_info->entry_given),
+              &(local_args_info.entry_given), optarg, 0, 0, ARG_STRING,
+              check_ambiguity, override, 0, 0,
+              "entry", 'e',
+              additional_error))
+            goto failure;
+        
+          break;
+        case 'y':      /* Flash layout version (version 2.2x of the Broadcom code requires this)..  */
+        
+        
+          if (update_arg( (void *)&(args_info->layoutver_arg), 
+               &(args_info->layoutver_orig), &(args_info->layoutver_given),
+              &(local_args_info.layoutver_given), optarg, 0, 0, ARG_STRING,
+              check_ambiguity, override, 0, 0,
+              "layoutver", 'y',
+              additional_error))
+            goto failure;
+        
+          break;
+        case '1':      /* String for first vendor information section..  */
+        
+        
+          if (update_arg( (void *)&(args_info->info1_arg), 
+               &(args_info->info1_orig), &(args_info->info1_given),
+              &(local_args_info.info1_given), optarg, 0, 0, ARG_STRING,
+              check_ambiguity, override, 0, 0,
+              "info1", '1',
+              additional_error))
+            goto failure;
+        
+          break;
+        case '2':      /* String for second vendor information section..  */
+        
+        
+          if (update_arg( (void *)&(args_info->info2_arg), 
+               &(args_info->info2_orig), &(args_info->info2_given),
+              &(local_args_info.info2_given), optarg, 0, 0, ARG_STRING,
+              check_ambiguity, override, 0, 0,
+              "info2", '2',
+              additional_error))
+            goto failure;
+        
+          break;
+        case 'r':      /* String for RSA Signature section..  */
+        
+        
+          if (update_arg( (void *)&(args_info->rsa_signature_arg), 
+               &(args_info->rsa_signature_orig), &(args_info->rsa_signature_given),
+              &(local_args_info.rsa_signature_given), optarg, 0, 0, ARG_STRING,
+              check_ambiguity, override, 0, 0,
+              "rsa-signature", 'r',
+              additional_error))
+            goto failure;
+        
+          break;
+        case 'p':      /* Pad the image to this size if smaller (in MiB).  */
+        
+        
+          if (update_arg( (void *)&(args_info->pad_arg), 
+               &(args_info->pad_orig), &(args_info->pad_given),
+              &(local_args_info.pad_given), optarg, 0, 0, ARG_INT,
+              check_ambiguity, override, 0, 0,
+              "pad", 'p',
+              additional_error))
+            goto failure;
+        
+          break;
+
+        case 0:        /* Long option with no short option */
+          /* File with CFE to include in the image..  */
+          if (strcmp (long_options[option_index].name, "cfe") == 0)
+          {
+          
+          
+            if (update_arg( (void *)&(args_info->cfe_arg), 
+                 &(args_info->cfe_orig), &(args_info->cfe_given),
+                &(local_args_info.cfe_given), optarg, 0, 0, ARG_STRING,
+                check_ambiguity, override, 0, 0,
+                "cfe", '-',
+                additional_error))
+              goto failure;
+          
+          }
+          /* String for vendor information section (alternate/pirelli)..  */
+          else if (strcmp (long_options[option_index].name, "altinfo") == 0)
+          {
+          
+          
+            if (update_arg( (void *)&(args_info->altinfo_arg), 
+                 &(args_info->altinfo_orig), &(args_info->altinfo_given),
+                &(local_args_info.altinfo_given), optarg, 0, 0, ARG_STRING,
+                check_ambiguity, override, 0, 0,
+                "altinfo", '-',
+                additional_error))
+              goto failure;
+          
+          }
+          /* Put the rootfs before the kernel (only for stock images, e.g. captured from the router's flash memory)..  */
+          else if (strcmp (long_options[option_index].name, "root-first") == 0)
+          {
+          
+          
+            if (update_arg((void *)&(args_info->root_first_flag), 0, &(args_info->root_first_given),
+                &(local_args_info.root_first_given), optarg, 0, 0, ARG_FLAG,
+                check_ambiguity, override, 1, 0, "root-first", '-',
+                additional_error))
+              goto failure;
+          
+          }
+          /* Dual Image Flag (2=not-specified)..  */
+          else if (strcmp (long_options[option_index].name, "second-image-flag") == 0)
+          {
+          
+          
+            if (update_arg( (void *)&(args_info->second_image_flag_arg), 
+                 &(args_info->second_image_flag_orig), &(args_info->second_image_flag_given),
+                &(local_args_info.second_image_flag_given), optarg, imagetag_cmdline_second_image_flag_values, "2", ARG_STRING,
+                check_ambiguity, override, 0, 0,
+                "second-image-flag", '-',
+                additional_error))
+              goto failure;
+          
+          }
+          /* Inactive Flag (2=not-specified)..  */
+          else if (strcmp (long_options[option_index].name, "inactive") == 0)
+          {
+          
+          
+            if (update_arg( (void *)&(args_info->inactive_arg), 
+                 &(args_info->inactive_orig), &(args_info->inactive_given),
+                &(local_args_info.inactive_given), optarg, imagetag_cmdline_inactive_values, "2", ARG_STRING,
+                check_ambiguity, override, 0, 0,
+                "inactive", '-',
+                additional_error))
+              goto failure;
+          
+          }
+          /* String for second reserved section..  */
+          else if (strcmp (long_options[option_index].name, "reserved2") == 0)
+          {
+          
+          
+            if (update_arg( (void *)&(args_info->reserved2_arg), 
+                 &(args_info->reserved2_orig), &(args_info->reserved2_given),
+                &(local_args_info.reserved2_given), optarg, 0, 0, ARG_STRING,
+                check_ambiguity, override, 0, 0,
+                "reserved2", '-',
+                additional_error))
+              goto failure;
+          
+          }
+          /* Indicates that the kernel file includes the kernel header with correct load address and entry point, so no changes are needed.  */
+          else if (strcmp (long_options[option_index].name, "kernel-file-has-header") == 0)
+          {
+          
+          
+            if (update_arg((void *)&(args_info->kernel_file_has_header_flag), 0, &(args_info->kernel_file_has_header_given),
+                &(local_args_info.kernel_file_has_header_given), optarg, 0, 0, ARG_FLAG,
+                check_ambiguity, override, 1, 0, "kernel-file-has-header", '-',
+                additional_error))
+              goto failure;
+          
+          }
+          /* Align the rootfs start to erase block size.  */
+          else if (strcmp (long_options[option_index].name, "align-rootfs") == 0)
+          {
+          
+          
+            if (update_arg((void *)&(args_info->align_rootfs_flag), 0, &(args_info->align_rootfs_given),
+                &(local_args_info.align_rootfs_given), optarg, 0, 0, ARG_FLAG,
+                check_ambiguity, override, 1, 0, "align-rootfs", '-',
+                additional_error))
+              goto failure;
+          
+          }
+          
+          break;
+        case '?':      /* Invalid option.  */
+          /* `getopt_long' already printed an error message.  */
+          goto failure;
+
+        default:       /* bug: option not considered.  */
+          fprintf (stderr, "%s: option unknown: %c%s\n", IMAGETAG_CMDLINE_PACKAGE, c, (additional_error ? additional_error : ""));
+          abort ();
+        } /* switch */
+    } /* while */
+
+
+
+  if (check_required)
+    {
+      error += imagetag_cmdline_required2 (args_info, argv[0], additional_error);
+    }
+
+  imagetag_cmdline_release (&local_args_info);
+
+  if ( error )
+    return (EXIT_FAILURE);
+
+  return 0;
+
+failure:
+  
+  imagetag_cmdline_release (&local_args_info);
+  return (EXIT_FAILURE);
+}
diff --git a/trunk/tools/firmware-utils/src/imagetag_cmdline.h b/trunk/tools/firmware-utils/src/imagetag_cmdline.h
new file mode 100644 (file)
index 0000000..3f55c50
--- /dev/null
@@ -0,0 +1,275 @@
+/** @file imagetag_cmdline.h
+ *  @brief The header file for the command line option parser
+ *  generated by GNU Gengetopt version 2.22.5
+ *  http://www.gnu.org/software/gengetopt.
+ *  DO NOT modify this file, since it can be overwritten
+ *  @author GNU Gengetopt by Lorenzo Bettini */
+
+#ifndef IMAGETAG_CMDLINE_H
+#define IMAGETAG_CMDLINE_H
+
+/* If we use autoconf.  */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h> /* for FILE */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#ifndef IMAGETAG_CMDLINE_PACKAGE
+/** @brief the program name (used for printing errors) */
+#define IMAGETAG_CMDLINE_PACKAGE "imagetag"
+#endif
+
+#ifndef IMAGETAG_CMDLINE_PACKAGE_NAME
+/** @brief the complete program name (used for help and version) */
+#define IMAGETAG_CMDLINE_PACKAGE_NAME "imagetag"
+#endif
+
+#ifndef IMAGETAG_CMDLINE_VERSION
+/** @brief the program version */
+#define IMAGETAG_CMDLINE_VERSION "2.0.0"
+#endif
+
+/** @brief Where the command line options are stored */
+struct gengetopt_args_info
+{
+  const char *help_help; /**< @brief Print help and exit help description.  */
+  const char *version_help; /**< @brief Print version and exit help description.  */
+  char * kernel_arg;   /**< @brief File with LZMA compressed kernel to include in the image..  */
+  char * kernel_orig;  /**< @brief File with LZMA compressed kernel to include in the image. original value given at command line.  */
+  const char *kernel_help; /**< @brief File with LZMA compressed kernel to include in the image. help description.  */
+  char * rootfs_arg;   /**< @brief File with RootFS to include in the image..  */
+  char * rootfs_orig;  /**< @brief File with RootFS to include in the image. original value given at command line.  */
+  const char *rootfs_help; /**< @brief File with RootFS to include in the image. help description.  */
+  char * output_arg;   /**< @brief Name of output file..  */
+  char * output_orig;  /**< @brief Name of output file. original value given at command line.  */
+  const char *output_help; /**< @brief Name of output file. help description.  */
+  char * cfe_arg;      /**< @brief File with CFE to include in the image..  */
+  char * cfe_orig;     /**< @brief File with CFE to include in the image. original value given at command line.  */
+  const char *cfe_help; /**< @brief File with CFE to include in the image. help description.  */
+  char * boardid_arg;  /**< @brief Board ID to set in the image (must match what router expects, e.g. \"96345GW2\")..  */
+  char * boardid_orig; /**< @brief Board ID to set in the image (must match what router expects, e.g. \"96345GW2\"). original value given at command line.  */
+  const char *boardid_help; /**< @brief Board ID to set in the image (must match what router expects, e.g. \"96345GW2\"). help description.  */
+  char * chipid_arg;   /**< @brief Chip ID to set in the image (must match the actual hardware, e.g. \"6345\")..  */
+  char * chipid_orig;  /**< @brief Chip ID to set in the image (must match the actual hardware, e.g. \"6345\"). original value given at command line.  */
+  const char *chipid_help; /**< @brief Chip ID to set in the image (must match the actual hardware, e.g. \"6345\"). help description.  */
+  char * flash_start_arg;      /**< @brief Flash start address. (default='0xBFC00000').  */
+  char * flash_start_orig;     /**< @brief Flash start address. original value given at command line.  */
+  const char *flash_start_help; /**< @brief Flash start address. help description.  */
+  char * image_offset_arg;     /**< @brief Offset from start address for the first byte after the CFE (in memory). (default='0x10000').  */
+  char * image_offset_orig;    /**< @brief Offset from start address for the first byte after the CFE (in memory). original value given at command line.  */
+  const char *image_offset_help; /**< @brief Offset from start address for the first byte after the CFE (in memory). help description.  */
+  char * tag_version_arg;      /**< @brief Version number for imagetag format. (default='6').  */
+  char * tag_version_orig;     /**< @brief Version number for imagetag format. original value given at command line.  */
+  const char *tag_version_help; /**< @brief Version number for imagetag format. help description.  */
+  char * signature_arg;        /**< @brief Magic string (signature), for boards that need it. (default='Broadcom Corporatio').  */
+  char * signature_orig;       /**< @brief Magic string (signature), for boards that need it. original value given at command line.  */
+  const char *signature_help; /**< @brief Magic string (signature), for boards that need it. help description.  */
+  char * signature2_arg;       /**< @brief Second magic string (signature2). (default='ver. 2.0').  */
+  char * signature2_orig;      /**< @brief Second magic string (signature2). original value given at command line.  */
+  const char *signature2_help; /**< @brief Second magic string (signature2). help description.  */
+  char * block_size_arg;       /**< @brief Flash erase block size. (default='0x10000').  */
+  char * block_size_orig;      /**< @brief Flash erase block size. original value given at command line.  */
+  const char *block_size_help; /**< @brief Flash erase block size. help description.  */
+  char * load_addr_arg;        /**< @brief Kernel load address..  */
+  char * load_addr_orig;       /**< @brief Kernel load address. original value given at command line.  */
+  const char *load_addr_help; /**< @brief Kernel load address. help description.  */
+  char * entry_arg;    /**< @brief Address where the kernel entry point will be for booting..  */
+  char * entry_orig;   /**< @brief Address where the kernel entry point will be for booting. original value given at command line.  */
+  const char *entry_help; /**< @brief Address where the kernel entry point will be for booting. help description.  */
+  char * layoutver_arg;        /**< @brief Flash layout version (version 2.2x of the Broadcom code requires this)..  */
+  char * layoutver_orig;       /**< @brief Flash layout version (version 2.2x of the Broadcom code requires this). original value given at command line.  */
+  const char *layoutver_help; /**< @brief Flash layout version (version 2.2x of the Broadcom code requires this). help description.  */
+  char * info1_arg;    /**< @brief String for first vendor information section..  */
+  char * info1_orig;   /**< @brief String for first vendor information section. original value given at command line.  */
+  const char *info1_help; /**< @brief String for first vendor information section. help description.  */
+  char * altinfo_arg;  /**< @brief String for vendor information section (alternate/pirelli)..  */
+  char * altinfo_orig; /**< @brief String for vendor information section (alternate/pirelli). original value given at command line.  */
+  const char *altinfo_help; /**< @brief String for vendor information section (alternate/pirelli). help description.  */
+  char * info2_arg;    /**< @brief String for second vendor information section..  */
+  char * info2_orig;   /**< @brief String for second vendor information section. original value given at command line.  */
+  const char *info2_help; /**< @brief String for second vendor information section. help description.  */
+  int root_first_flag; /**< @brief Put the rootfs before the kernel (only for stock images, e.g. captured from the router's flash memory). (default=off).  */
+  const char *root_first_help; /**< @brief Put the rootfs before the kernel (only for stock images, e.g. captured from the router's flash memory). help description.  */
+  char * rsa_signature_arg;    /**< @brief String for RSA Signature section..  */
+  char * rsa_signature_orig;   /**< @brief String for RSA Signature section. original value given at command line.  */
+  const char *rsa_signature_help; /**< @brief String for RSA Signature section. help description.  */
+  char * second_image_flag_arg;        /**< @brief Dual Image Flag (2=not-specified). (default='2').  */
+  char * second_image_flag_orig;       /**< @brief Dual Image Flag (2=not-specified). original value given at command line.  */
+  const char *second_image_flag_help; /**< @brief Dual Image Flag (2=not-specified). help description.  */
+  char * inactive_arg; /**< @brief Inactive Flag (2=not-specified). (default='2').  */
+  char * inactive_orig;        /**< @brief Inactive Flag (2=not-specified). original value given at command line.  */
+  const char *inactive_help; /**< @brief Inactive Flag (2=not-specified). help description.  */
+  char * reserved2_arg;        /**< @brief String for second reserved section..  */
+  char * reserved2_orig;       /**< @brief String for second reserved section. original value given at command line.  */
+  const char *reserved2_help; /**< @brief String for second reserved section. help description.  */
+  int kernel_file_has_header_flag;     /**< @brief Indicates that the kernel file includes the kernel header with correct load address and entry point, so no changes are needed (default=off).  */
+  const char *kernel_file_has_header_help; /**< @brief Indicates that the kernel file includes the kernel header with correct load address and entry point, so no changes are needed help description.  */
+  int pad_arg; /**< @brief Pad the image to this size if smaller (in MiB).  */
+  char * pad_orig;     /**< @brief Pad the image to this size if smaller (in MiB) original value given at command line.  */
+  const char *pad_help; /**< @brief Pad the image to this size if smaller (in MiB) help description.  */
+  int align_rootfs_flag;       /**< @brief Align the rootfs start to erase block size (default=off).  */
+  const char *align_rootfs_help; /**< @brief Align the rootfs start to erase block size help description.  */
+  
+  unsigned int help_given ;    /**< @brief Whether help was given.  */
+  unsigned int version_given ; /**< @brief Whether version was given.  */
+  unsigned int kernel_given ;  /**< @brief Whether kernel was given.  */
+  unsigned int rootfs_given ;  /**< @brief Whether rootfs was given.  */
+  unsigned int output_given ;  /**< @brief Whether output was given.  */
+  unsigned int cfe_given ;     /**< @brief Whether cfe was given.  */
+  unsigned int boardid_given ; /**< @brief Whether boardid was given.  */
+  unsigned int chipid_given ;  /**< @brief Whether chipid was given.  */
+  unsigned int flash_start_given ;     /**< @brief Whether flash-start was given.  */
+  unsigned int image_offset_given ;    /**< @brief Whether image-offset was given.  */
+  unsigned int tag_version_given ;     /**< @brief Whether tag-version was given.  */
+  unsigned int signature_given ;       /**< @brief Whether signature was given.  */
+  unsigned int signature2_given ;      /**< @brief Whether signature2 was given.  */
+  unsigned int block_size_given ;      /**< @brief Whether block-size was given.  */
+  unsigned int load_addr_given ;       /**< @brief Whether load-addr was given.  */
+  unsigned int entry_given ;   /**< @brief Whether entry was given.  */
+  unsigned int layoutver_given ;       /**< @brief Whether layoutver was given.  */
+  unsigned int info1_given ;   /**< @brief Whether info1 was given.  */
+  unsigned int altinfo_given ; /**< @brief Whether altinfo was given.  */
+  unsigned int info2_given ;   /**< @brief Whether info2 was given.  */
+  unsigned int root_first_given ;      /**< @brief Whether root-first was given.  */
+  unsigned int rsa_signature_given ;   /**< @brief Whether rsa-signature was given.  */
+  unsigned int second_image_flag_given ;       /**< @brief Whether second-image-flag was given.  */
+  unsigned int inactive_given ;        /**< @brief Whether inactive was given.  */
+  unsigned int reserved2_given ;       /**< @brief Whether reserved2 was given.  */
+  unsigned int kernel_file_has_header_given ;  /**< @brief Whether kernel-file-has-header was given.  */
+  unsigned int pad_given ;     /**< @brief Whether pad was given.  */
+  unsigned int align_rootfs_given ;    /**< @brief Whether align-rootfs was given.  */
+
+} ;
+
+/** @brief The additional parameters to pass to parser functions */
+struct imagetag_cmdline_params
+{
+  int override; /**< @brief whether to override possibly already present options (default 0) */
+  int initialize; /**< @brief whether to initialize the option structure gengetopt_args_info (default 1) */
+  int check_required; /**< @brief whether to check that all required options were provided (default 1) */
+  int check_ambiguity; /**< @brief whether to check for options already specified in the option structure gengetopt_args_info (default 0) */
+  int print_errors; /**< @brief whether getopt_long should print an error message for a bad option (default 1) */
+} ;
+
+/** @brief the purpose string of the program */
+extern const char *gengetopt_args_info_purpose;
+/** @brief the usage string of the program */
+extern const char *gengetopt_args_info_usage;
+/** @brief all the lines making the help output */
+extern const char *gengetopt_args_info_help[];
+
+/**
+ * The command line parser
+ * @param argc the number of command line options
+ * @param argv the command line options
+ * @param args_info the structure where option information will be stored
+ * @return 0 if everything went fine, NON 0 if an error took place
+ */
+int imagetag_cmdline (int argc, char **argv,
+  struct gengetopt_args_info *args_info);
+
+/**
+ * The command line parser (version with additional parameters - deprecated)
+ * @param argc the number of command line options
+ * @param argv the command line options
+ * @param args_info the structure where option information will be stored
+ * @param override whether to override possibly already present options
+ * @param initialize whether to initialize the option structure my_args_info
+ * @param check_required whether to check that all required options were provided
+ * @return 0 if everything went fine, NON 0 if an error took place
+ * @deprecated use imagetag_cmdline_ext() instead
+ */
+int imagetag_cmdline2 (int argc, char **argv,
+  struct gengetopt_args_info *args_info,
+  int override, int initialize, int check_required);
+
+/**
+ * The command line parser (version with additional parameters)
+ * @param argc the number of command line options
+ * @param argv the command line options
+ * @param args_info the structure where option information will be stored
+ * @param params additional parameters for the parser
+ * @return 0 if everything went fine, NON 0 if an error took place
+ */
+int imagetag_cmdline_ext (int argc, char **argv,
+  struct gengetopt_args_info *args_info,
+  struct imagetag_cmdline_params *params);
+
+/**
+ * Save the contents of the option struct into an already open FILE stream.
+ * @param outfile the stream where to dump options
+ * @param args_info the option struct to dump
+ * @return 0 if everything went fine, NON 0 if an error took place
+ */
+int imagetag_cmdline_dump(FILE *outfile,
+  struct gengetopt_args_info *args_info);
+
+/**
+ * Save the contents of the option struct into a (text) file.
+ * This file can be read by the config file parser (if generated by gengetopt)
+ * @param filename the file where to save
+ * @param args_info the option struct to save
+ * @return 0 if everything went fine, NON 0 if an error took place
+ */
+int imagetag_cmdline_file_save(const char *filename,
+  struct gengetopt_args_info *args_info);
+
+/**
+ * Print the help
+ */
+void imagetag_cmdline_print_help(void);
+/**
+ * Print the version
+ */
+void imagetag_cmdline_print_version(void);
+
+/**
+ * Initializes all the fields a imagetag_cmdline_params structure 
+ * to their default values
+ * @param params the structure to initialize
+ */
+void imagetag_cmdline_params_init(struct imagetag_cmdline_params *params);
+
+/**
+ * Allocates dynamically a imagetag_cmdline_params structure and initializes
+ * all its fields to their default values
+ * @return the created and initialized imagetag_cmdline_params structure
+ */
+struct imagetag_cmdline_params *imagetag_cmdline_params_create(void);
+
+/**
+ * Initializes the passed gengetopt_args_info structure's fields
+ * (also set default values for options that have a default)
+ * @param args_info the structure to initialize
+ */
+void imagetag_cmdline_init (struct gengetopt_args_info *args_info);
+/**
+ * Deallocates the string fields of the gengetopt_args_info structure
+ * (but does not deallocate the structure itself)
+ * @param args_info the structure to deallocate
+ */
+void imagetag_cmdline_free (struct gengetopt_args_info *args_info);
+
+/**
+ * Checks that all the required options were specified
+ * @param args_info the structure to check
+ * @param prog_name the name of the program that will be used to print
+ *   possible errors
+ * @return
+ */
+int imagetag_cmdline_required (struct gengetopt_args_info *args_info,
+  const char *prog_name);
+
+extern const char *imagetag_cmdline_second_image_flag_values[];  /**< @brief Possible values for second-image-flag. */
+extern const char *imagetag_cmdline_inactive_values[];  /**< @brief Possible values for inactive. */
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* IMAGETAG_CMDLINE_H */
diff --git a/trunk/tools/firmware-utils/src/lzma2eva.c b/trunk/tools/firmware-utils/src/lzma2eva.c
new file mode 100644 (file)
index 0000000..0bc13fa
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+    lzma2eva - convert lzma-compressed file to AVM EVA bootloader format
+    Copyright (C) 2007  Enrik Berkhan <Enrik.Berkhan@inka.de>
+
+    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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+*/
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <zlib.h> /* crc32 */
+
+#define checksum_add32(csum, data) \
+  csum += ((uint8_t *)&data)[0]; \
+  csum += ((uint8_t *)&data)[1]; \
+  csum += ((uint8_t *)&data)[2]; \
+  csum += ((uint8_t *)&data)[3];
+
+void
+usage(void)
+{
+  fprintf(stderr, "usage: lzma2eva <loadadddr> <entry> <lzmafile> <evafile>\n");
+  exit(1);
+}
+
+void
+pexit(const char *msg)
+{
+  perror(msg);
+  exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+
+  const char *infile, *outfile;
+  FILE *in, *out;
+  static const uint8_t buf[4096];
+  size_t elems;
+
+  uint8_t properties;
+  uint32_t dictsize;
+  uint64_t datasize;
+
+  uint32_t magic = 0xfeed1281L;
+  uint32_t reclength = 0;
+  fpos_t reclengthpos;
+  uint32_t loadaddress = 0;
+  uint32_t type = 0x075a0201L; /* might be 7Z 2.1? */
+  uint32_t checksum = 0;
+
+  uint32_t compsize = 0;
+  fpos_t compsizepos;
+  uint32_t datasize32 = 0;
+  uint32_t datacrc32 = crc32(0, 0, 0);
+
+  uint32_t zero = 0;
+  uint32_t entry = 0;
+
+  if (argc != 5)
+    usage();
+
+  /* "parse" command line */
+  loadaddress = strtoul(argv[1], 0, 0);
+  entry = strtoul(argv[2], 0, 0);
+  infile = argv[3];
+  outfile = argv[4];
+
+  in = fopen(infile, "rb");
+  if (!in)
+    pexit("fopen");
+  out = fopen(outfile, "w+b");
+  if (!out)
+    pexit("fopen");
+
+  /* read LZMA header */
+  if (1 != fread(&properties, sizeof properties, 1, in))
+    pexit("fread");
+  if (1 != fread(&dictsize, sizeof dictsize, 1, in))
+    pexit("fread");
+  if (1 != fread(&datasize, sizeof datasize, 1, in))
+    pexit("fread");
+
+  /* write EVA header */
+  if (1 != fwrite(&magic, sizeof magic, 1, out))
+    pexit("fwrite");
+  if (fgetpos(out, &reclengthpos))
+    pexit("fgetpos");
+  if (1 != fwrite(&reclength, sizeof reclength, 1, out))
+    pexit("fwrite");
+  if (1 != fwrite(&loadaddress, sizeof loadaddress, 1, out))
+    pexit("fwrite");
+  if (1 != fwrite(&type, sizeof type, 1, out))
+    pexit("fwrite");
+
+  /* write EVA LZMA header */
+  if (fgetpos(out, &compsizepos))
+    pexit("fgetpos");
+  if (1 != fwrite(&compsize, sizeof compsize, 1, out))
+    pexit("fwrite");
+  /* XXX check length */
+  datasize32 = (uint32_t)datasize;
+  if (1 != fwrite(&datasize32, sizeof datasize32, 1, out))
+    pexit("fwrite");
+  if (1 != fwrite(&datacrc32, sizeof datacrc32, 1, out))
+    pexit("fwrite");
+
+  /* write modified LZMA header */
+  if (1 != fwrite(&properties, sizeof properties, 1, out))
+    pexit("fwrite");
+  if (1 != fwrite(&dictsize, sizeof dictsize, 1, out))
+    pexit("fwrite");
+  if (1 != fwrite(&zero, 3, 1, out))
+    pexit("fwrite");
+
+  /* copy compressed data, calculate crc32 */
+  while (0 < (elems = fread(&buf, sizeof buf[0], sizeof buf, in))) {
+    compsize += elems;
+    if (elems != fwrite(&buf, sizeof buf[0], elems, out))
+      pexit("fwrite");
+    datacrc32 = crc32(datacrc32, buf, elems);
+  }
+  if (ferror(in))
+    pexit("fread");
+  fclose(in);
+
+  /* re-write record length */
+  reclength = compsize + 24;
+  if (fsetpos(out, &reclengthpos))
+    pexit("fsetpos");
+  if (1 != fwrite(&reclength, sizeof reclength, 1, out))
+    pexit("fwrite");
+
+  /* re-write EVA LZMA header including size and data crc */
+  if (fsetpos(out, &compsizepos))
+    pexit("fsetpos");
+  if (1 != fwrite(&compsize, sizeof compsize, 1, out))
+    pexit("fwrite");
+  if (1 != fwrite(&datasize32, sizeof datasize32, 1, out))
+    pexit("fwrite");
+  if (1 != fwrite(&datacrc32, sizeof datacrc32, 1, out))
+    pexit("fwrite");
+
+  /* calculate record checksum */
+  checksum += reclength;
+  checksum += loadaddress;
+  checksum_add32(checksum, type);
+  checksum_add32(checksum, compsize);
+  checksum_add32(checksum, datasize32);
+  checksum_add32(checksum, datacrc32);
+  if (fseek(out, 0, SEEK_CUR))
+    pexit("fseek");
+  while (0 < (elems = fread(&buf, sizeof buf[0], sizeof buf, out))) {
+    size_t i;
+    for (i = 0; i < elems; ++i)
+      checksum += buf[i];
+  }
+  if (ferror(out))
+    pexit("fread");
+  if (fseek(out, 0, SEEK_CUR))
+    pexit("fseek");
+
+  checksum = ~checksum + 1;
+  if (1 != fwrite(&checksum, sizeof checksum, 1, out))
+    pexit("fwrite");
+
+  /* write entry record */
+  if (1 != fwrite(&zero, sizeof zero, 1, out))
+    pexit("fwrite");
+  if (1 != fwrite(&entry, sizeof entry, 1, out))
+    pexit("fwrite");
+
+  if (fclose(out))
+    pexit("fclose");
+
+  return 0;
+}
diff --git a/trunk/tools/firmware-utils/src/makeamitbin.c b/trunk/tools/firmware-utils/src/makeamitbin.c
new file mode 100644 (file)
index 0000000..5c33442
--- /dev/null
@@ -0,0 +1,316 @@
+/*
+ *  makeamitbin - create firmware binaries for MGB100
+ *
+ *  Copyright (C) 2007 Volker Weiss     <dev@tintuc.de>
+ *                     Christian Welzel <dev@welzel-online.ch>
+ *
+ *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+
+/* defaults: Level One WAP-0007 */
+static char *ascii1 = "DDC_RUS001";
+static char *ascii2 = "Queen";
+
+static struct hdrinfo {
+  char *name;
+       unsigned long unknown; /* can probably be any number, maybe version number */
+       int topalign;
+       unsigned int addr;
+       unsigned int size;
+} hdrinfo[] = {
+       { "bios", 0xc76be111, 1, 0x3fa000, 0x006000 },        /* BIOS */
+       { "recovery", 0xc76be222, 0, 0x3f0000, 0x004000 },    /* Recovery Loader */
+       { "linux", 0xc76bee9d, 0, 0x000000, 0x100000 },       /* Linux */
+       { "ramdisk", 0xc76bee9d, 0, 0x100000, 0x280000 },     /* ramdisk */
+       { "amitconfig", 0xc76bee8b, 0, 0x380000, 0x060000 },  /* AMIT config */
+       { "redboot", 0x00000000, 1, 0x3d0000, 0x030000 },     /* Redboot 128kB image */
+       { "redbootlow", 0, 0, 0x3e0000, 0x18000 },            /* Redboot 1. part */
+       { "redboothigh", 0, 0, 0x3fa000, 0x6000 },            /* Redboot 2. part */
+       { "linux3g", 0xcb5f06b5, 0, 0x000000, 0x100000 },       /* Linux */
+       { "ramdisk3g", 0xcb5f06b5, 0, 0x100000, 0x280000 },     /* ramdisk */
+       { NULL }
+};
+
+/*
+CHD2WLANU_R400b7
+
+11e1 6bc7
+22e2 6bc7
+5dc3 47c8
+5cc3 47c8
+21c3 47c8
+*/
+
+/*
+20060106_DDC_WAP-0007_R400b4
+
+11e1 6bc7
+22e2 6bc7
+9dee 6bc7
+9dee 6bc7
+8bee 6bc7
+*/
+
+/*
+WMU-6000FS_R400b6
+
+11e1 6bc7
+22e2 6bc7
+6d2d 0fc8
+6c2d 0fc8
+542d 0fc8
+*/
+
+/*
+WAP-0007(R4.00b8)_2006-10-02
+
+9979 5fc8
+22e2 6bc7
+c46e cec8
+c36e cec8
+a76e cec8
+*/
+
+
+
+#define HDRSIZE              80
+
+#define COPY_SHORT(d, o, v)  d[o+0] = (unsigned char)((v) & 0xff); \
+                             d[o+1] = (unsigned char)(((v) >> 8) & 0xff)
+#define COPY_LONG(d, o, v)   d[o+0] = (unsigned char)((v) & 0xff); \
+                             d[o+1] = (unsigned char)(((v) >> 8) & 0xff); \
+                                                                                                          d[o+2] = (unsigned char)(((v) >> 16) & 0xff); \
+                                                                                                          d[o+3] = (unsigned char)(((v) >> 24) & 0xff)
+#define READ_SHORT(d, o)     ((unsigned short)(d[o+0]) + \
+                             (((unsigned short)(d[o+1])) << 8))
+
+/*
+00..0d ASCII product ID
+0e..0f checksum of payload
+10..1b ASCII Queen
+1c..1f AMIT BIOS: 11e1 6bc7, Recovery Tool: 22e2 6bc7
+       Linux: 5dc3 47c8, ramdisk: 5cc3 47c8
+                        AMIT FS: 21c3 47c8    VERSION NUMBER??????
+20..23 offset in flash aligned to segment boundary
+24..27 length in flash aligned to segment boundary
+28..2b offset in flash (payload)
+2c..2f length (payload)
+30..3f always 0
+40..47 always 4248 0101 5000 0001 (last maybe .....0501)
+48..4b same as 20..23
+4c..4d always 0b00
+4e..4f inverted checksum of header
+*/
+
+unsigned short checksum(unsigned char *data, long size)
+{
+       long n;
+       unsigned short d, cs = 0;
+       for (n = 0; n < size; n += 2)
+       {
+               d = READ_SHORT(data, n);
+               cs += d;
+               if (cs < d)
+                       cs++;
+       }
+       if (size & 1)
+       {
+               d = data[n];
+               cs += d;
+               if (cs < d)
+                       cs++;
+       }
+       return cs;
+}
+
+void showhdr(unsigned char *hdr)
+{
+       int i, j;
+       for (j = 0; j < 5; j++)
+       {
+               for (i = 0; i < 16; i++)
+               {
+                       printf("%02x ", (unsigned int)(hdr[j * 16 + i]));
+               }
+               printf("   ");
+               for (i = 0; i < 16; i++)
+               {
+                       unsigned char d = hdr[j * 16 + i];
+                       printf("%c", (d >= ' ' && d < 127) ? d : '.');
+               }
+               printf("\n");
+       }
+}
+
+void makehdr(unsigned char *hdr, struct hdrinfo *info,
+             unsigned char *data, long size, int last)
+{
+       unsigned int offset = info->addr + 0x10;
+       memset(hdr, 0, HDRSIZE);
+       if (info->topalign)
+               offset = info->addr + info->size - size;        /* top align */
+       strncpy((char *)hdr + 0x00, ascii1, 14);
+       strncpy((char *)hdr + 0x10, ascii2, 12);
+       COPY_LONG(hdr, 0x1c, info->unknown);
+       COPY_LONG(hdr, 0x20, info->addr);
+       COPY_LONG(hdr, 0x24, info->size);
+       COPY_LONG(hdr, 0x28, offset);
+       COPY_LONG(hdr, 0x2c, size);
+       COPY_LONG(hdr, 0x40, 0x01014842);
+       COPY_LONG(hdr, 0x44, last ? 0x01050050 : 0x01000050);
+       COPY_LONG(hdr, 0x48, info->addr);
+       COPY_SHORT(hdr, 0x4c, info->unknown == 0xcb5f06b5 ? 0x0016 : 0x000b);
+       COPY_SHORT(hdr, 0x0e, checksum(data, size));
+       COPY_SHORT(hdr, 0x4e, ~checksum(hdr, HDRSIZE));
+}
+
+unsigned char *read_file(const char *name, long *size)
+{
+       FILE *f;
+       unsigned char *data = NULL;
+       *size = 0;
+       f = fopen(name, "r");
+       if (f != NULL)
+       {
+               if (fseek(f, 0, SEEK_END) == 0)
+               {
+           *size = ftell(f);
+                       if (*size != -1)
+                       {
+                               if (fseek(f, 0, SEEK_SET) == 0)
+                               {
+                                       data = (unsigned char *)malloc(*size);
+                                       if (data != NULL)
+                                       {
+                                               if (fread(data, sizeof(char), *size, f) != *size)
+                                               {
+                                                       free(data);
+                                                       data = NULL;
+                                               }
+                                       }
+                               }
+                       }
+               }
+               fclose(f);
+       }
+       return data;
+}
+
+struct hdrinfo *find_hdrinfo(const char *name)
+{
+       int n;
+       for (n = 0; hdrinfo[n].name != NULL; n++)
+       {
+               if (strcmp(name, hdrinfo[n].name) == 0)
+                       return &hdrinfo[n];
+       }
+       return NULL;
+}
+
+void oferror(FILE *f)
+{
+       printf("file error\n");
+       exit(2);
+}
+
+void showhelp(void)
+{
+       printf("Syntax: makeamitbin [options]\n");
+       printf("Options:\n");
+       printf("  -1 ID1\tFirmware identifier 1, e.g. 'DDC_RUS001' for manufacturer LevelOne\n");
+       printf("  -2 ID2\tFirmware identifier 2, 'Queen' in all known cases\n");
+       printf("  -o FILE\tOutput file\n");
+       printf("  -ids\t\tShow a list of known firmware identifiers.\n");
+       exit(1);
+}
+
+void show_fwids(void)
+{
+       printf("List of known firmware identifiers:\n");
+       printf("Manufacturer\t\tProduct\t\tIdentifier\n");
+       printf("=====================================================\n");
+       printf("Conceptronic\t\tCHD2WLANU\tLLM_RUS001\n");
+       printf("Pearl\t\t\tPE6643\t\tQueen\n");
+       printf("Micronica\t\tMGB100\t\tQueen\n");
+       printf("LevelOne\t\tWAP-0007\tDDC_RUS001\n");
+       printf("SMC\t\t\tWAPS-G\t\tSMC_RUS001\n");
+       printf("OvisLink (AirLive)\tWMU-6\t\tOVS_RUS001\n");
+       printf("SafeCom SWSAPUR-5\tFMW\t\tSafeco_RPS001\n");
+       exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+       unsigned char hdr[HDRSIZE];
+       unsigned char *data;
+       FILE *of;
+       char *outfile = NULL;
+       char *type;
+       struct hdrinfo *info;
+       long size;
+       int last = 0;
+       int n;
+       for (n = 1; n < argc; n++)
+       {
+               if (strcmp(argv[n], "-1") == 0)
+                       ascii1 = argv[n+1];
+               if (strcmp(argv[n], "-2") == 0)
+                       ascii2 = argv[n+1];
+               if (strcmp(argv[n], "-o") == 0)
+                       outfile = argv[n+1];
+               if (strcmp(argv[n], "-ids") == 0)
+                       show_fwids();
+       }
+       if (ascii1 == NULL || ascii2 == NULL || outfile == NULL)
+               showhelp();
+       of = fopen(outfile, "w");
+       if (of == NULL)
+               oferror(of);
+       for (n = 1; n < argc; n++)
+       {
+               if (strncmp(argv[n], "-", 1) != 0)
+               {
+                       type = argv[n++];
+                       if (n >= argc)
+                               showhelp();
+                       last = ((n + 1) >= argc);               /* dirty, options first! */
+                       info = find_hdrinfo(type);
+                       if (info == NULL)
+                               showhelp();
+                       data = read_file(argv[n], &size);
+                       if (data == NULL)
+                               showhelp();
+                       makehdr(hdr, info, data, size, last);
+                       /* showhdr(hdr); */
+                       if (fwrite(hdr, HDRSIZE, 1, of) != 1)
+                               oferror(of);
+                       if (fwrite(data, size, 1, of) != 1)
+                               oferror(of);
+                       free(data);
+               }
+               else
+                       n++;
+       }
+       if (fclose(of) != 0)
+               oferror(NULL);
+       return 0;
+}
diff --git a/trunk/tools/firmware-utils/src/md5.c b/trunk/tools/firmware-utils/src/md5.c
new file mode 100644 (file)
index 0000000..2039760
--- /dev/null
@@ -0,0 +1,307 @@
+
+
+/*
+ ***********************************************************************
+ ** md5.c -- the source code for MD5 routines                         **
+ ** RSA Data Security, Inc. MD5 Message-Digest Algorithm              **
+ ** Created: 2/17/90 RLR                                              **
+ ** Revised: 1/91 SRD,AJ,BSK,JT Reference C ver., 7/10 constant corr. **
+ ***********************************************************************
+ */
+
+/*
+ ***********************************************************************
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved.  **
+ **                                                                   **
+ ** License to copy and use this software is granted provided that    **
+ ** it is identified as the "RSA Data Security, Inc. MD5 Message-     **
+ ** Digest Algorithm" in all material mentioning or referencing this  **
+ ** software or this function.                                        **
+ **                                                                   **
+ ** License is also granted to make and use derivative works          **
+ ** provided that such works are identified as "derived from the RSA  **
+ ** Data Security, Inc. MD5 Message-Digest Algorithm" in all          **
+ ** material mentioning or referencing the derived work.              **
+ **                                                                   **
+ ** RSA Data Security, Inc. makes no representations concerning       **
+ ** either the merchantability of this software or the suitability    **
+ ** of this software for any particular purpose.  It is provided "as  **
+ ** is" without express or implied warranty of any kind.              **
+ **                                                                   **
+ ** These notices must be retained in any copies of any part of this  **
+ ** documentation and/or software.                                    **
+ ***********************************************************************
+ */
+
+#include <string.h>
+#include "md5.h"
+
+/*
+ ***********************************************************************
+ **  Message-digest routines:                                         **
+ **  To form the message digest for a message M                       **
+ **    (1) Initialize a context buffer mdContext using MD5_Init       **
+ **    (2) Call MD5_Update on mdContext and M                         **
+ **    (3) Call MD5_Final on mdContext                                **
+ **  The message digest is now in mdContext->digest[0...15]           **
+ ***********************************************************************
+ */
+
+/* forward declaration */
+static void Transform ();
+
+static unsigned char PADDING[64] = {
+  0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/* F, G, H and I are basic MD5 functions */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */
+/* Rotation is separate from addition to prevent recomputation */
+#define FF(a, b, c, d, x, s, ac) \
+  {(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+   (a) = ROTATE_LEFT ((a), (s)); \
+   (a) += (b); \
+  }
+#define GG(a, b, c, d, x, s, ac) \
+  {(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+   (a) = ROTATE_LEFT ((a), (s)); \
+   (a) += (b); \
+  }
+#define HH(a, b, c, d, x, s, ac) \
+  {(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+   (a) = ROTATE_LEFT ((a), (s)); \
+   (a) += (b); \
+  }
+#define II(a, b, c, d, x, s, ac) \
+  {(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+   (a) = ROTATE_LEFT ((a), (s)); \
+   (a) += (b); \
+  }
+
+#ifdef __STDC__
+#define UL(x)  x##U
+#else
+#define UL(x)  x
+#endif
+
+/* The routine MD5_Init initializes the message-digest context
+   mdContext. All fields are set to zero.
+ */
+void MD5_Init (mdContext)
+MD5_CTX *mdContext;
+{
+  mdContext->i[0] = mdContext->i[1] = (UINT4)0;
+
+  /* Load magic initialization constants.
+   */
+  mdContext->buf[0] = (UINT4)0x67452301;
+  mdContext->buf[1] = (UINT4)0xefcdab89;
+  mdContext->buf[2] = (UINT4)0x98badcfe;
+  mdContext->buf[3] = (UINT4)0x10325476;
+}
+
+/* The routine MD5Update updates the message-digest context to
+   account for the presence of each of the characters inBuf[0..inLen-1]
+   in the message whose digest is being computed.
+ */
+void MD5_Update (mdContext, inBuf, inLen)
+MD5_CTX *mdContext;
+unsigned char *inBuf;
+unsigned int inLen;
+{
+  UINT4 in[16];
+  int mdi;
+  unsigned int i, ii;
+
+  /* compute number of bytes mod 64 */
+  mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+  /* update number of bits */
+  if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0])
+    mdContext->i[1]++;
+  mdContext->i[0] += ((UINT4)inLen << 3);
+  mdContext->i[1] += ((UINT4)inLen >> 29);
+
+  while (inLen--) {
+    /* add new character to buffer, increment mdi */
+    mdContext->in[mdi++] = *inBuf++;
+
+    /* transform if necessary */
+    if (mdi == 0x40) {
+      for (i = 0, ii = 0; i < 16; i++, ii += 4)
+        in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
+                (((UINT4)mdContext->in[ii+2]) << 16) |
+                (((UINT4)mdContext->in[ii+1]) << 8) |
+                ((UINT4)mdContext->in[ii]);
+      Transform (mdContext->buf, in);
+      mdi = 0;
+    }
+  }
+}
+
+/* The routine MD5Final terminates the message-digest computation and
+   ends with the desired message digest in mdContext->digest[0...15].
+ */
+void MD5_Final (hash, mdContext)
+unsigned char hash[];
+MD5_CTX *mdContext;
+{
+  UINT4 in[16];
+  int mdi;
+  unsigned int i, ii;
+  unsigned int padLen;
+
+  /* save number of bits */
+  in[14] = mdContext->i[0];
+  in[15] = mdContext->i[1];
+
+  /* compute number of bytes mod 64 */
+  mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+  /* pad out to 56 mod 64 */
+  padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);
+  MD5_Update (mdContext, PADDING, padLen);
+
+  /* append length in bits and transform */
+  for (i = 0, ii = 0; i < 14; i++, ii += 4)
+    in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
+            (((UINT4)mdContext->in[ii+2]) << 16) |
+            (((UINT4)mdContext->in[ii+1]) << 8) |
+            ((UINT4)mdContext->in[ii]);
+  Transform (mdContext->buf, in);
+
+  /* store buffer in digest */
+  for (i = 0, ii = 0; i < 4; i++, ii += 4) {
+    mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF);
+    mdContext->digest[ii+1] =
+      (unsigned char)((mdContext->buf[i] >> 8) & 0xFF);
+    mdContext->digest[ii+2] =
+      (unsigned char)((mdContext->buf[i] >> 16) & 0xFF);
+    mdContext->digest[ii+3] =
+      (unsigned char)((mdContext->buf[i] >> 24) & 0xFF);
+  }
+  memcpy(hash, mdContext->digest, 16);
+}
+
+/* Basic MD5 step. Transforms buf based on in.
+ */
+static void Transform (buf, in)
+UINT4 *buf;
+UINT4 *in;
+{
+  UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
+
+  /* Round 1 */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+  FF ( a, b, c, d, in[ 0], S11, UL(3614090360)); /* 1 */
+  FF ( d, a, b, c, in[ 1], S12, UL(3905402710)); /* 2 */
+  FF ( c, d, a, b, in[ 2], S13, UL( 606105819)); /* 3 */
+  FF ( b, c, d, a, in[ 3], S14, UL(3250441966)); /* 4 */
+  FF ( a, b, c, d, in[ 4], S11, UL(4118548399)); /* 5 */
+  FF ( d, a, b, c, in[ 5], S12, UL(1200080426)); /* 6 */
+  FF ( c, d, a, b, in[ 6], S13, UL(2821735955)); /* 7 */
+  FF ( b, c, d, a, in[ 7], S14, UL(4249261313)); /* 8 */
+  FF ( a, b, c, d, in[ 8], S11, UL(1770035416)); /* 9 */
+  FF ( d, a, b, c, in[ 9], S12, UL(2336552879)); /* 10 */
+  FF ( c, d, a, b, in[10], S13, UL(4294925233)); /* 11 */
+  FF ( b, c, d, a, in[11], S14, UL(2304563134)); /* 12 */
+  FF ( a, b, c, d, in[12], S11, UL(1804603682)); /* 13 */
+  FF ( d, a, b, c, in[13], S12, UL(4254626195)); /* 14 */
+  FF ( c, d, a, b, in[14], S13, UL(2792965006)); /* 15 */
+  FF ( b, c, d, a, in[15], S14, UL(1236535329)); /* 16 */
+
+  /* Round 2 */
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+  GG ( a, b, c, d, in[ 1], S21, UL(4129170786)); /* 17 */
+  GG ( d, a, b, c, in[ 6], S22, UL(3225465664)); /* 18 */
+  GG ( c, d, a, b, in[11], S23, UL( 643717713)); /* 19 */
+  GG ( b, c, d, a, in[ 0], S24, UL(3921069994)); /* 20 */
+  GG ( a, b, c, d, in[ 5], S21, UL(3593408605)); /* 21 */
+  GG ( d, a, b, c, in[10], S22, UL(  38016083)); /* 22 */
+  GG ( c, d, a, b, in[15], S23, UL(3634488961)); /* 23 */
+  GG ( b, c, d, a, in[ 4], S24, UL(3889429448)); /* 24 */
+  GG ( a, b, c, d, in[ 9], S21, UL( 568446438)); /* 25 */
+  GG ( d, a, b, c, in[14], S22, UL(3275163606)); /* 26 */
+  GG ( c, d, a, b, in[ 3], S23, UL(4107603335)); /* 27 */
+  GG ( b, c, d, a, in[ 8], S24, UL(1163531501)); /* 28 */
+  GG ( a, b, c, d, in[13], S21, UL(2850285829)); /* 29 */
+  GG ( d, a, b, c, in[ 2], S22, UL(4243563512)); /* 30 */
+  GG ( c, d, a, b, in[ 7], S23, UL(1735328473)); /* 31 */
+  GG ( b, c, d, a, in[12], S24, UL(2368359562)); /* 32 */
+
+  /* Round 3 */
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+  HH ( a, b, c, d, in[ 5], S31, UL(4294588738)); /* 33 */
+  HH ( d, a, b, c, in[ 8], S32, UL(2272392833)); /* 34 */
+  HH ( c, d, a, b, in[11], S33, UL(1839030562)); /* 35 */
+  HH ( b, c, d, a, in[14], S34, UL(4259657740)); /* 36 */
+  HH ( a, b, c, d, in[ 1], S31, UL(2763975236)); /* 37 */
+  HH ( d, a, b, c, in[ 4], S32, UL(1272893353)); /* 38 */
+  HH ( c, d, a, b, in[ 7], S33, UL(4139469664)); /* 39 */
+  HH ( b, c, d, a, in[10], S34, UL(3200236656)); /* 40 */
+  HH ( a, b, c, d, in[13], S31, UL( 681279174)); /* 41 */
+  HH ( d, a, b, c, in[ 0], S32, UL(3936430074)); /* 42 */
+  HH ( c, d, a, b, in[ 3], S33, UL(3572445317)); /* 43 */
+  HH ( b, c, d, a, in[ 6], S34, UL(  76029189)); /* 44 */
+  HH ( a, b, c, d, in[ 9], S31, UL(3654602809)); /* 45 */
+  HH ( d, a, b, c, in[12], S32, UL(3873151461)); /* 46 */
+  HH ( c, d, a, b, in[15], S33, UL( 530742520)); /* 47 */
+  HH ( b, c, d, a, in[ 2], S34, UL(3299628645)); /* 48 */
+
+  /* Round 4 */
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+  II ( a, b, c, d, in[ 0], S41, UL(4096336452)); /* 49 */
+  II ( d, a, b, c, in[ 7], S42, UL(1126891415)); /* 50 */
+  II ( c, d, a, b, in[14], S43, UL(2878612391)); /* 51 */
+  II ( b, c, d, a, in[ 5], S44, UL(4237533241)); /* 52 */
+  II ( a, b, c, d, in[12], S41, UL(1700485571)); /* 53 */
+  II ( d, a, b, c, in[ 3], S42, UL(2399980690)); /* 54 */
+  II ( c, d, a, b, in[10], S43, UL(4293915773)); /* 55 */
+  II ( b, c, d, a, in[ 1], S44, UL(2240044497)); /* 56 */
+  II ( a, b, c, d, in[ 8], S41, UL(1873313359)); /* 57 */
+  II ( d, a, b, c, in[15], S42, UL(4264355552)); /* 58 */
+  II ( c, d, a, b, in[ 6], S43, UL(2734768916)); /* 59 */
+  II ( b, c, d, a, in[13], S44, UL(1309151649)); /* 60 */
+  II ( a, b, c, d, in[ 4], S41, UL(4149444226)); /* 61 */
+  II ( d, a, b, c, in[11], S42, UL(3174756917)); /* 62 */
+  II ( c, d, a, b, in[ 2], S43, UL( 718787259)); /* 63 */
+  II ( b, c, d, a, in[ 9], S44, UL(3951481745)); /* 64 */
+
+  buf[0] += a;
+  buf[1] += b;
+  buf[2] += c;
+  buf[3] += d;
+}
+
+/*
+ ***********************************************************************
+ ** End of md5.c                                                      **
+ ******************************** (cut) ********************************
+ */
diff --git a/trunk/tools/firmware-utils/src/md5.h b/trunk/tools/firmware-utils/src/md5.h
new file mode 100644 (file)
index 0000000..f7a0c96
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ ***********************************************************************
+ ** md5.h -- header file for implementation of MD5                    **
+ ** RSA Data Security, Inc. MD5 Message-Digest Algorithm              **
+ ** Created: 2/17/90 RLR                                              **
+ ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version               **
+ ** Revised (for MD5): RLR 4/27/91                                    **
+ **   -- G modified to have y&~z instead of y&z                       **
+ **   -- FF, GG, HH modified to add in last register done             **
+ **   -- Access pattern: round 2 works mod 5, round 3 works mod 3     **
+ **   -- distinct additive constant for each step                     **
+ **   -- round 4 added, working mod 7                                 **
+ ***********************************************************************
+ */
+
+/*
+ ***********************************************************************
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved.  **
+ **                                                                   **
+ ** License to copy and use this software is granted provided that    **
+ ** it is identified as the "RSA Data Security, Inc. MD5 Message-     **
+ ** Digest Algorithm" in all material mentioning or referencing this  **
+ ** software or this function.                                        **
+ **                                                                   **
+ ** License is also granted to make and use derivative works          **
+ ** provided that such works are identified as "derived from the RSA  **
+ ** Data Security, Inc. MD5 Message-Digest Algorithm" in all          **
+ ** material mentioning or referencing the derived work.              **
+ **                                                                   **
+ ** RSA Data Security, Inc. makes no representations concerning       **
+ ** either the merchantability of this software or the suitability    **
+ ** of this software for any particular purpose.  It is provided "as  **
+ ** is" without express or implied warranty of any kind.              **
+ **                                                                   **
+ ** These notices must be retained in any copies of any part of this  **
+ ** documentation and/or software.                                    **
+ ***********************************************************************
+ */
+
+#ifndef __MD5_INCLUDE__
+
+/* typedef a 32-bit type */
+#ifdef _LP64
+typedef unsigned int UINT4;
+typedef int          INT4;
+#else
+typedef unsigned long UINT4;
+typedef long          INT4;
+#endif
+#define _UINT4_T
+
+/* Data structure for MD5 (Message-Digest) computation */
+typedef struct {
+  UINT4 i[2];                   /* number of _bits_ handled mod 2^64 */
+  UINT4 buf[4];                                    /* scratch buffer */
+  unsigned char in[64];                              /* input buffer */
+  unsigned char digest[16];     /* actual digest after MD5Final call */
+} MD5_CTX;
+
+void MD5_Init ();
+void MD5_Update ();
+void MD5_Final ();
+
+#define __MD5_INCLUDE__
+#endif /* __MD5_INCLUDE__ */
diff --git a/trunk/tools/firmware-utils/src/mkbrncmdline.c b/trunk/tools/firmware-utils/src/mkbrncmdline.c
new file mode 100644 (file)
index 0000000..207098b
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * mkbrncmdline.c - partially based on libreCMC's wndr3700.c
+ *
+ * Copyright (C) 2011 Tobias Diedrich <ranma+librecmc@tdiedrich.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License,
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <inttypes.h>
+
+static void usage(const char *) __attribute__ (( __noreturn__ ));
+
+static void usage(const char *mess)
+{
+       fprintf(stderr, "Error: %s\n", mess);
+       fprintf(stderr, "Usage: mkbrncmdline -i input_file -o output_file [-a loadaddress] arg1 [argx ...]\n");
+       fprintf(stderr, "\n");
+       exit(1);
+}
+
+static char *input_file = NULL;
+static char *output_file = NULL;
+static unsigned loadaddr = 0x80002000;
+
+static void parseopts(int *argc, char ***argv)
+{
+       char *endptr;
+       int res;
+
+       while ((res = getopt(*argc, *argv, "a:i:o:")) != -1) {
+               switch (res) {
+               default:
+                       usage("Unknown option");
+                       break;
+               case 'a':
+                       loadaddr = strtoul(optarg, &endptr, 0);
+                       if (endptr == optarg || *endptr != 0)
+                               usage("loadaddress must be a decimal or hexadecimal 32-bit value");
+                       break;
+               case 'i':
+                       input_file = optarg;
+                       break;
+               case 'o':
+                       output_file = optarg;
+                       break;
+               }
+       }
+       *argc -= optind;
+       *argv += optind;
+}
+
+static void emitload(int outfd, int reg, unsigned value)
+{
+       char buf[8] = {
+               0x3c, 0x04 + reg,
+               value >> 24, value >> 16,
+               0x34, 0x84 + reg + (reg << 5),
+               value >> 8, value,
+       };
+       if (write(outfd, buf, sizeof(buf)) != sizeof(buf)) {
+               fprintf(stderr, "write: %s\n", strerror(errno));
+               exit(1);
+       }
+}
+
+int main(int argc, char **argv)
+{
+       int outfd;
+       int i;
+       int fd;
+       size_t len, skip, buf_len;
+       unsigned cmdline_addr;
+       unsigned s_ofs;
+       char *buf;
+
+       parseopts(&argc, &argv);
+
+       if (argc < 1)
+               usage("must specify at least one kernel cmdline argument");
+
+       if (input_file == NULL || output_file == NULL)
+               usage("must specify input and output file");
+
+       if ((outfd = open(output_file, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1)
+       {
+               fprintf(stderr, "Error opening '%s' for writing: %s\n", output_file, strerror(errno));
+               exit(1);
+       }
+
+       // mmap input_file
+       if ((fd = open(input_file, O_RDONLY))  < 0
+       || (len = lseek(fd, 0, SEEK_END)) < 0
+       || (input_file = mmap(0, len, PROT_READ, MAP_SHARED, fd, 0)) == (void *) (-1)
+       || close(fd) < 0)
+       {
+               fprintf(stderr, "Error mapping file '%s': %s\n", input_file, strerror(errno));
+               exit(1);
+       }
+
+       cmdline_addr = loadaddr + len;
+
+       // Kernel args are passed in registers a0,a1,a2 and a3
+       emitload(outfd, 0, 0);              /* a0 = 0 */
+       emitload(outfd, 1, 0);              /* a1 = 0 */
+       emitload(outfd, 2, cmdline_addr);   /* a2 = &cmdline */
+       emitload(outfd, 3, 0);              /* a3 = 0 */
+       skip = lseek(outfd, 0, SEEK_END);
+
+       // write the kernel
+       if (write(outfd, input_file + skip, len - skip) != len -skip) {
+               fprintf(stderr, "write: %s\n", strerror(errno));
+               exit(1);
+       }
+
+       // write cmdline structure
+       buf_len = (argc + 1) * 4;
+       for (i=0; i<argc; i++) {
+               buf_len += strlen(argv[i]) + 1;
+       }
+       buf = malloc(buf_len + 16);
+       if (!buf) {
+               fprintf(stderr, "Could not allocate memory for cmdline buffer\n");
+               exit(1);
+       }
+       memset(buf, 0, buf_len);
+
+       s_ofs = 4 * (argc + 1);
+       for (i=0; i<argc; i++) {
+               unsigned s_ptr = cmdline_addr + s_ofs;
+               buf[i * 4 + 0] = s_ptr >> 24;
+               buf[i * 4 + 1] = s_ptr >> 16;
+               buf[i * 4 + 2] = s_ptr >>  8;
+               buf[i * 4 + 3] = s_ptr >>  0;
+               memcpy(&buf[s_ofs], argv[i], strlen(argv[i]));
+               s_ofs += strlen(argv[i]) + 1;
+       }
+       if (write(outfd, buf, buf_len) != buf_len) {
+               fprintf(stderr, "write: %s\n", strerror(errno));
+               exit(1);
+       }
+
+
+       munmap(input_file, len);
+       close(outfd);
+       free(buf);
+
+       return 0;
+}
diff --git a/trunk/tools/firmware-utils/src/mkbrnimg.c b/trunk/tools/firmware-utils/src/mkbrnimg.c
new file mode 100644 (file)
index 0000000..3c2a91d
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * mkbrnimg.c - partially based on libreCMC's wndr3700.c
+ *
+ * Copyright (C) 2011 Tobias Diedrich <ranma+librecmc@tdiedrich.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License,
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <inttypes.h>
+
+#define BPB 8 /* bits/byte */
+
+static uint32_t crc32[1<<BPB];
+
+static void init_crc32()
+{
+       const uint32_t poly = ntohl(0x2083b8ed);
+       int n;
+
+       for (n = 0; n < 1<<BPB; n++) {
+               uint32_t crc = n;
+               int bit;
+
+               for (bit = 0; bit < BPB; bit++)
+                       crc = (crc & 1) ? (poly ^ (crc >> 1)) : (crc >> 1);
+               crc32[n] = crc;
+       }
+}
+
+static uint32_t crc32buf(unsigned char *buf, size_t len)
+{
+       uint32_t crc = 0xFFFFFFFF;
+
+       for (; len; len--, buf++)
+               crc = crc32[(uint8_t)crc ^ *buf] ^ (crc >> BPB);
+       return ~crc;
+}
+
+static void usage(const char *) __attribute__ (( __noreturn__ ));
+
+static void usage(const char *mess)
+{
+       fprintf(stderr, "Error: %s\n", mess);
+       fprintf(stderr, "Usage: mkbrnimg [-o output_file] [-m magic] [-s signature] kernel_file [additional files]\n");
+       fprintf(stderr, "\n");
+       exit(1);
+}
+
+static char *output_file = "default-brnImage";
+static uint32_t magic = 0x12345678;
+static char *signature = "BRNDTW502";
+
+static void parseopts(int *argc, char ***argv)
+{
+       char *endptr;
+       int res;
+
+       while ((res = getopt(*argc, *argv, "o:m:s:")) != -1) {
+               switch (res) {
+               default:
+                       usage("Unknown option");
+                       break;
+               case 'o':
+                       output_file = optarg;
+                       break;
+               case 'm':
+                       magic = strtoul(optarg, &endptr, 0);
+                       if (endptr == optarg || *endptr != 0)
+                               usage("magic must be a decimal or hexadecimal 32-bit value");
+                       break;
+               case 's':
+                       signature = optarg;
+                       break;
+               }
+       }
+       *argc -= optind;
+       *argv += optind;
+}
+
+static void appendfile(int outfd, char *path, int kernel) {
+       int fd;
+       size_t len, padded_len;
+       char *input_file;
+       uint32_t crc;
+       char padding[0x400];
+       char footer[12];
+
+       memset(padding, 0xff, sizeof(padding));
+
+       // mmap input_file
+       if ((fd = open(path, O_RDONLY))  < 0
+       || (len = lseek(fd, 0, SEEK_END)) < 0
+       || (input_file = mmap(0, len, PROT_READ, MAP_SHARED, fd, 0)) == (void *) (-1)
+       || close(fd) < 0)
+       {
+               fprintf(stderr, "Error mapping file '%s': %s\n", path, strerror(errno));
+               exit(1);
+       }
+
+       // kernel should be lzma compressed image, not uImage
+       if (kernel &&
+           (input_file[0] != (char)0x5d ||
+            input_file[1] != (char)0x00 ||
+            input_file[2] != (char)0x00 ||
+            input_file[3] != (char)0x80)) {
+               fprintf(stderr, "lzma signature not found on kernel image.\n");
+               exit(1);
+       }
+
+       init_crc32();
+       crc = crc32buf(input_file, len);
+       fprintf(stderr, "crc32 for '%s' is %08x.\n", path, crc);
+
+       // write the file
+       write(outfd, input_file, len);
+
+       // write padding
+       padded_len = ((len + sizeof(footer) + sizeof(padding) - 1) & ~(sizeof(padding) - 1)) - sizeof(footer);
+       fprintf(stderr, "len=%08x padded_len=%08x\n", len, padded_len);
+       write(outfd, padding, padded_len - len);
+
+       // write footer
+       footer[0]  = (len   >>  0) & 0xff;
+       footer[1]  = (len   >>  8) & 0xff;
+       footer[2]  = (len   >> 16) & 0xff;
+       footer[3]  = (len   >> 24) & 0xff;
+       footer[4]  = (magic >>  0) & 0xff;
+       footer[5]  = (magic >>  8) & 0xff;
+       footer[6]  = (magic >> 16) & 0xff;
+       footer[7]  = (magic >> 24) & 0xff;
+       footer[8]  = (crc   >>  0) & 0xff;
+       footer[9]  = (crc   >>  8) & 0xff;
+       footer[10] = (crc   >> 16) & 0xff;
+       footer[11] = (crc   >> 24) & 0xff;
+       write(outfd, footer, sizeof(footer));
+
+       munmap(input_file, len);
+}
+
+int main(int argc, char **argv)
+{
+       int outfd;
+       int i;
+
+       parseopts(&argc, &argv);
+
+       if (argc < 1)
+               usage("wrong number of arguments");
+
+       if ((outfd = open(output_file, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1)
+       {
+               fprintf(stderr, "Error opening '%s' for writing: %s\n", output_file, strerror(errno));
+               exit(1);
+       }
+
+       for (i=0; i<argc; i++) {
+               appendfile(outfd, argv[i], i == 0);
+       }
+       write(outfd, signature, strlen(signature)+1);
+       close(outfd);
+
+       return 0;
+}
diff --git a/trunk/tools/firmware-utils/src/mkcameofw.c b/trunk/tools/firmware-utils/src/mkcameofw.c
new file mode 100644 (file)
index 0000000..e0da4ba
--- /dev/null
@@ -0,0 +1,433 @@
+/*
+ * Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>     /* for unlink() */
+#include <libgen.h>
+#include <getopt.h>     /* for getopt() */
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#define MAX_MODEL_LEN          20
+#define MAX_SIGNATURE_LEN      30
+#define MAX_REGION_LEN         4
+#define MAX_VERSION_LEN                12
+
+#define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
+
+struct file_info {
+       char            *file_name;     /* name of the file */
+       uint32_t        file_size;      /* length of the file */
+       uint32_t        write_size;
+};
+
+struct img_header {
+       uint32_t        checksum;
+       uint32_t        image_size;
+       uint32_t        kernel_size;
+       char            model[MAX_MODEL_LEN];
+       char            signature[MAX_SIGNATURE_LEN];
+       char            region[MAX_REGION_LEN];
+       char            version[MAX_VERSION_LEN];
+       unsigned char   header_len;
+       unsigned char   is_tgz;
+       unsigned char   pad[4];
+} __attribute__ ((packed));
+
+/*
+ * Globals
+ */
+static char *ofname;
+static char *progname;
+
+static char *model;
+static char *signature;
+static char *region = "DEF";
+static char *version;
+static struct file_info kernel_info;
+static struct file_info rootfs_info;
+static uint32_t kernel_size;
+static uint32_t image_size;
+static int combined;
+
+/*
+ * Message macros
+ */
+#define ERR(fmt, ...) do { \
+       fflush(0); \
+       fprintf(stderr, "[%s] *** error: " fmt "\n", \
+                       progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERRS(fmt, ...) do { \
+       int save = errno; \
+       fflush(0); \
+       fprintf(stderr, "[%s] *** error: " fmt " (%s)\n", \
+                       progname, ## __VA_ARGS__, strerror(save)); \
+} while (0)
+
+#define DBG(fmt, ...) do { \
+       fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
+} while (0)
+
+static void usage(int status)
+{
+       FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+
+       fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+       fprintf(stream,
+"\n"
+"Options:\n"
+"  -k <file>       read kernel image from the file <file>\n"
+"  -c              use the kernel image as a combined image\n"
+"  -M <model>      set model to <model>\n"
+"  -o <file>       write output to the file <file>\n"
+"  -r <file>       read rootfs image from the file <file>\n"
+"  -S <signature>  set image signature to <signature>\n"
+"  -R <region>     set image region to <region>\n"
+"  -V <version>    set image version to <version>\n"
+"  -I <size>       set image size to <size>\n"
+"  -K <size>       set kernel size to <size>\n"
+"  -h              show this screen\n"
+       );
+
+       exit(status);
+}
+
+int
+str2u32(char *arg, uint32_t *val)
+{
+       char *err = NULL;
+       uint32_t t;
+
+       errno=0;
+       t = strtoul(arg, &err, 0);
+       if (errno || (err==arg) || ((err != NULL) && *err)) {
+               return -1;
+       }
+
+       *val = t;
+       return 0;
+}
+
+static int get_file_stat(struct file_info *fdata)
+{
+       struct stat st;
+       int res;
+
+       if (fdata->file_name == NULL)
+               return 0;
+
+       res = stat(fdata->file_name, &st);
+       if (res){
+               ERRS("stat failed on %s", fdata->file_name);
+               return res;
+       }
+
+       fdata->file_size = st.st_size;
+       fdata->write_size = fdata->file_size;
+       return 0;
+}
+
+static int read_to_buf(struct file_info *fdata, char *buf)
+{
+       FILE *f;
+       int ret = EXIT_FAILURE;
+
+       f = fopen(fdata->file_name, "r");
+       if (f == NULL) {
+               ERRS("could not open \"%s\" for reading", fdata->file_name);
+               goto out;
+       }
+
+       errno = 0;
+       fread(buf, fdata->file_size, 1, f);
+       if (errno != 0) {
+               ERRS("unable to read from file \"%s\"", fdata->file_name);
+               goto out_close;
+       }
+
+       ret = EXIT_SUCCESS;
+
+out_close:
+       fclose(f);
+out:
+       return ret;
+}
+
+static int check_options(void)
+{
+       int ret;
+
+#define CHKSTR(_name, _msg)                            \
+       do {                                            \
+               if (_name == NULL) {                    \
+                       ERR("no %s specified", _msg);   \
+                       return -1;                      \
+               }                                       \
+       } while (0)
+
+#define CHKSTRLEN(_name, _msg)                                 \
+       do {                                                    \
+               int field_len;                                  \
+               CHKSTR(_name, _msg);                            \
+               field_len = FIELD_SIZEOF(struct img_header, _name) - 1; \
+               if (strlen(_name) > field_len) {                \
+                       ERR("%s is too long, max length is %d", \
+                           _msg, field_len);                   \
+                       return -1;                              \
+               }                                               \
+       } while (0)
+
+       CHKSTRLEN(model, "model");
+       CHKSTRLEN(signature, "signature");
+       CHKSTRLEN(region, "region");
+       CHKSTRLEN(version, "version");
+       CHKSTR(ofname, "output file");
+       CHKSTR(kernel_info.file_name, "kernel image");
+
+       ret = get_file_stat(&kernel_info);
+       if (ret)
+               return ret;
+
+       if (combined) {
+               if (!kernel_size) {
+                       ERR("kernel size must be specified for combined images");
+                       return -1;                              \
+               }
+
+               if (!image_size)
+                       image_size = kernel_info.file_size;
+
+               if (kernel_info.file_size > image_size) {
+                       ERR("kernel image is too big");
+                       return -1;
+               }
+
+               kernel_info.write_size = image_size;
+       } else {
+               CHKSTR(rootfs_info.file_name, "rootfs image");
+
+               ret = get_file_stat(&rootfs_info);
+               if (ret)
+                       return ret;
+
+               if (kernel_size) {
+                       /* override kernel size */
+                       kernel_info.write_size = kernel_size;
+               }
+
+               if (image_size) {
+                       if (image_size < kernel_info.write_size)
+                               kernel_info.write_size = image_size;
+
+                       /* override rootfs size */
+                       rootfs_info.write_size = image_size - kernel_info.write_size;
+               }
+
+               if (kernel_info.file_size > kernel_info.write_size) {
+                       ERR("kernel image is too big");
+                       return -1;
+               }
+
+               if (rootfs_info.file_size > rootfs_info.write_size) {
+                       ERR("rootfs image is too big");
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+static int write_fw(char *data, int len)
+{
+       FILE *f;
+       int ret = EXIT_FAILURE;
+
+       f = fopen(ofname, "w");
+       if (f == NULL) {
+               ERRS("could not open \"%s\" for writing", ofname);
+               goto out;
+       }
+
+       errno = 0;
+       fwrite(data, len, 1, f);
+       if (errno) {
+               ERRS("unable to write output file");
+               goto out_flush;
+       }
+
+       DBG("firmware file \"%s\" completed", ofname);
+
+       ret = EXIT_SUCCESS;
+
+out_flush:
+       fflush(f);
+       fclose(f);
+       if (ret != EXIT_SUCCESS) {
+               unlink(ofname);
+       }
+out:
+       return ret;
+}
+
+static uint32_t get_csum(unsigned char *p, uint32_t len)
+{
+       uint32_t csum = 0;
+
+       while (len--)
+               csum += *p++;
+
+       return csum;
+}
+
+static int build_fw(void)
+{
+       int buflen;
+       char *buf;
+       char *p;
+       uint32_t csum;
+       struct img_header *hdr;
+       int ret = EXIT_FAILURE;
+
+       buflen = sizeof(struct img_header) +
+                kernel_info.write_size + rootfs_info.write_size;
+
+       buf = malloc(buflen);
+       if (!buf) {
+               ERR("no memory for buffer\n");
+               goto out;
+       }
+
+       memset(buf, 0, buflen);
+
+       p = buf + sizeof(struct img_header);
+
+       /* read kernel data */
+       ret = read_to_buf(&kernel_info, p);
+       if (ret)
+               goto out_free_buf;
+
+       if (!combined) {
+               p += kernel_info.write_size;
+
+               /* read rootfs data */
+               ret = read_to_buf(&rootfs_info, p);
+               if (ret)
+                       goto out_free_buf;
+       }
+
+       csum = get_csum((unsigned char *)(buf + sizeof(struct img_header)),
+                       buflen - sizeof(struct img_header));
+
+       /* fill firmware header */
+       hdr = (struct img_header *) buf;
+
+       hdr->checksum = htonl(csum);
+       hdr->image_size = htonl(buflen - sizeof(struct img_header));
+       if (!combined)
+               hdr->kernel_size = htonl(kernel_info.write_size);
+       else
+               hdr->kernel_size = htonl(kernel_size);
+       hdr->header_len = sizeof(struct img_header);
+       strncpy(hdr->model, model, sizeof(hdr->model));
+       strncpy(hdr->signature, signature, sizeof(hdr->signature));
+       strncpy(hdr->version, version, sizeof(hdr->version));
+       strncpy(hdr->region, region, sizeof(hdr->region));
+
+       ret = write_fw(buf, buflen);
+       if (ret)
+               goto out_free_buf;
+
+       ret = EXIT_SUCCESS;
+
+out_free_buf:
+       free(buf);
+out:
+       return ret;
+}
+
+int main(int argc, char *argv[])
+{
+       int ret = EXIT_FAILURE;
+
+       progname = basename(argv[0]);
+
+       while (1) {
+               int c;
+
+               c = getopt(argc, argv, "M:S:V:R:k:K:I:r:o:hc");
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'M':
+                       model = optarg;
+                       break;
+               case 'S':
+                       signature = optarg;
+                       break;
+               case 'V':
+                       version = optarg;
+                       break;
+               case 'R':
+                       region = optarg;
+                       break;
+               case 'k':
+                       kernel_info.file_name = optarg;
+                       break;
+               case 'K':
+                       if (str2u32(optarg, &kernel_size)) {
+                               ERR("%s is invalid '%s'",
+                                   "kernel size", optarg);
+                               goto out;
+                       }
+                       break;
+               case 'I':
+                       if (str2u32(optarg, &image_size)) {
+                               ERR("%s is invalid '%s'",
+                                   "image size", optarg);
+                               goto out;
+                       }
+                       break;
+               case 'r':
+                       rootfs_info.file_name = optarg;
+                       break;
+               case 'c':
+                       combined = 1;
+                       break;
+               case 'o':
+                       ofname = optarg;
+                       break;
+               case 'h':
+                       usage(EXIT_SUCCESS);
+                       break;
+               default:
+                       usage(EXIT_FAILURE);
+                       break;
+               }
+       }
+
+       ret = check_options();
+       if (ret)
+               goto out;
+
+       ret = build_fw();
+
+out:
+       return ret;
+}
+
diff --git a/trunk/tools/firmware-utils/src/mkcasfw.c b/trunk/tools/firmware-utils/src/mkcasfw.c
new file mode 100644 (file)
index 0000000..dfcfd08
--- /dev/null
@@ -0,0 +1,1030 @@
+/*
+ *
+ *  Copyright (C) 2007 OpenWrt.org
+ *  Copyright (C) 2007 Gabor Juhos <juhosg at librecmc.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>     /* for unlink() */
+#include <libgen.h>
+#include <getopt.h>     /* for getopt() */
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <endian.h>     /* for __BYTE_ORDER */
+#if defined(__CYGWIN__)
+#  include <byteswap.h>
+#endif
+
+#if (__BYTE_ORDER == __LITTLE_ENDIAN)
+#  define HOST_TO_LE16(x)      (x)
+#  define HOST_TO_LE32(x)      (x)
+#  define LE16_TO_HOST(x)      (x)
+#  define LE32_TO_HOST(x)      (x)
+#else
+#  define HOST_TO_LE16(x)      bswap_16(x)
+#  define HOST_TO_LE32(x)      bswap_32(x)
+#  define LE16_TO_HOST(x)      bswap_16(x)
+#  define LE32_TO_HOST(x)      bswap_32(x)
+#endif
+
+#define MAX_NUM_BLOCKS 2
+#define MAX_ARG_COUNT  32
+#define MAX_ARG_LEN    1024
+#define FILE_BUF_LEN   (16*1024)
+#define DEFAULT_PADC   0xFF
+
+#define DEFAULT_BLOCK_ALIGN    0x10000U
+
+#define CSUM_TYPE_NONE 0
+#define CSUM_TYPE_8    1
+#define CSUM_TYPE_16   2
+#define CSUM_TYPE_32   3
+
+struct csum_state{
+       int     size;
+       uint32_t val;
+       uint32_t tmp;
+       int     odd;
+};
+
+struct image_desc {
+       int             need_file;
+       char            *file_name;     /* name of the file */
+       uint32_t        file_size;      /* length of the file */
+
+       uint32_t        csum;
+       uint32_t        out_size;
+       uint8_t         padc;
+};
+
+struct fwhdr_nfs {
+       uint32_t        type;
+       uint32_t        kernel_offs;
+       uint32_t        kernel_size;
+       uint32_t        fs_offs;
+       uint32_t        fs_size;
+       uint32_t        kernel_csum;
+       uint32_t        fs_csum;
+       uint32_t        id;
+} __attribute__ ((packed));
+
+struct fwhdr_cas {
+       uint32_t        type;
+       uint32_t        kernel_offs;
+       uint32_t        kernel_size;
+       uint32_t        id;
+       uint32_t        kernel_csum;
+       uint32_t        magic1;
+       uint32_t        magic2;
+       uint32_t        magic3;
+} __attribute__ ((packed));
+
+union file_hdr {
+       struct fwhdr_cas cas;
+       struct fwhdr_nfs nfs;
+};
+
+struct board_info {
+       char            *model;
+       char            *name;
+       int             header_type;
+       uint32_t        id;
+       uint32_t        max_kernel_size;
+       uint32_t        max_fs_size;
+};
+
+#define HEADER_TYPE_NFS                0
+#define HEADER_TYPE_CAS                1
+
+#define KERNEL_SIZE_CAS                (61*64*1024)
+#define KERNEL_SIZE_NFS                (52*64*1024)
+#define FS_SIZE_NFS            (9*64*1024)
+
+#define CAS_MAGIC1     0x5241AA55
+#define CAS_MAGIC2     0x524F4741
+#define CAS_MAGIC3     0xD3F22D4E
+
+/* Cellvision/SparkLAN products */
+#define MODEL_CAS_630          0x01000000
+#define MODEL_CAS_630W         0x01000000
+#define MODEL_CAS_670          0x01000000
+#define MODEL_CAS_670W         0x01000000
+#define MODEL_NFS_101U         0x01000000
+#define MODEL_NFS_101WU                0x01000003
+#define MODEL_NFS_202U         0x01000001
+#define MODEL_NFS_202WU                0x01000002
+
+/* Corega products */
+#define MODEL_CG_NSADP         0x01000020 /* NFS-101U */
+#define MODEL_CG_NSADPCR       0x01000021 /* NFS-202U */
+
+/* D-Link products */
+#define MODEL_DCS_950          0x01010102 /* CAS-630 */
+#define MODEL_DCS_950G         0x01020102 /* CAS-630W */
+#define MODEL_DNS_120          0x01000030 /* NFS-101U */
+#define MODEL_DNS_G120         0x01000032 /* NFS-101WU */
+
+/* Digitus products */
+#define MODEL_DN_16021         MODEL_CAS_630
+#define MODEL_DN_16022         MODEL_CAS_630W
+#define MODEL_DN_16030         MODEL_CAS_670
+#define MODEL_DN_16031         MODEL_CAS_670W
+#define MODEL_DN_7013          MODEL_NFS_101U
+
+/* Lobos products */
+#define MODEL_LB_SS01TXU       0x00000000
+
+/* Neu-Fusion products */
+
+/* Ovislink products */
+#define MODEL_MU_5000FS                0x01000040 /* NFS-101U */
+#define MODEL_WL_5420CAM       0x020B0101 /* CAS-630W? */
+#define MODEL_WL_5460CAM       0x020B0001 /* CAS-670W */
+
+/* Repotec products */
+
+/* Sitecom products */
+#define MODEL_LN_350           /* unknown */
+#define MODEL_LN_403           0x01020402
+#define MODEL_WL_401           0x01010402
+
+/* Surecom products */
+#define MODEL_EP_4001_MM       0x01030A02 /* CAS-630 */
+#define MODEL_EP_4002_MM       0x01020A02 /* CAS-630W */
+#define MODEL_EP_4011_MM       0x01010A02 /* CAS-670 */
+#define MODEL_EP_4012_MM       0x01000A02 /* CAS-670W */
+#define MODEL_EP_9812_U                /* unknown */
+
+/* Trendnet products */
+#define MODEL_TN_U100          0x01000081 /* NFS-101U */
+#define MODEL_TN_U200          0x01000082 /* NFS-202U */
+
+/*
+ * Globals
+ */
+char *progname;
+char *ofname;
+int verblevel;
+int keep_invalid_images;
+int invalid_causes_error = 1;
+union file_hdr header;
+
+struct image_desc kernel_image;
+struct image_desc fs_image;
+
+struct board_info *board = NULL;
+
+#define BOARD(m, n, i, ks, fs, h) {            \
+               .model = (m),                   \
+               .name = (n),                    \
+               .id = (i),                      \
+               .max_kernel_size = (ks),        \
+               .max_fs_size = (fs),            \
+               .header_type = (h)              \
+       }
+
+#define BOARD_CAS(m,n,i) \
+               BOARD(m, n, i, KERNEL_SIZE_CAS, 0, HEADER_TYPE_CAS)
+#define BOARD_NFS(m,n,i) \
+               BOARD(m, n, i, KERNEL_SIZE_NFS, FS_SIZE_NFS, HEADER_TYPE_NFS)
+
+static struct board_info boards[] = {
+       /* Cellvision/Sparklan products */
+       BOARD_CAS("CAS-630", "Cellvision CAS-630", MODEL_CAS_630),
+       BOARD_CAS("CAS-630W", "Cellvision CAS-630W", MODEL_CAS_630W),
+       BOARD_CAS("CAS-670", "Cellvision CAS-670", MODEL_CAS_670),
+       BOARD_CAS("CAS-670W", "Cellvision CAS-670W", MODEL_CAS_670W),
+       BOARD_NFS("NFS-101U", "Cellvision NFS-101U", MODEL_NFS_101U),
+       BOARD_NFS("NFS-101WU", "Cellvision NFS-101WU", MODEL_NFS_101WU),
+       BOARD_NFS("NFS-202U", "Cellvision NFS-202U", MODEL_NFS_202U),
+       BOARD_NFS("NFS-202WU", "Cellvision NFS-202WU", MODEL_NFS_202WU),
+
+       /* Corega products */
+       BOARD_NFS("CG-NSADP", "Corega CG-NSADP", MODEL_CG_NSADP),
+       BOARD_NFS("CG-NSADPCR", "Corega CG-NSADPCR", MODEL_CG_NSADPCR),
+
+       /* D-Link products */
+       BOARD_CAS("DCS-950", "D-Link DCS-950", MODEL_DCS_950),
+       BOARD_CAS("DCS-950G", "D-Link DCS-950G", MODEL_DCS_950G),
+       BOARD_NFS("DNS-120", "D-Link DNS-120", MODEL_DNS_120),
+       BOARD_NFS("DNS-G120", "D-Link DNS-G120", MODEL_DNS_G120),
+
+       /* Digitus products */
+       BOARD_NFS("DN-7013", "Digitus DN-7013", MODEL_DN_7013),
+
+       /* Lobos products */
+       BOARD_NFS("LB-SS01TXU", "Lobos LB-SS01TXU", MODEL_LB_SS01TXU),
+
+       /* Ovislink products */
+       BOARD_NFS("MU-5000FS", "Ovislink MU-5000FS", MODEL_MU_5000FS),
+       BOARD_CAS("WL-5420CAM", "Ovislink WL-5420 CAM", MODEL_WL_5420CAM),
+       BOARD_CAS("WL-5460CAM", "Ovislink WL-5460 CAM", MODEL_WL_5460CAM),
+
+       /* Sitecom products */
+       BOARD_CAS("LN-403", "Sitecom LN-403", MODEL_LN_403),
+       BOARD_CAS("WL-401", "Sitecom WL-401", MODEL_WL_401),
+
+       /* Surecom products */
+       BOARD_CAS("EP-4001-MM", "Surecom EP-4001-MM", MODEL_EP_4001_MM),
+       BOARD_CAS("EP-4002-MM", "Surecom EP-4002-MM", MODEL_EP_4002_MM),
+       BOARD_CAS("EP-4011-MM", "Surecom EP-4011-MM", MODEL_EP_4011_MM),
+       BOARD_CAS("EP-4012-MM", "Surecom EP-4012-MM", MODEL_EP_4012_MM),
+
+       /* TrendNET products */
+       BOARD_NFS("TN-U100", "TrendNET TN-U100", MODEL_TN_U100),
+       BOARD_NFS("TN-U200", "TrendNET TN-U200", MODEL_TN_U200),
+
+       {.model = NULL}
+};
+
+/*
+ * Message macros
+ */
+#define ERR(fmt, ...) do { \
+       fflush(0); \
+       fprintf(stderr, "[%s] *** error: " fmt "\n", \
+                       progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERRS(fmt, ...) do { \
+       int save = errno; \
+       fflush(0); \
+       fprintf(stderr, "[%s] *** error: " fmt "\n", \
+                       progname, ## __VA_ARGS__, strerror(save)); \
+} while (0)
+
+#define WARN(fmt, ...) do { \
+       fprintf(stderr, "[%s] *** warning: " fmt "\n", \
+                       progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define DBG(lev, fmt, ...) do { \
+       if (verblevel < lev) \
+               break;\
+       fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERR_FATAL              -1
+#define ERR_INVALID_IMAGE      -2
+
+void
+usage(int status)
+{
+       FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+       struct board_info *board;
+
+       fprintf(stream, "Usage: %s [OPTIONS...] <file>\n", progname);
+       fprintf(stream,
+"\n"
+"Options:\n"
+"  -B <board>      create image for the board specified with <board>.\n"
+"                  valid <board> values:\n"
+       );
+       for (board = boards; board->model != NULL; board++){
+               fprintf(stream,
+"                  %-12s: %s\n",
+                board->model, board->name);
+       };
+       fprintf(stream,
+"  -d              don't throw error on invalid images\n"
+"  -k              keep invalid images\n"
+"  -K <file>       add kernel to the image\n"
+"  -C <file>       add custom filesystem to the image\n"
+"  -h              show this screen\n"
+"Parameters:\n"
+"  <file>          write output to the file <file>\n"
+       );
+
+       exit(status);
+}
+
+static inline uint32_t align(uint32_t base, uint32_t alignment)
+{
+       uint32_t ret;
+
+       if (alignment) {
+               ret = (base + alignment - 1);
+               ret &= ~(alignment-1);
+       } else {
+               ret = base;
+       }
+
+       return ret;
+}
+
+/*
+ * argument parsing
+ */
+int
+str2u32(char *arg, uint32_t *val)
+{
+       char *err = NULL;
+       uint32_t t;
+
+       errno=0;
+       t = strtoul(arg, &err, 0);
+       if (errno || (err==arg) || ((err != NULL) && *err)) {
+               return -1;
+       }
+
+       *val = t;
+       return 0;
+}
+
+
+int
+str2u16(char *arg, uint16_t *val)
+{
+       char *err = NULL;
+       uint32_t t;
+
+       errno=0;
+       t = strtoul(arg, &err, 0);
+       if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x10000)) {
+               return -1;
+       }
+
+       *val = t & 0xFFFF;
+       return 0;
+}
+
+int
+str2u8(char *arg, uint8_t *val)
+{
+       char *err = NULL;
+       uint32_t t;
+
+       errno=0;
+       t = strtoul(arg, &err, 0);
+       if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x100)) {
+               return -1;
+       }
+
+       *val = t & 0xFF;
+       return 0;
+}
+
+int
+parse_arg(char *arg, char *buf, char *argv[])
+{
+       int res = 0;
+       size_t argl;
+       char *tok;
+       char **ap = &buf;
+       int i;
+
+       memset(argv, 0, MAX_ARG_COUNT * sizeof(void *));
+
+       if ((arg == NULL)) {
+               /* no arguments */
+               return 0;
+       }
+
+       argl = strlen(arg);
+       if (argl == 0) {
+               /* no arguments */
+               return 0;
+       }
+
+       if (argl >= MAX_ARG_LEN) {
+               /* argument is too long */
+               argl = MAX_ARG_LEN-1;
+       }
+
+       memcpy(buf, arg, argl);
+       buf[argl] = '\0';
+
+       for (i = 0; i < MAX_ARG_COUNT; i++) {
+               tok = strsep(ap, ":");
+               if (tok == NULL) {
+                       break;
+               }
+#if 0
+               else if (tok[0] == '\0') {
+                       break;
+               }
+#endif
+               argv[i] = tok;
+               res++;
+       }
+
+       return res;
+}
+
+
+int
+required_arg(char c, char *arg)
+{
+       if (arg == NULL || *arg != '-')
+               return 0;
+
+       ERR("option -%c requires an argument\n", c);
+       return ERR_FATAL;
+}
+
+
+int
+is_empty_arg(char *arg)
+{
+       int ret = 1;
+       if (arg != NULL) {
+               if (*arg) ret = 0;
+       };
+       return ret;
+}
+
+
+void
+csum8_update(uint8_t *p, uint32_t len, struct csum_state *css)
+{
+       for ( ; len > 0; len --) {
+               css->val += *p++;
+       }
+}
+
+
+uint16_t
+csum8_get(struct csum_state *css)
+{
+       uint8_t t;
+
+       t = css->val;
+       return ~t + 1;
+}
+
+
+void
+csum16_update(uint8_t *p, uint32_t len, struct csum_state *css)
+{
+       uint16_t t;
+
+       if (css->odd) {
+               t = css->tmp + (p[0]<<8);
+               css->val += LE16_TO_HOST(t);
+               css->odd = 0;
+               len--;
+               p++;
+       }
+
+       for ( ; len > 1; len -= 2, p +=2 ) {
+               t = p[0] + (p[1] << 8);
+               css->val += LE16_TO_HOST(t);
+       }
+
+       if (len == 1) {
+               css->tmp = p[0];
+               css->odd = 1;
+       }
+}
+
+
+uint16_t
+csum16_get(struct csum_state *css)
+{
+       char pad = 0;
+
+       csum16_update(&pad, 1, css);
+       return ~css->val + 1;
+}
+
+void
+csum32_update(uint8_t *p, uint32_t len, struct csum_state *css)
+{
+       uint32_t t;
+
+       for ( ; len > 3; len -= 4, p += 4 ) {
+               t = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24);
+               css->val ^= t;
+       }
+}
+
+uint32_t
+csum32_get(struct csum_state *css)
+{
+       return css->val;
+}
+
+
+void
+csum_init(struct csum_state *css, int size)
+{
+       css->val = 0;
+       css->tmp = 0;
+       css->odd = 0;
+       css->size = size;
+}
+
+void
+csum_update(uint8_t *p, uint32_t len, struct csum_state *css)
+{
+       switch (css->size) {
+       case CSUM_TYPE_8:
+               csum8_update(p,len,css);
+               break;
+       case CSUM_TYPE_16:
+               csum16_update(p,len,css);
+               break;
+       case CSUM_TYPE_32:
+               csum32_update(p,len,css);
+               break;
+       }
+}
+
+
+uint32_t
+csum_get(struct csum_state *css)
+{
+       uint32_t ret;
+
+       switch (css->size) {
+       case CSUM_TYPE_8:
+               ret = csum8_get(css);
+               break;
+       case CSUM_TYPE_16:
+               ret = csum16_get(css);
+               break;
+       case CSUM_TYPE_32:
+               ret = csum32_get(css);
+       }
+
+       return ret;
+}
+
+
+/*
+ * routines to write data to the output file
+ */
+int
+write_out_data(FILE *outfile, uint8_t *data, size_t len,
+               struct csum_state *css)
+{
+       errno = 0;
+
+       fwrite(data, len, 1, outfile);
+       if (errno) {
+               ERRS("unable to write output file");
+               return ERR_FATAL;
+       }
+
+       if (css) {
+               csum_update(data, len, css);
+       }
+
+       return 0;
+}
+
+
+int
+write_out_padding(FILE *outfile, size_t len, uint8_t padc,
+                struct csum_state *css)
+{
+       uint8_t buf[512];
+       size_t buflen = sizeof(buf);
+       int err;
+
+       memset(buf, padc, buflen);
+       while (len > 0) {
+               if (len < buflen)
+                       buflen = len;
+
+               err = write_out_data(outfile, buf, buflen, css);
+               if (err)
+                       return err;
+
+               len -= buflen;
+       }
+
+       return 0;
+}
+
+
+int
+image_stat_file(struct image_desc *desc)
+{
+       struct stat st;
+       int err;
+
+       if (desc->file_name == NULL)
+               return 0;
+
+       err = stat(desc->file_name, &st);
+       if (err){
+               ERRS("stat failed on %s", desc->file_name);
+               return ERR_FATAL;
+       }
+
+       if (st.st_size > desc->out_size) {
+               WARN("file %s is too big, will be truncated to %d bytes\n",
+                       desc->file_name, desc->out_size);
+               desc->file_size = desc->out_size;
+               return ERR_INVALID_IMAGE;
+       }
+
+
+       desc->file_size = st.st_size;
+       desc->out_size = align(desc->file_size,1);
+       return 0;
+}
+
+
+int
+image_writeout_file(FILE *outfile, struct image_desc *desc,
+                       struct csum_state *css)
+{
+       char buf[FILE_BUF_LEN];
+       size_t buflen = sizeof(buf);
+       FILE *f;
+       size_t len;
+       int res;
+
+       if (desc->file_name == NULL)
+               return 0;
+
+       if (desc->file_size == 0)
+               return 0;
+
+       errno = 0;
+       f = fopen(desc->file_name,"r");
+       if (errno) {
+               ERRS("unable to open file: %s", desc->file_name);
+               return ERR_FATAL;
+       }
+
+       len = desc->file_size;
+       while (len > 0) {
+               if (len < buflen)
+                       buflen = len;
+
+               /* read data from source file */
+               errno = 0;
+               fread(buf, buflen, 1, f);
+               if (errno != 0) {
+                       ERRS("unable to read from file: %s", desc->file_name);
+                       res = ERR_FATAL;
+                       break;
+               }
+
+               res = write_out_data(outfile, buf, buflen, css);
+               if (res)
+                       break;
+
+               len -= buflen;
+       }
+
+       fclose(f);
+       return res;
+}
+
+
+int
+image_writeout(FILE *outfile, struct image_desc *desc)
+{
+       int res;
+       struct csum_state css;
+       size_t padlen;
+
+       res = 0;
+
+       if (!desc->file_size)
+               return 0;
+
+       DBG(2, "writing image, file=%s, file_size=%d\n",
+               desc->file_name, desc->file_size);
+
+       csum_init(&css, CSUM_TYPE_32);
+
+       res = image_writeout_file(outfile, desc, &css);
+       if (res)
+               return res;
+
+       /* write padding data if neccesary */
+       padlen = desc->out_size - desc->file_size;
+       DBG(1,"padding desc, length=%d", padlen);
+       res = write_out_padding(outfile, padlen, desc->padc, &css);
+
+       desc->csum = csum_get(&css);
+
+       return res;
+}
+
+
+int
+write_out_header(FILE *outfile)
+{
+       union file_hdr tmp;
+       int res;
+
+       errno = 0;
+       if (fseek(outfile, 0, SEEK_SET) != 0) {
+               ERRS("fseek failed on output file");
+               return ERR_FATAL;
+       }
+
+       switch (board->header_type) {
+       case HEADER_TYPE_CAS:
+               tmp.cas.type = HOST_TO_LE32(header.cas.type);
+               tmp.cas.id = HOST_TO_LE32(header.cas.id);
+               tmp.cas.kernel_offs = HOST_TO_LE32(sizeof(tmp.cas));
+               tmp.cas.kernel_size = HOST_TO_LE32(kernel_image.out_size);
+               tmp.cas.kernel_csum = HOST_TO_LE32(kernel_image.csum);
+               tmp.cas.magic1 = HOST_TO_LE32(CAS_MAGIC1);
+               tmp.cas.magic2 = HOST_TO_LE32(CAS_MAGIC2);
+               tmp.cas.magic3 = HOST_TO_LE32(CAS_MAGIC3);
+               res = write_out_data(outfile, (uint8_t *)&tmp.cas,
+                                       sizeof(tmp.cas), NULL);
+               break;
+       case HEADER_TYPE_NFS:
+               tmp.nfs.type = HOST_TO_LE32(header.nfs.type);
+               tmp.nfs.id = HOST_TO_LE32(header.nfs.id);
+               tmp.nfs.kernel_offs = HOST_TO_LE32(sizeof(tmp.nfs));
+               tmp.nfs.kernel_size = HOST_TO_LE32(kernel_image.out_size);
+               tmp.nfs.kernel_csum = HOST_TO_LE32(kernel_image.csum);
+               tmp.nfs.fs_offs = HOST_TO_LE32(sizeof(tmp.nfs)
+                                       + kernel_image.out_size);
+               tmp.nfs.fs_size = HOST_TO_LE32(fs_image.out_size);
+               tmp.nfs.fs_csum = HOST_TO_LE32(fs_image.csum);
+               res = write_out_data(outfile, (uint8_t *)&tmp.nfs,
+                                       sizeof(tmp.nfs), NULL);
+               break;
+       }
+
+       return res;
+}
+
+int
+write_out_images(FILE *outfile)
+{
+       struct image_desc *desc;
+       int i, res;
+
+       res = image_writeout(outfile, &kernel_image);
+       if (res)
+               return res;
+
+       res = image_writeout(outfile, &fs_image);
+       if (res)
+               return res;
+
+       return 0;
+}
+
+
+struct board_info *
+find_board(char *model)
+{
+       struct board_info *ret;
+       struct board_info *board;
+
+       ret = NULL;
+       for (board = boards; board->model != NULL; board++){
+               if (strcasecmp(model, board->model) == 0) {
+                       ret = board;
+                       break;
+               }
+       };
+
+       return ret;
+}
+
+
+int
+parse_opt_board(char ch, char *arg)
+{
+
+       DBG(1,"parsing board option: -%c %s", ch, arg);
+
+       if (board != NULL) {
+               ERR("only one board option allowed");
+               return ERR_FATAL;
+       }
+
+       if (required_arg(ch, arg))
+               return ERR_FATAL;
+
+       board = find_board(arg);
+       if (board == NULL){
+               ERR("invalid/unknown board specified: %s", arg);
+               return ERR_FATAL;
+       }
+
+       switch (board->header_type) {
+       case HEADER_TYPE_CAS:
+               header.cas.type = HEADER_TYPE_CAS;
+               header.cas.id = board->id;
+               break;
+       case HEADER_TYPE_NFS:
+               header.nfs.type = HEADER_TYPE_NFS;
+               header.nfs.id = board->id;
+               break;
+       default:
+               ERR("internal error, unknown header type\n");
+               return ERR_FATAL;
+       }
+
+       return 0;
+}
+
+
+int
+parse_opt_image(char ch, char *arg)
+{
+       char buf[MAX_ARG_LEN];
+       char *argv[MAX_ARG_COUNT];
+       int argc;
+       char *p;
+       struct image_desc *desc = NULL;
+       int i;
+
+       switch (ch) {
+       case 'K':
+               if (kernel_image.file_name) {
+                       WARN("only one kernel option allowed");
+                       break;
+               }
+               desc = &kernel_image;
+               break;
+       case 'F':
+               if (fs_image.file_name) {
+                       WARN("only one fs option allowed");
+                       break;
+               }
+               desc = &fs_image;
+               break;
+       }
+
+       if (!desc)
+               return ERR_FATAL;
+
+       argc = parse_arg(arg, buf, argv);
+
+       i = 0;
+       p = argv[i++];
+       if (!is_empty_arg(p)) {
+               desc->file_name = strdup(p);
+               if (desc->file_name == NULL) {
+                       ERR("not enough memory");
+                       return ERR_FATAL;
+               }
+       } else {
+               ERR("no file specified for option %c", ch);
+               return ERR_FATAL;
+       }
+
+       return 0;
+}
+
+
+int
+process_images(void)
+{
+       struct image_desc *desc;
+       uint32_t offs = 0;
+       int i;
+       int res;
+
+       kernel_image.out_size = board->max_kernel_size;
+       kernel_image.padc = DEFAULT_PADC;
+       res = image_stat_file(&kernel_image);
+       if (res)
+               return res;
+
+       if (!fs_image.file_name)
+               return 0;
+
+       fs_image.out_size = board->max_fs_size;
+       fs_image.padc = DEFAULT_PADC;
+       res = image_stat_file(&fs_image);
+       if (res)
+               return res;
+
+       return 0;
+}
+
+
+int
+main(int argc, char *argv[])
+{
+       int optinvalid = 0;   /* flag for invalid option */
+       int c;
+       int res = ERR_FATAL;
+
+       FILE *outfile;
+
+       progname=basename(argv[0]);
+
+       opterr = 0;  /* could not print standard getopt error messages */
+       while ( 1 ) {
+               optinvalid = 0;
+
+               c = getopt(argc, argv, "B:C:dhK:r:vw:x:");
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'B':
+                       optinvalid = parse_opt_board(c,optarg);
+                       break;
+               case 'd':
+                       invalid_causes_error = 0;
+                       break;
+               case 'C':
+               case 'K':
+                       optinvalid = parse_opt_image(c,optarg);
+                       break;
+               case 'k':
+                       keep_invalid_images = 1;
+                       break;
+               case 'v':
+                       verblevel++;
+                       break;
+               case 'h':
+                       usage(EXIT_SUCCESS);
+                       break;
+               default:
+                       optinvalid = 1;
+                       break;
+               }
+               if (optinvalid != 0 ){
+                       ERR("invalid option: -%c", optopt);
+                       goto out;
+               }
+       }
+
+       if (board == NULL) {
+               ERR("no board specified");
+               goto out;
+       }
+
+       if (optind == argc) {
+               ERR("no output file specified");
+               goto out;
+       }
+
+       ofname = argv[optind++];
+
+       if (optind < argc) {
+               ERR("invalid option: %s", argv[optind]);
+               goto out;
+       }
+
+       res = process_images();
+       if (res == ERR_FATAL)
+               goto out;
+
+       if (res == ERR_INVALID_IMAGE) {
+               if (invalid_causes_error)
+                       res = ERR_FATAL;
+
+               if (keep_invalid_images == 0) {
+                       WARN("generation of invalid images disabled", ofname);
+                       goto out;
+               }
+
+               WARN("generating invalid image", ofname);
+       }
+
+       outfile = fopen(ofname, "w");
+       if (outfile == NULL) {
+               ERRS("could not open \"%s\" for writing", ofname);
+               res = ERR_FATAL;
+               goto out;
+       }
+
+       if (write_out_header(outfile) != 0) {
+               res = ERR_FATAL;
+               goto out_flush;
+       }
+
+       if (write_out_images(outfile) != 0) {
+               res = ERR_FATAL;
+               goto out_flush;
+       }
+
+       if (write_out_header(outfile) != 0) {
+               res = ERR_FATAL;
+               goto out_flush;
+       }
+
+       DBG(1,"Image file %s completed.", ofname);
+
+out_flush:
+       fflush(outfile);
+       fclose(outfile);
+       if (res == ERR_FATAL) {
+               unlink(ofname);
+       }
+out:
+       if (res == ERR_FATAL)
+               return EXIT_FAILURE;
+
+       return EXIT_SUCCESS;
+}
diff --git a/trunk/tools/firmware-utils/src/mkchkimg.c b/trunk/tools/firmware-utils/src/mkchkimg.c
new file mode 100644 (file)
index 0000000..e152f7d
--- /dev/null
@@ -0,0 +1,327 @@
+/*
+ *     Make CHK Image
+ *
+ *     This utility creates Netgear .chk files.
+ *
+ *     Copyright (C) 2008 Dave C. Reeve <Dave.Reeve@dreeve.org>
+ *
+ *     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.,
+ *     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+
+#define BUF_LEN (2048)
+
+#define MAX_BOARD_ID_LEN (64)
+
+struct chk_header {
+       uint32_t magic;
+       uint32_t header_len;
+       uint8_t  reserved[8];
+       uint32_t kernel_chksum;
+       uint32_t rootfs_chksum;
+       uint32_t kernel_len;
+       uint32_t rootfs_len;
+       uint32_t image_chksum;
+       uint32_t header_chksum;
+       /* char board_id[] - upto MAX_BOARD_ID_LEN */
+};
+
+static void __attribute__ ((format (printf, 2, 3)))
+fatal_error (int maybe_errno, const char * format, ...)
+{
+       va_list ap;
+
+       fprintf (stderr, "mkchkimg: ");
+       va_start (ap, format);
+       vfprintf (stderr, format, ap);
+       va_end (ap);
+
+       if (maybe_errno) {
+               fprintf (stderr, ": %s\n", strerror (maybe_errno));
+       } else {
+               fprintf (stderr, "\n");
+       }
+
+       exit (EXIT_FAILURE);
+}
+
+static void __attribute__ ((format (printf, 1, 2)))
+message (const char * format, ...)
+{
+       va_list ap;
+
+       fprintf (stderr, "mkchkimg: ");
+       va_start (ap, format);
+       vfprintf (stderr, format, ap);
+       va_end (ap);
+       fprintf (stderr, "\n");
+}
+
+struct ngr_checksum {
+       uint32_t c0;
+       uint32_t c1;
+};
+
+static inline void
+netgear_checksum_init (struct ngr_checksum * c)
+{
+       c->c0 = c->c1 = 0;
+}
+
+static inline void
+netgear_checksum_add (struct ngr_checksum * c, unsigned char * buf, size_t len)
+{
+       size_t i;
+
+       for (i=0; i<len; i++) {
+               c->c0 += buf[i] & 0xff;
+               c->c1 += c->c0;
+       }
+}
+
+static inline unsigned long
+netgear_checksum_fini (struct ngr_checksum * c)
+{
+       uint32_t b, checksum;
+
+       b = (c->c0 & 65535) + ((c->c0 >> 16) & 65535);
+       c->c0 = ((b >> 16) + b) & 65535;
+       b = (c->c1 & 65535) + ((c->c1 >> 16) & 65535);
+       c->c1 = ((b >> 16) + b) & 65535;
+       checksum = ((c->c1 << 16) | c->c0);
+       return checksum;
+}
+
+static void
+print_help (void)
+{
+       fprintf (stderr, "Usage: mkchkimg -o output -k kernel [-f filesys] [-b board_id] [-r region]\n");
+}
+
+int
+main (int argc, char * argv[])
+{
+       int opt;
+       char * ptr;
+       size_t len;
+       size_t header_len;
+       struct chk_header * hdr;
+       struct ngr_checksum chk_part, chk_whole;
+       char buf[BUF_LEN];
+       char * output_file, * kern_file, * fs_file;
+       FILE * out_fp, * kern_fp, * fs_fp;
+       char * board_id;
+       unsigned long region;
+
+       /* Default values */
+       board_id = "U12H072T00_NETGEAR";
+       region = 1;     /* 1=WW, 2=NA */
+       output_file = NULL;
+       kern_file = NULL;
+       fs_file = NULL;
+       fs_fp = NULL;
+
+       while ((opt = getopt (argc, argv, ":b:r:k:f:o:h")) != -1) {
+               switch (opt) {
+                   case 'b':
+                       /* Board Identity */
+                       if (strlen (optarg) > MAX_BOARD_ID_LEN) {
+                               fatal_error (0, "Board lenght exceeds %d", 
+                                       MAX_BOARD_ID_LEN);
+                       }
+                       board_id = optarg;
+                       break;
+
+                   case 'r':
+                       /* Region */
+                       errno = 0;
+                       region = strtoul (optarg, &ptr, 0);
+                       if (errno || ptr==optarg || *ptr!='\0') {
+                               fatal_error (0, "Cannot parse region %s", optarg);
+                       }
+                       if (region > 0xff) {
+                               fatal_error (0, "Region cannot exceed 0xff");
+                       }
+                       break;
+
+                   case 'k':
+                       /* Kernel */
+                       kern_file = optarg;
+                       break;
+
+                   case 'f':
+                       /* Filing System */
+                       fs_file = optarg;
+                       break;
+
+                   case 'o':
+                       /* Output file */
+                       output_file = optarg;
+                       break;
+
+                   case 'h':
+                       print_help ();
+                       return EXIT_SUCCESS;
+
+                   case ':':
+                       print_help ();
+                       fatal_error (0, "Option -%c missing argument", optopt);
+                       break;
+
+                   case '?':
+                       print_help ();
+                       fatal_error (0, "Unknown argument -%c", optopt);
+                       break;
+                   
+                   default:
+                       break;
+               }
+       }
+
+       /* Check we have all the options expected */
+       if (!kern_file) {
+               print_help ();
+               fatal_error (0, "Kernel file expected");
+       }
+       if (!output_file) {
+               print_help ();
+               fatal_error (0, "Output file required");
+       }
+       message ("Netgear CHK writer - v0.1");
+
+       /* Open the input file */
+       kern_fp = fopen (kern_file, "r");
+       if (!kern_fp) {
+               fatal_error (errno, "Cannot open %s", kern_file);
+       }
+
+       /* Open the fs file, if specified */
+       if (fs_file) {
+               fs_fp = fopen (fs_file, "r");
+               if (!fs_fp) {
+                       fatal_error (errno, "Cannot open %s", fs_file);
+               }
+       }
+
+       /* Open the output file */
+       out_fp = fopen (output_file, "w+");
+       if (!out_fp) {
+               fatal_error (errno, "Cannot open %s", output_file);
+       }
+
+       /* Write zeros when the chk header will be */
+       buf[0] = '\0';
+       header_len = sizeof (struct chk_header) + strlen (board_id);
+       if (fwrite (buf, 1, header_len, out_fp) != header_len) {
+               fatal_error (errno, "Cannot write header");
+       }
+
+       /* Allocate storage for header, we fill in as we go */
+       hdr = malloc (sizeof (struct chk_header));
+       if (!hdr) {
+               fatal_error (0, "malloc failed");
+       }
+       bzero (hdr, sizeof (struct chk_header));
+
+       /* Fill in known values */
+       hdr->magic = htonl (0x2a23245e);
+       hdr->header_len = htonl(header_len);
+       hdr->reserved[0] = (unsigned char)(region & 0xff);
+       hdr->reserved[1] = 1;           /* Major */
+       hdr->reserved[2] = 1;           /* Minor */
+       hdr->reserved[3] = 99;          /* Build */
+       hdr->reserved[4] = 0;           /* Unknown t1 ? was 1 */
+       hdr->reserved[5] = 0;           /* Unknonw t2 ? was 0 */
+       hdr->reserved[6] = 0;           /* Unknonw t3 ? was 1 */
+       hdr->reserved[7] = 0;           /* Unused ? */
+       message ("       Board Id: %s", board_id);
+       message ("         Region: %s", region == 1 ? "World Wide (WW)" 
+                       : (region == 2 ? "North America (NA)" : "Unknown"));
+
+       /* Copy the trx file, calculating the checksum as we go */
+       netgear_checksum_init (&chk_part);
+       netgear_checksum_init (&chk_whole);
+       while (!feof (kern_fp)) {
+               len = fread (buf, 1, BUF_LEN, kern_fp);
+               if (len < 1) {
+                       break;
+               }
+               if (fwrite (buf, len, 1, out_fp) != 1) {
+                       fatal_error (errno, "Write error");
+               }
+               hdr->kernel_len += len;
+               netgear_checksum_add (&chk_part, (unsigned char *)buf, len);
+               netgear_checksum_add (&chk_whole, (unsigned char *)buf, len);
+       }
+       hdr->kernel_chksum = netgear_checksum_fini (&chk_part);
+       message ("     Kernel Len: %u", hdr->kernel_len);
+       message ("Kernel Checksum: 0x%08x", hdr->kernel_chksum);
+       hdr->kernel_len = htonl (hdr->kernel_len);
+       hdr->kernel_chksum = htonl (hdr->kernel_chksum);
+
+       /* Now copy the root fs, calculating the checksum as we go */
+       if (fs_fp) {
+               netgear_checksum_init (&chk_part);
+               while (!feof (fs_fp)) {
+                       len = fread (buf, 1, BUF_LEN, fs_fp);
+                       if (len < 1) {
+                               break;
+                       }
+                       if (fwrite (buf, len, 1, out_fp) != 1) {
+                               fatal_error (errno, "Write error");
+                       }
+                       hdr->rootfs_len += len;
+                       netgear_checksum_add (&chk_part, (unsigned char *)buf, len);
+                       netgear_checksum_add (&chk_whole, (unsigned char *)buf, len);
+               }
+               hdr->rootfs_chksum = (netgear_checksum_fini (&chk_part));
+               message ("     Rootfs Len: %u", hdr->rootfs_len);
+               message ("Rootfs Checksum: 0x%08x", hdr->rootfs_chksum);
+               hdr->rootfs_len = htonl (hdr->rootfs_len);
+               hdr->rootfs_chksum = htonl (hdr->rootfs_chksum);
+       }
+
+       /* Calcautate the image checksum */
+       hdr->image_chksum = netgear_checksum_fini (&chk_whole);
+       message (" Image Checksum: 0x%08x", hdr->image_chksum);
+       hdr->image_chksum = htonl (hdr->image_chksum);
+
+       /* Calculate the header checksum */
+       netgear_checksum_init (&chk_part);
+       netgear_checksum_add (&chk_part, (unsigned char *)hdr, 
+                               sizeof (struct chk_header));
+       netgear_checksum_add (&chk_part, (unsigned char *)board_id,
+                               strlen (board_id));
+       hdr->header_chksum = htonl (netgear_checksum_fini (&chk_part));
+
+       /* Finally rewind the output and write headers */
+       rewind (out_fp);
+       if (fwrite (hdr, sizeof (struct chk_header), 1, out_fp) != 1) {
+               fatal_error (errno, "Cannot write header");
+       }
+       if (fwrite (board_id, strlen (board_id), 1, out_fp) != 1) {
+               fatal_error (errno, "Cannot write board id");
+       }
+
+       /* Success */
+       return EXIT_SUCCESS;
+}
+
diff --git a/trunk/tools/firmware-utils/src/mkcsysimg.c b/trunk/tools/firmware-utils/src/mkcsysimg.c
new file mode 100644 (file)
index 0000000..c00096f
--- /dev/null
@@ -0,0 +1,1157 @@
+/*
+ *
+ *  Copyright (C) 2007-2009 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  This program was based on the code found in various Linux
+ *  source tarballs released by Edimax for it's devices.
+ *  Original author: David Hsu <davidhsu@realtek.com.tw>
+ *
+ *  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., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA  02110-1301, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>     /* for unlink() */
+#include <libgen.h>
+#include <getopt.h>     /* for getopt() */
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <endian.h>     /* for __BYTE_ORDER */
+#if defined(__CYGWIN__)
+#  include <byteswap.h>
+#endif
+
+#include "csysimg.h"
+
+#if (__BYTE_ORDER == __LITTLE_ENDIAN)
+#  define HOST_TO_LE16(x)      (x)
+#  define HOST_TO_LE32(x)      (x)
+#  define LE16_TO_HOST(x)      (x)
+#  define LE32_TO_HOST(x)      (x)
+#else
+#  define HOST_TO_LE16(x)      bswap_16(x)
+#  define HOST_TO_LE32(x)      bswap_32(x)
+#  define LE16_TO_HOST(x)      bswap_16(x)
+#  define LE32_TO_HOST(x)      bswap_32(x)
+#endif
+
+#define MAX_NUM_BLOCKS 8
+#define MAX_ARG_COUNT  32
+#define MAX_ARG_LEN    1024
+#define FILE_BUF_LEN   (16*1024)
+#define CSYS_PADC      0xFF
+
+#define BLOCK_TYPE_BOOT        0
+#define BLOCK_TYPE_CONF        1
+#define BLOCK_TYPE_WEBP        2
+#define BLOCK_TYPE_CODE        3
+#define BLOCK_TYPE_XTRA        4
+
+#define DEFAULT_BLOCK_ALIGN    0x10000U
+
+#define CSUM_SIZE_NONE 0
+#define CSUM_SIZE_8    1
+#define CSUM_SIZE_16   2
+
+
+struct csum_state{
+       int     size;
+       uint16_t val;
+       uint16_t tmp;
+       int     odd;
+};
+
+
+struct csys_block {
+       int             type;   /* type of the block */
+
+       int             need_file;
+       char            *file_name;     /* name of the file */
+       uint32_t        file_size;      /* length of the file */
+
+       unsigned char   sig[SIG_LEN];
+       uint32_t        addr;
+       int             addr_set;
+       uint32_t        align;
+       int             align_set;
+       uint8_t         padc;
+
+       uint32_t        size;
+       uint32_t        size_hdr;
+       uint32_t        size_csum;
+       uint32_t        size_avail;
+
+       struct csum_state *css;
+};
+
+
+struct board_info {
+       char *model;
+       char *name;
+       uint32_t flash_size;
+
+       char sig_boot[SIG_LEN];
+       char sig_conf[SIG_LEN];
+       char sig_webp[SIG_LEN];
+
+       uint32_t boot_size;
+       uint32_t conf_size;
+       uint32_t webp_size;
+       uint32_t webp_size_max;
+       uint32_t code_size;
+
+       uint32_t addr_code;
+       uint32_t addr_webp;
+};
+
+#define BOARD(m, n, f, sigb, sigw, bs, cs, ws, ac, aw) {\
+       .model = m, .name = n, .flash_size = f<<20, \
+       .sig_boot = sigb, .sig_conf = SIG_CONF, .sig_webp = sigw, \
+       .boot_size = bs, .conf_size = cs, \
+       .webp_size = ws, .webp_size_max = 3*0x10000, \
+       .addr_code = ac, .addr_webp = aw \
+       }
+
+#define BOARD_ADM(m,n,f, sigw) BOARD(m,n,f, ADM_BOOT_SIG, sigw, \
+       ADM_BOOT_SIZE, ADM_CONF_SIZE, ADM_WEBP_SIZE, \
+       ADM_CODE_ADDR, ADM_WEBP_ADDR)
+
+
+/*
+ * Globals
+ */
+char *progname;
+char *ofname = NULL;
+int verblevel = 0;
+int invalid_causes_error = 1;
+int keep_invalid_images = 0;
+
+struct board_info *board = NULL;
+
+struct csys_block *boot_block = NULL;
+struct csys_block *conf_block = NULL;
+struct csys_block *webp_block = NULL;
+struct csys_block *code_block = NULL;
+
+struct csys_block blocks[MAX_NUM_BLOCKS];
+int num_blocks = 0;
+
+static struct board_info boards[] = {
+       /* The original Edimax products */
+       BOARD_ADM("BR-6104K", "Edimax BR-6104K", 2, SIG_BR6104K),
+       BOARD_ADM("BR-6104KP", "Edimax BR-6104KP", 2, SIG_BR6104KP),
+       BOARD_ADM("BR-6104Wg", "Edimax BR-6104Wg", 2, SIG_BR6104Wg),
+       BOARD_ADM("BR-6114WG", "Edimax BR-6114WG", 2, SIG_BR6114WG),
+       BOARD_ADM("BR-6524K", "Edimax BR-6524K", 2, SIG_BR6524K),
+       BOARD_ADM("BR-6524KP", "Edimax BR-6524KP", 2, SIG_BR6524KP),
+       BOARD_ADM("BR-6524N", "Edimax BR-6524N", 2, SIG_BR6524N),
+       BOARD_ADM("BR-6524WG", "Edimax BR-6524WG", 4, SIG_BR6524WG),
+       BOARD_ADM("BR-6524WP", "Edimax BR-6524WP", 4, SIG_BR6524WP),
+       BOARD_ADM("BR-6541K", "Edimax BR-6541K", 2, SIG_BR6541K),
+       BOARD_ADM("BR-6541KP", "Edimax BR-6541K", 2, SIG_BR6541KP),
+       BOARD_ADM("BR-6541WP", "Edimax BR-6541WP", 4, SIG_BR6541WP),
+       BOARD_ADM("EW-7207APg", "Edimax EW-7207APg", 2, SIG_EW7207APg),
+       BOARD_ADM("PS-1205UWg", "Edimax PS-1205UWg", 2, SIG_PS1205UWg),
+       BOARD_ADM("PS-3205U", "Edimax PS-3205U", 2, SIG_PS3205U),
+       BOARD_ADM("PS-3205UWg", "Edimax PS-3205UWg", 2, SIG_PS3205UWg),
+
+       /* Hawking products */
+       BOARD_ADM("H2BR4", "Hawking H2BR4", 2, SIG_H2BR4),
+       BOARD_ADM("H2WR54G", "Hawking H2WR54G", 4, SIG_H2WR54G),
+
+       /* Planet products */
+       BOARD_ADM("XRT-401D", "Planet XRT-401D", 2, SIG_XRT401D),
+       BOARD_ADM("XRT-402D", "Planet XRT-402D", 2, SIG_XRT402D),
+
+       /* Conceptronic products */
+       BOARD_ADM("C54BSR4", "Conceptronic C54BSR4", 2, SIG_C54BSR4),
+
+       /* OSBRiDGE products */
+       BOARD_ADM("5GXi", "OSBDRiDGE 5GXi", 2, SIG_5GXI),
+
+       {.model = NULL}
+};
+
+/*
+ * Message macros
+ */
+#define ERR(fmt, ...) do { \
+       fflush(0); \
+       fprintf(stderr, "[%s] *** error: " fmt "\n", progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERRS(fmt, ...) do { \
+       int save = errno; \
+       fflush(0); \
+       fprintf(stderr, "[%s] *** error: " fmt "\n", progname, ## __VA_ARGS__ \
+               , strerror(save)); \
+} while (0)
+
+#define WARN(fmt, ...) do { \
+       fprintf(stderr, "[%s] *** warning: " fmt "\n", progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define DBG(lev, fmt, ...) do { \
+       if (verblevel < lev) \
+               break;\
+       fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERR_FATAL              -1
+#define ERR_INVALID_IMAGE      -2
+
+void
+usage(int status)
+{
+       FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+       struct board_info *board;
+
+       fprintf(stream, "Usage: %s [OPTIONS...] <file>\n", progname);
+       fprintf(stream,
+"\n"
+"Options:\n"
+"  -B <board>      create image for the board specified with <board>.\n"
+"                  valid <board> values:\n"
+       );
+       for (board = boards; board->model != NULL; board++){
+               fprintf(stream,
+"                  %-12s: %s\n",
+                board->model, board->name);
+       };
+       fprintf(stream,
+"  -d              don't throw error on invalid images\n"
+"  -k              keep invalid images\n"
+"  -b <file>[:<align>[:<padc>]]\n"
+"                  add boot code to the image\n"
+"  -c <file>[:<align>[:<padc>]]\n"
+"                  add configuration settings to the image\n"
+"  -r <file>:[<addr>][:<align>[:<padc>]]\n"
+"                  add runtime code to the image\n"
+"  -w [<file>:[<addr>][:<align>[:<padc>]]]\n"
+"                  add webpages to the image\n"
+"  -x <file>[:<align>[:<padc>]]\n"
+"                  add extra data at the end of the image\n"
+"  -h              show this screen\n"
+"Parameters:\n"
+"  <file>          write output to the file <file>\n"
+       );
+
+       exit(status);
+}
+
+static inline uint32_t align(uint32_t base, uint32_t alignment)
+{
+       uint32_t ret;
+
+       if (alignment) {
+               ret = (base + alignment - 1);
+               ret &= ~(alignment-1);
+       } else {
+               ret = base;
+       }
+
+       return ret;
+}
+
+/*
+ * argument parsing
+ */
+int
+str2u32(char *arg, uint32_t *val)
+{
+       char *err = NULL;
+       uint32_t t;
+
+       errno=0;
+       t = strtoul(arg, &err, 0);
+       if (errno || (err==arg) || ((err != NULL) && *err)) {
+               return -1;
+       }
+
+       *val = t;
+       return 0;
+}
+
+
+int
+str2u16(char *arg, uint16_t *val)
+{
+       char *err = NULL;
+       uint32_t t;
+
+       errno=0;
+       t = strtoul(arg, &err, 0);
+       if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x10000)) {
+               return -1;
+       }
+
+       *val = t & 0xFFFF;
+       return 0;
+}
+
+int
+str2u8(char *arg, uint8_t *val)
+{
+       char *err = NULL;
+       uint32_t t;
+
+       errno=0;
+       t = strtoul(arg, &err, 0);
+       if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x100)) {
+               return -1;
+       }
+
+       *val = t & 0xFF;
+       return 0;
+}
+
+int
+str2sig(char *arg, uint32_t *sig)
+{
+       if (strlen(arg) != 4)
+               return -1;
+
+       *sig = arg[0] | (arg[1] << 8) | (arg[2] << 16) | (arg[3] << 24);
+
+       return 0;
+}
+
+
+int
+parse_arg(char *arg, char *buf, char *argv[])
+{
+       int res = 0;
+       size_t argl;
+       char *tok;
+       char **ap = &buf;
+       int i;
+
+       memset(argv, 0, MAX_ARG_COUNT * sizeof(void *));
+
+       if ((arg == NULL)) {
+               /* no arguments */
+               return 0;
+       }
+
+       argl = strlen(arg);
+       if (argl == 0) {
+               /* no arguments */
+               return 0;
+       }
+
+       if (argl >= MAX_ARG_LEN) {
+               /* argument is too long */
+               argl = MAX_ARG_LEN-1;
+       }
+
+       memcpy(buf, arg, argl);
+       buf[argl] = '\0';
+
+       for (i = 0; i < MAX_ARG_COUNT; i++) {
+               tok = strsep(ap, ":");
+               if (tok == NULL) {
+                       break;
+               }
+#if 0
+               else if (tok[0] == '\0') {
+                       break;
+               }
+#endif
+               argv[i] = tok;
+               res++;
+       }
+
+       return res;
+}
+
+
+int
+required_arg(char c, char *arg)
+{
+       if (arg == NULL || *arg != '-')
+               return 0;
+
+       ERR("option -%c requires an argument\n", c);
+       return ERR_FATAL;
+}
+
+
+int
+is_empty_arg(char *arg)
+{
+       int ret = 1;
+       if (arg != NULL) {
+               if (*arg) ret = 0;
+       };
+       return ret;
+}
+
+
+void
+csum8_update(uint8_t *p, uint32_t len, struct csum_state *css)
+{
+       for ( ; len > 0; len --) {
+               css->val += *p++;
+       }
+}
+
+
+uint16_t
+csum8_get(struct csum_state *css)
+{
+       uint8_t t;
+
+       t = css->val;
+       return ~t + 1;
+}
+
+
+void
+csum16_update(uint8_t *p, uint32_t len, struct csum_state *css)
+{
+       uint16_t t;
+
+       if (css->odd) {
+               t = css->tmp + (p[0]<<8);
+               css->val += LE16_TO_HOST(t);
+               css->odd = 0;
+               len--;
+               p++;
+       }
+
+       for ( ; len > 1; len -= 2, p +=2 ) {
+               t = p[0] + (p[1] << 8);
+               css->val += LE16_TO_HOST(t);
+       }
+
+       if (len == 1) {
+               css->tmp = p[0];
+               css->odd = 1;
+       }
+}
+
+
+uint16_t
+csum16_get(struct csum_state *css)
+{
+       char pad = 0;
+
+       csum16_update(&pad, 1, css);
+       return ~css->val + 1;
+}
+
+
+void
+csum_init(struct csum_state *css, int size)
+{
+       css->val = 0;
+       css->tmp = 0;
+       css->odd = 0;
+       css->size = size;
+}
+
+
+void
+csum_update(uint8_t *p, uint32_t len, struct csum_state *css)
+{
+       switch (css->size) {
+       case CSUM_SIZE_8:
+               csum8_update(p,len,css);
+               break;
+       case CSUM_SIZE_16:
+               csum16_update(p,len,css);
+               break;
+       }
+}
+
+
+uint16_t
+csum_get(struct csum_state *css)
+{
+       uint16_t ret;
+
+       switch (css->size) {
+       case CSUM_SIZE_8:
+               ret = csum8_get(css);
+               break;
+       case CSUM_SIZE_16:
+               ret = csum16_get(css);
+               break;
+       }
+
+       return ret;
+}
+
+
+/*
+ * routines to write data to the output file
+ */
+int
+write_out_data(FILE *outfile, uint8_t *data, size_t len,
+               struct csum_state *css)
+{
+       errno = 0;
+
+       fwrite(data, len, 1, outfile);
+       if (errno) {
+               ERRS("unable to write output file");
+               return ERR_FATAL;
+       }
+
+       if (css) {
+               csum_update(data, len, css);
+       }
+
+       return 0;
+}
+
+
+int
+write_out_padding(FILE *outfile, size_t len, uint8_t padc,
+                struct csum_state *css)
+{
+       uint8_t buf[512];
+       size_t buflen = sizeof(buf);
+       int err;
+
+       memset(buf, padc, buflen);
+       while (len > 0) {
+               if (len < buflen)
+                       buflen = len;
+
+               err = write_out_data(outfile, buf, buflen, css);
+               if (err)
+                       return err;
+
+               len -= buflen;
+       }
+
+       return 0;
+}
+
+
+int
+block_stat_file(struct csys_block *block)
+{
+       struct stat st;
+       int err;
+
+       if (block->file_name == NULL)
+               return 0;
+
+       err = stat(block->file_name, &st);
+       if (err){
+               ERRS("stat failed on %s", block->file_name);
+               return ERR_FATAL;
+       }
+
+       block->file_size = st.st_size;
+       return 0;
+}
+
+
+int
+block_writeout_hdr(FILE *outfile, struct csys_block *block)
+{
+       struct csys_header hdr;
+       int res;
+
+       if (block->size_hdr == 0)
+               return 0;
+
+       /* setup header fields */
+       memcpy(hdr.sig, block->sig, 4);
+       hdr.addr = HOST_TO_LE32(block->addr);
+       hdr.size = HOST_TO_LE32(block->size - block->size_hdr - block->size_csum);
+
+       DBG(1,"writing header for block");
+       res = write_out_data(outfile, (uint8_t *)&hdr, sizeof(hdr),NULL);
+       return res;
+
+}
+
+
+int
+block_writeout_file(FILE *outfile, struct csys_block *block)
+{
+       char buf[FILE_BUF_LEN];
+       size_t buflen = sizeof(buf);
+       FILE *f;
+       size_t len;
+       int res;
+
+       if (block->file_name == NULL)
+               return 0;
+
+       if (block->file_size == 0)
+               return 0;
+
+       errno = 0;
+       f = fopen(block->file_name,"r");
+       if (errno) {
+               ERRS("unable to open file: %s", block->file_name);
+               return ERR_FATAL;
+       }
+
+       len = block->file_size;
+       while (len > 0) {
+               if (len < buflen)
+                       buflen = len;
+
+               /* read data from source file */
+               errno = 0;
+               fread(buf, buflen, 1, f);
+               if (errno != 0) {
+                       ERRS("unable to read from file: %s", block->file_name);
+                       res = ERR_FATAL;
+                       break;
+               }
+
+               res = write_out_data(outfile, buf, buflen, block->css);
+               if (res)
+                       break;
+
+               len -= buflen;
+       }
+
+       fclose(f);
+       return res;
+}
+
+
+int
+block_writeout_data(FILE *outfile, struct csys_block *block)
+{
+       int res;
+       size_t padlen;
+
+       res = block_writeout_file(outfile, block);
+       if (res)
+               return res;
+
+       /* write padding data if neccesary */
+       padlen = block->size_avail - block->file_size;
+       DBG(1,"padding block, length=%d", padlen);
+       res = write_out_padding(outfile, padlen, block->padc, block->css);
+
+       return res;
+}
+
+
+int
+block_writeout_csum(FILE *outfile, struct csys_block *block)
+{
+       uint16_t csum;
+       int res;
+
+       if (block->size_csum == 0)
+               return 0;
+
+       DBG(1,"writing checksum for block");
+       csum = HOST_TO_LE16(csum_get(block->css));
+       res = write_out_data(outfile, (uint8_t *)&csum, block->size_csum, NULL);
+
+       return res;
+}
+
+
+int
+block_writeout(FILE *outfile, struct csys_block *block)
+{
+       int res;
+       struct csum_state css;
+
+       res = 0;
+
+       if (block == NULL)
+               return res;
+
+       block->css = NULL;
+
+       DBG(2, "writing block, file=%s, file_size=%d, space=%d",
+               block->file_name, block->file_size, block->size_avail);
+       res = block_writeout_hdr(outfile, block);
+       if (res)
+               return res;
+
+       if (block->size_csum != 0) {
+               block->css = &css;
+               csum_init(&css, block->size_csum);
+       }
+
+       res = block_writeout_data(outfile, block);
+       if (res)
+               return res;
+
+       res = block_writeout_csum(outfile, block);
+       if (res)
+               return res;
+
+       return res;
+}
+
+
+int
+write_out_blocks(FILE *outfile)
+{
+       struct csys_block *block;
+       int i, res;
+
+       res = block_writeout(outfile, boot_block);
+       if (res)
+               return res;
+
+       res = block_writeout(outfile, conf_block);
+       if (res)
+               return res;
+
+       res = block_writeout(outfile, webp_block);
+       if (res)
+               return res;
+
+       res = block_writeout(outfile, code_block);
+       if (res)
+               return res;
+
+       res = 0;
+       for (i=0; i < num_blocks; i++) {
+               block = &blocks[i];
+
+               if (block->type != BLOCK_TYPE_XTRA)
+                       continue;
+
+               res = block_writeout(outfile, block);
+               if (res)
+                       break;
+       }
+
+       return res;
+}
+
+
+struct board_info *
+find_board(char *model)
+{
+       struct board_info *ret;
+       struct board_info *board;
+
+       ret = NULL;
+       for (board = boards; board->model != NULL; board++){
+               if (strcasecmp(model, board->model) == 0) {
+                       ret = board;
+                       break;
+               }
+       };
+
+       return ret;
+}
+
+
+int
+parse_opt_board(char ch, char *arg)
+{
+
+       DBG(1,"parsing board option: -%c %s", ch, arg);
+
+       if (board != NULL) {
+               ERR("only one board option allowed");
+               return ERR_FATAL;
+       }
+
+       if (required_arg(ch, arg))
+               return ERR_FATAL;
+
+       board = find_board(arg);
+       if (board == NULL){
+               ERR("invalid/unknown board specified: %s", arg);
+               return ERR_FATAL;
+       }
+
+       return 0;
+}
+
+
+int
+parse_opt_block(char ch, char *arg)
+{
+       char buf[MAX_ARG_LEN];
+       char *argv[MAX_ARG_COUNT];
+       int argc;
+       char *p;
+       struct csys_block *block;
+       int i;
+
+       if ( num_blocks > MAX_NUM_BLOCKS ) {
+               ERR("too many blocks specified");
+               return ERR_FATAL;
+       }
+
+       block = &blocks[num_blocks];
+
+       /* setup default field values */
+       block->need_file = 1;
+       block->padc = 0xFF;
+
+       switch (ch) {
+       case 'b':
+               if (boot_block) {
+                       WARN("only one boot block allowed");
+                       break;
+               }
+               block->type = BLOCK_TYPE_BOOT;
+               boot_block = block;
+               break;
+       case 'c':
+               if (conf_block) {
+                       WARN("only one config block allowed");
+                       break;
+               }
+               block->type = BLOCK_TYPE_CONF;
+               conf_block = block;
+               break;
+       case 'w':
+               if (webp_block) {
+                       WARN("only one web block allowed");
+                       break;
+               }
+               block->type = BLOCK_TYPE_WEBP;
+               block->size_hdr = sizeof(struct csys_header);
+               block->size_csum = CSUM_SIZE_8;
+               block->need_file = 0;
+               webp_block = block;
+               break;
+       case 'r':
+               if (code_block) {
+                       WARN("only one runtime block allowed");
+                       break;
+               }
+               block->type = BLOCK_TYPE_CODE;
+               block->size_hdr = sizeof(struct csys_header);
+               block->size_csum = CSUM_SIZE_16;
+               code_block = block;
+               break;
+       case 'x':
+               block->type = BLOCK_TYPE_XTRA;
+               break;
+       default:
+               ERR("unknown block type \"%c\"", ch);
+               return ERR_FATAL;
+       }
+
+       argc = parse_arg(arg, buf, argv);
+
+       i = 0;
+       p = argv[i++];
+       if (!is_empty_arg(p)) {
+               block->file_name = strdup(p);
+               if (block->file_name == NULL) {
+                       ERR("not enough memory");
+                       return ERR_FATAL;
+               }
+       } else if (block->need_file){
+               ERR("no file specified in %s", arg);
+               return ERR_FATAL;
+       }
+
+       if (block->size_hdr) {
+               p = argv[i++];
+               if (!is_empty_arg(p)) {
+                       if (str2u32(p, &block->addr) != 0) {
+                               ERR("invalid start address in %s", arg);
+                               return ERR_FATAL;
+                       }
+                       block->addr_set = 1;
+               }
+       }
+
+       p = argv[i++];
+       if (!is_empty_arg(p)) {
+               if (str2u32(p, &block->align) != 0) {
+                       ERR("invalid alignment value in %s", arg);
+                       return ERR_FATAL;
+               }
+               block->align_set = 1;
+       }
+
+       p = argv[i++];
+       if (!is_empty_arg(p) && (str2u8(p, &block->padc) != 0)) {
+               ERR("invalid paddig character in %s", arg);
+               return ERR_FATAL;
+       }
+
+       num_blocks++;
+
+       return 0;
+}
+
+
+int
+process_blocks(void)
+{
+       struct csys_block *block;
+       uint32_t offs = 0;
+       int i;
+       int res;
+
+       res = 0;
+       /* collecting stats */
+       for (i = 0; i < num_blocks; i++) {
+               block = &blocks[i];
+               res = block_stat_file(block);
+               if (res)
+                       return res;
+       }
+
+       /* bootloader */
+       block = boot_block;
+       if (block) {
+               block->size = board->boot_size;
+               if (block->file_size > board->boot_size) {
+                       WARN("boot block is too big");
+                       res = ERR_INVALID_IMAGE;
+               }
+       }
+       offs += board->boot_size;
+
+       /* configuration data */
+       block = conf_block;
+       if (block) {
+               block->size = board->conf_size;
+               if (block->file_size > board->conf_size) {
+                       WARN("config block is too big");
+                       res = ERR_INVALID_IMAGE;
+               }
+       }
+       offs += board->conf_size;
+
+       /* webpages */
+       block = webp_block;
+       if (block) {
+
+               memcpy(block->sig, board->sig_webp, 4);
+
+               if (block->addr_set == 0)
+                       block->addr = board->addr_webp;
+
+               if (block->align_set == 0)
+                       block->align = DEFAULT_BLOCK_ALIGN;
+
+               block->size = align(offs + block->file_size + block->size_hdr +
+                               block->size_csum, block->align) - offs;
+
+               if (block->size > board->webp_size_max) {
+                       WARN("webpages block is too big");
+                       res = ERR_INVALID_IMAGE;
+               }
+
+               DBG(2,"webpages start at %08x, size=%08x", offs,
+                               block->size);
+
+               offs += block->size;
+               if (offs > board->flash_size) {
+                       WARN("webp block is too big");
+                       res = ERR_INVALID_IMAGE;
+               }
+       }
+
+       /* runtime code */
+       block = code_block;
+       if (block) {
+               memcpy(code_block->sig, SIG_CSYS, 4);
+
+               if (block->addr_set == 0)
+                       block->addr = board->addr_code;
+
+               if (block->align_set == 0)
+                       block->align = DEFAULT_BLOCK_ALIGN;
+
+               block->size = align(offs + block->file_size +
+                               block->size_hdr + block->size_csum,
+                               block->align) - offs;
+
+               DBG(2,"code block start at %08x, size=%08x", offs,
+                               block->size);
+
+               offs += block->size;
+               if (offs > board->flash_size) {
+                       WARN("code block is too big");
+                       res = ERR_INVALID_IMAGE;
+               }
+       }
+
+       for (i = 0; i < num_blocks; i++) {
+               block = &blocks[i];
+
+               if (block->type != BLOCK_TYPE_XTRA)
+                       continue;
+
+               if (block->align_set == 0)
+                       block->align = DEFAULT_BLOCK_ALIGN;
+
+               block->size = align(offs + block->file_size,
+                               block->align) - offs;
+
+               DBG(2,"file %s start at %08x, size=%08x, align=%08x",
+                       block->file_name, offs, block->size, block->align);
+
+               offs += block->size;
+               if (offs > board->flash_size) {
+                       WARN("file %s is too big, size=%d, avail=%d",
+                               block->file_name, block->file_size,
+                               board->flash_size - offs);
+                       res = ERR_INVALID_IMAGE;
+               }
+       }
+
+       for (i = 0; i < num_blocks; i++) {
+               block = &blocks[i];
+
+               block->size_avail = block->size - block->size_hdr -
+                       block->size_csum;
+
+               if (block->size_avail < block->file_size) {
+                       WARN("file %s is too big, size=%d, avail=%d",
+                               block->file_name, block->file_size,
+                               block->size_avail);
+                       res = ERR_INVALID_IMAGE;
+               }
+       }
+
+       return res;
+}
+
+
+int
+main(int argc, char *argv[])
+{
+       int optinvalid = 0;   /* flag for invalid option */
+       int c;
+       int res = ERR_FATAL;
+
+       FILE *outfile;
+
+       progname=basename(argv[0]);
+
+       opterr = 0;  /* could not print standard getopt error messages */
+       while ( 1 ) {
+               optinvalid = 0;
+
+               c = getopt(argc, argv, "b:B:c:dhkr:vw:x:");
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'b':
+               case 'c':
+               case 'r':
+               case 'x':
+                       optinvalid = parse_opt_block(c,optarg);
+                       break;
+               case 'w':
+                       if (optarg != NULL && *optarg == '-') {
+                               /* rollback */
+                               optind--;
+                               optarg = NULL;
+                       }
+                       optinvalid = parse_opt_block(c,optarg);
+                       break;
+               case 'd':
+                       invalid_causes_error = 0;
+                       break;
+               case 'k':
+                       keep_invalid_images = 1;
+                       break;
+               case 'B':
+                       optinvalid = parse_opt_board(c,optarg);
+                       break;
+               case 'v':
+                       verblevel++;
+                       break;
+               case 'h':
+                       usage(EXIT_SUCCESS);
+                       break;
+               default:
+                       optinvalid = 1;
+                       break;
+               }
+               if (optinvalid != 0 ){
+                       ERR("invalid option: -%c", optopt);
+                       goto out;
+               }
+       }
+
+       if (board == NULL) {
+               ERR("no board specified");
+               goto out;
+       }
+
+       if (optind == argc) {
+               ERR("no output file specified");
+               goto out;
+       }
+
+       ofname = argv[optind++];
+
+       if (optind < argc) {
+               ERR("invalid option: %s", argv[optind]);
+               goto out;
+       }
+
+       res = process_blocks();
+       if (res == ERR_FATAL)
+               goto out;
+
+       if (res == ERR_INVALID_IMAGE) {
+               if (invalid_causes_error)
+                       res = ERR_FATAL;
+
+               if (keep_invalid_images == 0) {
+                       WARN("generation of invalid images disabled", ofname);
+                       goto out;
+               }
+
+               WARN("generating invalid image", ofname);
+       }
+
+       outfile = fopen(ofname, "w");
+       if (outfile == NULL) {
+               ERRS("could not open \"%s\" for writing", ofname);
+               res = ERR_FATAL;
+               goto out;
+       }
+
+       if (write_out_blocks(outfile) != 0) {
+               res = ERR_FATAL;
+               goto out_flush;
+       }
+
+       DBG(1,"Image file %s completed.", ofname);
+
+out_flush:
+       fflush(outfile);
+       fclose(outfile);
+       if (res == ERR_FATAL) {
+               unlink(ofname);
+       }
+out:
+       if (res == ERR_FATAL)
+               return EXIT_FAILURE;
+
+       return EXIT_SUCCESS;
+}
diff --git a/trunk/tools/firmware-utils/src/mkdapimg.c b/trunk/tools/firmware-utils/src/mkdapimg.c
new file mode 100644 (file)
index 0000000..ed662d8
--- /dev/null
@@ -0,0 +1,226 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <libgen.h>
+#include <stdarg.h>
+#include <getopt.h>
+#include <string.h>
+#include <errno.h>
+
+#include <netinet/in.h>        // htonl
+
+// Usage: mkdapimg [-p] [-m <model>] -s <sig> -i <input> -o <output>
+//
+// e.g.: mkdapimg -s RT3052-AP-DAP1350-3 -i sysupgarde.bin -o factory.bin
+//
+// If the model string <model> is not given, we will assume that
+// the leading characters upto the first "-" is the model.
+//
+// The "-p" (patch) option is used to patch the exisiting image with the
+// specified model and signature.
+// The "-x" (fix) option will recalculate the payload size and checksum
+// during the patch mode operation.
+
+// The img_hdr_struct was taken from the D-Link SDK:
+// DAP-1350_A1_FW1.11NA_GPL/GPL_Source_Code/Uboot/DAP-1350/httpd/header.h
+
+#define MAX_MODEL_NAME_LEN     20
+#define MAX_SIG_LEN            30
+#define MAX_REGION_LEN         4
+#define MAX_VERSION_LEN                12
+
+struct img_hdr_struct {
+       uint32_t checksum;
+       char model[MAX_MODEL_NAME_LEN];
+       char sig[MAX_SIG_LEN];
+       uint8_t partition;       
+       uint8_t hdr_len;
+       uint8_t rsv1;
+       uint8_t rsv2;    
+       uint32_t flash_byte_cnt;  
+} imghdr ;
+
+char *progname;
+
+void
+perrexit(int code, char *msg)
+{
+       fprintf(stderr, "%s: %s: %s\n", progname, msg, strerror(errno));
+       exit(code);
+}
+
+void
+usage()
+{
+       fprintf(stderr, "usage: %s [-p] [-m model] [-r region] [-v version] -s signature -i input -o output\n", progname);
+       exit(1);
+}
+
+int
+main(int ac, char *av[])
+{
+       char model[MAX_MODEL_NAME_LEN+1];
+       char signature[MAX_SIG_LEN+1];
+       char region[MAX_REGION_LEN+1];
+       char version[MAX_VERSION_LEN+1];
+       int patchmode = 0;
+       int fixmode = 0;
+       int have_regionversion = 0;
+
+       FILE *ifile, *ofile;
+       int c;
+       uint32_t cksum;
+       uint32_t bcnt;
+
+       progname = basename(av[0]);
+       memset(model, 0, sizeof(model));
+       memset(signature, 0, sizeof(signature));
+       memset(region, 0, sizeof(region));
+       memset(version, 0, sizeof(version));
+
+       while ( 1 ) {
+               int c;
+
+               c = getopt(ac, av, "pxm:r:v:s:i:o:");
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'p':
+                       patchmode = 1;
+                       break;
+               case 'x':
+                       fixmode = 1;
+                       break;
+               case 'm':
+                       if (strlen(optarg) > MAX_MODEL_NAME_LEN) {
+                               fprintf(stderr, "%s: model name exceeds %d chars\n",
+                                       progname, MAX_MODEL_NAME_LEN);
+                               exit(1);
+                       }
+                       strcpy(model, optarg);
+                       break;
+               case 'r':
+                       if (strlen(optarg) > MAX_REGION_LEN) {
+                               fprintf(stderr, "%s: region exceeds %d chars\n",
+                                       progname, MAX_REGION_LEN);
+                               exit(1);
+                       }
+                       have_regionversion = 1;
+                       strcpy(region, optarg);
+                       break;
+               case 'v':
+                       if (strlen(optarg) > MAX_VERSION_LEN) {
+                               fprintf(stderr, "%s: version exceeds %d chars\n",
+                                       progname, MAX_VERSION_LEN);
+                               exit(1);
+                       }
+                       have_regionversion = 1;
+                       strcpy(version, optarg);
+                       break;
+               case 's':
+                       if (strlen(optarg) > MAX_SIG_LEN) {
+                               fprintf(stderr, "%s: signature exceeds %d chars\n",
+                                       progname, MAX_SIG_LEN);
+                               exit(1);
+                       }
+                       strcpy(signature, optarg);
+                       break;
+               case 'i':
+                       if ((ifile = fopen(optarg, "r")) == NULL)
+                               perrexit(1, optarg);
+                       break;
+               case 'o':
+                       if ((ofile = fopen(optarg, "w")) == NULL)
+                               perrexit(1, optarg);
+                       break;
+               default:
+                       usage();
+               }
+       }
+
+       if (signature[0] == 0 || ifile == NULL || ofile == NULL) {
+               usage();
+       }
+
+       if (model[0] == 0) {
+               char *p = strchr(signature, '-');
+               if (p == NULL) {
+                       fprintf(stderr, "%s: model name unknown\n", progname);
+                       exit(1);
+               }
+               if (p - signature > MAX_MODEL_NAME_LEN) {
+                       *p = 0;
+                       fprintf(stderr, "%s: auto model name failed, string %s too long\n", progname, signature);
+                       exit(1);
+               }
+               strncpy(model, signature, p - signature);
+       }
+
+       if (patchmode) {
+               if (fread(&imghdr, sizeof(imghdr), 1, ifile) < 0)
+                       perrexit(2, "fread on input");
+       }
+
+       for (bcnt = 0, cksum = 0 ; (c = fgetc(ifile)) != EOF ; bcnt++)
+               cksum += c & 0xff;
+
+       if (fseek(ifile, patchmode ? sizeof(imghdr) : 0, SEEK_SET) < 0)
+               perrexit(2, "fseek on input");
+
+       if (patchmode == 0) {
+               // Fill in the header
+               memset(&imghdr, 0, sizeof(imghdr));
+               imghdr.checksum = htonl(cksum);
+               imghdr.partition = 0 ; // don't care?
+               imghdr.hdr_len = sizeof(imghdr);
+               if (have_regionversion) {
+                       imghdr.hdr_len += MAX_REGION_LEN;
+                       imghdr.hdr_len += MAX_VERSION_LEN;
+               }
+               imghdr.flash_byte_cnt = htonl(bcnt);
+       } else {
+               if (ntohl(imghdr.checksum) != cksum) {
+                       fprintf(stderr, "%s: patch mode, checksum mismatch\n",
+                               progname);
+                       if (fixmode) {
+                               fprintf(stderr, "%s: fixing\n", progname);
+                               imghdr.checksum = htonl(cksum);
+                       } else
+                               exit(3);
+               } else if (ntohl(imghdr.flash_byte_cnt) != bcnt) {
+                       fprintf(stderr, "%s: patch mode, size mismatch\n",
+                               progname);
+                       if (fixmode) {
+                               fprintf(stderr, "%s: fixing\n", progname);
+                               imghdr.flash_byte_cnt = htonl(bcnt);
+                       } else
+                               exit(3);
+               }
+       }
+
+       strncpy(imghdr.model, model, MAX_MODEL_NAME_LEN);
+       strncpy(imghdr.sig, signature, MAX_SIG_LEN);
+
+       if (fwrite(&imghdr, sizeof(imghdr), 1, ofile) < 0)
+               perrexit(2, "fwrite header on output");
+       if (have_regionversion) {
+               if (fwrite(&region, MAX_REGION_LEN, 1, ofile) < 0)
+                       perrexit(2, "fwrite header on output");
+               if (fwrite(&version, MAX_VERSION_LEN, 1, ofile) < 0)
+                       perrexit(2, "fwrite header on output");
+       }
+
+       while ((c = fgetc(ifile)) != EOF) {
+               if (fputc(c, ofile) == EOF)
+                       perrexit(2, "fputc on output");
+       }
+
+       if (ferror(ifile))
+               perrexit(2, "fgetc on input");
+
+
+       fclose(ofile);
+       fclose(ifile);
+}
diff --git a/trunk/tools/firmware-utils/src/mkdcs932.c b/trunk/tools/firmware-utils/src/mkdcs932.c
new file mode 100644 (file)
index 0000000..28c67aa
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License,
+ * version 2 as published by the Free Software Foundation.
+ *
+ * (C) John Crispin <blogic@openwrt.org>
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <errno.h>
+
+int main(int argc, char **argv)
+{
+       uint32_t t = 0, sum = 0x55aa55aa;
+       int fd;
+
+       if ((argc != 2) || ((fd = open(argv[1], O_RDWR)) == -1)) {
+               fprintf(stderr, "Usage: %s input_file\n", *argv);
+               return -EINVAL;
+       }
+
+       lseek(fd, -4, SEEK_END);
+       write(fd, &t, 4);
+       lseek(fd, 0, SEEK_SET);
+
+       while (read(fd, &t, 4) > 0)
+               sum -= t;
+
+       lseek(fd, -4, SEEK_END);
+       write(fd, &sum, 4);
+       close(fd);
+
+       return 0;
+}
diff --git a/trunk/tools/firmware-utils/src/mkdniimg.c b/trunk/tools/firmware-utils/src/mkdniimg.c
new file mode 100644 (file)
index 0000000..7230f09
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ *  Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>     /* for unlink() */
+#include <libgen.h>
+#include <getopt.h>     /* for getopt() */
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#define DNI_HDR_LEN    128
+
+/*
+ * Globals
+ */
+static char *ifname;
+static char *progname;
+static char *ofname;
+static char *version = "1.00.00";
+static char *region = "";
+static char *hd_id;
+
+static char *board_id;
+/*
+ * Message macros
+ */
+#define ERR(fmt, ...) do { \
+       fflush(0); \
+       fprintf(stderr, "[%s] *** error: " fmt "\n", \
+                       progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERRS(fmt, ...) do { \
+       int save = errno; \
+       fflush(0); \
+       fprintf(stderr, "[%s] *** error: " fmt "\n", \
+                       progname, ## __VA_ARGS__, strerror(save)); \
+} while (0)
+
+void usage(int status)
+{
+       FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+       struct board_info *board;
+
+       fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+       fprintf(stream,
+"\n"
+"Options:\n"
+"  -B <board>      create image for the board specified with <board>\n"
+"  -i <file>       read input from the file <file>\n"
+"  -o <file>       write output to the file <file>\n"
+"  -v <version>    set image version to <version>\n"
+"  -r <region>     set image region to <region>\n"
+"  -H <hd_id>      set image hardware id to <hd_id>\n"
+"  -h              show this screen\n"
+       );
+
+       exit(status);
+}
+
+int main(int argc, char *argv[])
+{
+       int res = EXIT_FAILURE;
+       int buflen;
+       int err;
+       struct stat st;
+       char *buf;
+       int pos, rem, i;
+       uint8_t csum;
+
+       FILE *outfile, *infile;
+
+       progname = basename(argv[0]);
+
+       while ( 1 ) {
+               int c;
+
+               c = getopt(argc, argv, "B:i:o:v:r:H:h");
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'B':
+                       board_id = optarg;
+                       break;
+               case 'i':
+                       ifname = optarg;
+                       break;
+               case 'o':
+                       ofname = optarg;
+                       break;
+               case 'v':
+                       version = optarg;
+                       break;
+               case 'r':
+                       region = optarg;
+                       break;
+               case 'H':
+                       hd_id = optarg;
+                       break;
+               case 'h':
+                       usage(EXIT_SUCCESS);
+                       break;
+               default:
+                       usage(EXIT_FAILURE);
+                       break;
+               }
+       }
+
+       if (board_id == NULL) {
+               ERR("no board specified");
+               goto err;
+       }
+
+       if (ifname == NULL) {
+               ERR("no input file specified");
+               goto err;
+       }
+
+       if (ofname == NULL) {
+               ERR("no output file specified");
+               goto err;
+       }
+
+       err = stat(ifname, &st);
+       if (err){
+               ERRS("stat failed on %s", ifname);
+               goto err;
+       }
+
+       buflen = st.st_size + DNI_HDR_LEN + 1;
+       buf = malloc(buflen);
+       if (!buf) {
+               ERR("no memory for buffer\n");
+               goto err;
+       }
+
+       memset(buf, 0, DNI_HDR_LEN);
+       pos = snprintf(buf, DNI_HDR_LEN, "device:%s\nversion:V%s\nregion:%s\n",
+                      board_id, version, region);
+       rem = DNI_HDR_LEN - pos;
+       if (pos >= 0 && rem > 1 && hd_id) {
+               snprintf(buf + pos, rem, "hd_id:%s\n", hd_id);
+       }
+
+       infile = fopen(ifname, "r");
+       if (infile == NULL) {
+               ERRS("could not open \"%s\" for reading", ifname);
+               goto err_free;
+       }
+
+       errno = 0;
+       fread(buf +  DNI_HDR_LEN, st.st_size, 1, infile);
+       if (errno != 0) {
+               ERRS("unable to read from file %s", ifname);
+               goto err_close_in;
+       }
+
+       csum = 0;
+       for (i = 0; i < (st.st_size + DNI_HDR_LEN); i++)
+               csum += buf[i];
+
+       csum = 0xff - csum;
+       buf[st.st_size + DNI_HDR_LEN] = csum;
+
+       outfile = fopen(ofname, "w");
+       if (outfile == NULL) {
+               ERRS("could not open \"%s\" for writing", ofname);
+               goto err_close_in;
+       }
+
+       errno = 0;
+       fwrite(buf, buflen, 1, outfile);
+       if (errno) {
+               ERRS("unable to write to file %s", ofname);
+               goto err_close_out;
+       }
+
+       res = EXIT_SUCCESS;
+
+ out_flush:
+       fflush(outfile);
+
+ err_close_out:
+       fclose(outfile);
+       if (res != EXIT_SUCCESS) {
+               unlink(ofname);
+       }
+
+ err_close_in:
+       fclose(infile);
+
+ err_free:
+       free(buf);
+
+ err:
+       return res;
+}
diff --git a/trunk/tools/firmware-utils/src/mkedimaximg.c b/trunk/tools/firmware-utils/src/mkedimaximg.c
new file mode 100644 (file)
index 0000000..d8a017e
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2011 Vasilis Tsiligiannis <b_tsiligiannis@silverton.gr>
+ *
+ * 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.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libgen.h>
+#include <getopt.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <endian.h>    /* for __BYTE_ORDER */
+
+#if (__BYTE_ORDER == __LITTLE_ENDIAN)
+#  define HOST_TO_LE16(x)      (x)
+#  define HOST_TO_LE32(x)      (x)
+#else
+#  define HOST_TO_LE16(x)      bswap_16(x)
+#  define HOST_TO_LE32(x)      bswap_32(x)
+#endif
+
+struct header
+{
+    unsigned char sign[4];
+    unsigned int start;
+    unsigned int flash;
+    unsigned char model[4];
+    unsigned int size;
+} __attribute__ ((packed));
+
+struct finfo
+{
+    char *name;
+    off_t size;
+};
+
+struct buf
+{
+    char *start;
+    size_t size;
+};
+
+static char *progname;
+
+static void usage(int status)
+{
+    FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+
+    fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+    fprintf(stream,
+           "\n"
+           "Options:\n"
+           "  -s <sig>        set image signature to <sig>\n"
+           "  -m <model>      set model to <model>\n"
+           "  -i <file>       read input from file <file>\n"
+           "  -o <file>       write output to file <file>\n"
+           "  -f <flash>      set flash address to <flash>\n"
+           "  -S <start>      set start address to <start>\n");
+
+    exit(status);
+}
+
+static int strtou32(char *arg, unsigned int *val)
+{
+    char *endptr = NULL;
+
+    errno = 0;
+    *val = strtoul(arg, &endptr, 0);
+    if (errno || (endptr == arg) || (*endptr && (endptr != NULL))) {
+       return EXIT_SUCCESS;
+    }
+
+    return EXIT_FAILURE;
+}
+
+static unsigned short fwcsum (struct buf *buf) {
+    int i;
+    unsigned short ret = 0;
+
+    for (i = 0; i < buf->size / 2; i++)
+       ret -= ((unsigned short *) buf->start)[i];
+    
+    return ret;
+}
+
+static int fwread(struct finfo *finfo, struct buf *buf)
+{
+    FILE *f;
+    
+    f = fopen(finfo->name, "r");
+    if (!f) {
+       fprintf(stderr, "could not open \"%s\" for reading\n", finfo->name);
+       usage(EXIT_FAILURE);
+    }
+
+    buf->size = fread(buf->start, 1, finfo->size, f);
+    if (buf->size != finfo->size) {
+       fprintf(stderr, "unable to read from file \"%s\"\n", finfo->name);
+       usage(EXIT_FAILURE);
+    }
+
+    fclose(f);
+
+    return EXIT_SUCCESS;
+}
+
+static int fwwrite(struct finfo *finfo, struct buf *buf)
+{
+    FILE *f;
+
+    f = fopen(finfo->name, "w");
+    if (!f) {
+       fprintf(stderr, "could not open \"%s\" for writing\n", finfo->name);
+       usage(EXIT_FAILURE);
+    }
+
+    buf->size = fwrite(buf->start, 1, finfo->size, f);
+    if (buf->size != finfo->size) {
+       fprintf(stderr, "unable to write to file \"%s\"\n", finfo->name);
+       usage(EXIT_FAILURE);
+    }
+
+    fclose(f);
+
+    return EXIT_SUCCESS;
+}      
+  
+int main(int argc, char **argv)
+{
+    struct stat st;
+    struct header header;
+    struct buf ibuf, obuf;
+    struct finfo ifinfo, ofinfo;
+    unsigned short csum;
+    int c;
+
+    ifinfo.name = ofinfo.name = NULL;
+    header.flash = header.size = header.start = 0;
+    progname = basename(argv[0]);
+
+    while((c = getopt(argc, argv, "i:o:m:s:f:S:h")) != -1) {
+       switch (c) {
+       case 'i':
+           ifinfo.name = optarg;
+           break;
+       case 'o':
+           ofinfo.name = optarg;
+           break;
+       case 'm':
+           if (strlen(optarg) != 4) {
+               fprintf(stderr, "model must be 4 characters long\n");
+               usage(EXIT_FAILURE);
+           }
+           memcpy(header.model, optarg, 4);
+           break;
+       case 's':
+           if (strlen(optarg) != 4) {
+               fprintf(stderr, "signature must be 4 characters long\n");
+               usage(EXIT_FAILURE);
+           }
+           memcpy(header.sign, optarg, 4);
+           break;
+       case 'h':
+           usage(EXIT_SUCCESS);
+           break;
+       case 'f':
+           if (!strtou32(optarg, &header.flash)) {
+               fprintf(stderr, "invalid flash address specified\n");
+               usage(EXIT_FAILURE);
+           }
+           break;
+       case 'S':
+           if (!strtou32(optarg, &header.start)) {
+               fprintf(stderr, "invalid start address specified\n");
+               usage(EXIT_FAILURE);
+           }
+           break;
+       default:
+           usage(EXIT_FAILURE);
+           break;
+       }
+    }
+
+    if (ifinfo.name == NULL) {
+       fprintf(stderr, "no input file specified\n");
+       usage(EXIT_FAILURE);
+    }
+
+    if (ofinfo.name == NULL) {
+       fprintf(stderr, "no output file specified\n");
+       usage(EXIT_FAILURE);
+    }
+
+    if (stat(ifinfo.name, &st)) {
+       fprintf(stderr, "stat failed on %s\n", ifinfo.name);
+       usage(EXIT_FAILURE);
+    }
+
+    if (header.sign == NULL) {
+       fprintf(stderr, "no signature specified\n");
+       usage(EXIT_FAILURE);
+    }
+
+    if (header.model == NULL) {
+       fprintf(stderr, "no model specified\n");
+       usage(EXIT_FAILURE);
+    }
+
+    if (!header.flash) {
+       fprintf(stderr, "no flash address specified\n");
+       usage(EXIT_FAILURE);
+    }
+
+    if (!header.start) {
+       fprintf(stderr, "no start address specified\n");
+       usage(EXIT_FAILURE);
+    }
+
+    ifinfo.size = st.st_size;
+
+    obuf.size = ifinfo.size + sizeof(struct header) + sizeof(unsigned short);
+    if (obuf.size % sizeof(unsigned short))
+       obuf.size++;
+
+    obuf.start = malloc(obuf.size);
+    if (!obuf.start) {
+       fprintf(stderr, "no memory for buffer\n");
+       usage(EXIT_FAILURE);
+    }
+    memset(obuf.start, 0, obuf.size);
+
+    ibuf.size = ifinfo.size;
+    ibuf.start = obuf.start + sizeof(struct header);
+    
+    if (fwread(&ifinfo, &ibuf))
+       usage(EXIT_FAILURE);
+
+    header.flash = HOST_TO_LE32(header.flash);
+    header.size = HOST_TO_LE32(obuf.size - sizeof(struct header));
+    header.start = HOST_TO_LE32(header.start);
+    memcpy (obuf.start, &header, sizeof(struct header));
+
+    csum = HOST_TO_LE16(fwcsum(&ibuf));
+    memcpy(obuf.start + obuf.size - sizeof(unsigned short),
+          &csum, sizeof(unsigned short));
+
+    ofinfo.size = obuf.size;
+
+    if (fwwrite(&ofinfo, &obuf))
+       usage(EXIT_FAILURE);
+
+    return EXIT_SUCCESS;
+}
diff --git a/trunk/tools/firmware-utils/src/mkfwimage.c b/trunk/tools/firmware-utils/src/mkfwimage.c
new file mode 100644 (file)
index 0000000..e3a03c1
--- /dev/null
@@ -0,0 +1,467 @@
+/*
+ * Copyright (C) 2007 Ubiquiti Networks, Inc.
+ * Copyright (C) 2008 Lukas Kuna <ValXdater@seznam.cz>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <zlib.h>
+#include <sys/mman.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include "fw.h"
+
+typedef struct fw_layout_data {
+       char            name[PATH_MAX];
+       u_int32_t       kern_start;
+       u_int32_t       kern_entry;
+       u_int32_t       firmware_max_length;
+} fw_layout_t;
+
+fw_layout_t fw_layout_data[] = {
+       {
+               .name           =       "XS2",
+               .kern_start     =       0xbfc30000,
+               .kern_entry     =       0x80041000,
+               .firmware_max_length=   0x00390000,
+       },
+       {
+               .name           =       "XS5",
+               .kern_start     =       0xbe030000,
+               .kern_entry     =       0x80041000,
+               .firmware_max_length=   0x00390000,
+       },
+       {
+               .name           =       "RS",
+               .kern_start     =       0xbf030000,
+               .kern_entry     =       0x80060000,
+               .firmware_max_length=   0x00B00000,
+       },
+       {
+               .name           =       "RSPRO",
+               .kern_start     =       0xbf030000,
+               .kern_entry     =       0x80060000,
+               .firmware_max_length=   0x00F00000,
+       },
+       {
+               .name           =       "LS-SR71",
+               .kern_start     =       0xbf030000,
+               .kern_entry     =       0x80060000,
+               .firmware_max_length=   0x00640000,
+       },
+       {
+               .name           =       "XS2-8",
+               .kern_start     =       0xa8030000,
+               .kern_entry     =       0x80041000,
+               .firmware_max_length=   0x006C0000,
+       },
+       {
+               .name           =       "XM",
+               .kern_start     =       0x9f050000,
+               .kern_entry     =       0x80002000,
+               .firmware_max_length=   0x006A0000,
+       },
+       {       .name           =       "",
+       },
+};
+
+typedef struct part_data {
+       char    partition_name[64];
+       int     partition_index;
+       u_int32_t       partition_baseaddr;
+       u_int32_t       partition_startaddr;
+       u_int32_t       partition_memaddr;
+       u_int32_t       partition_entryaddr;
+       u_int32_t  partition_length;
+
+       char    filename[PATH_MAX];
+       struct stat stats;
+} part_data_t;
+
+#define MAX_SECTIONS   8
+#define DEFAULT_OUTPUT_FILE    "firmware-image.bin"
+#define DEFAULT_VERSION                "UNKNOWN"
+
+#define OPTIONS "B:hv:m:o:r:k:"
+
+static int debug = 0;
+
+typedef struct image_info {
+       char magic[16];
+       char version[256];
+       char outputfile[PATH_MAX];
+       u_int32_t       part_count;
+       part_data_t parts[MAX_SECTIONS];
+} image_info_t;
+
+static void write_header(void* mem, const char *magic, const char* version)
+{
+       header_t* header = mem;
+       memset(header, 0, sizeof(header_t));
+
+       memcpy(header->magic, magic, MAGIC_LENGTH);
+       strncpy(header->version, version, sizeof(header->version));
+       header->crc = htonl(crc32(0L, (unsigned char *)header,
+                               sizeof(header_t) - 2 * sizeof(u_int32_t)));
+       header->pad = 0L;
+}
+
+
+static void write_signature(void* mem, u_int32_t sig_offset)
+{
+       /* write signature */
+       signature_t* sign = (signature_t*)(mem + sig_offset);
+       memset(sign, 0, sizeof(signature_t));
+
+       memcpy(sign->magic, MAGIC_END, MAGIC_LENGTH);
+       sign->crc = htonl(crc32(0L,(unsigned char *)mem, sig_offset));
+       sign->pad = 0L;
+}
+
+static int write_part(void* mem, part_data_t* d)
+{
+       char* addr;
+       int fd;
+       part_t* p = mem;
+       part_crc_t* crc = mem + sizeof(part_t) + d->stats.st_size;
+
+       fd = open(d->filename, O_RDONLY);
+       if (fd < 0)
+       {
+               ERROR("Failed opening file '%s'\n", d->filename);
+               return -1;
+       }
+
+       if ((addr=(char*)mmap(0, d->stats.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED)
+       {
+               ERROR("Failed mmaping memory for file '%s'\n", d->filename);
+               close(fd);
+               return -2;
+       }
+
+       memcpy(mem + sizeof(part_t), addr, d->stats.st_size);
+       munmap(addr, d->stats.st_size);
+
+       memset(p->name, 0, sizeof(p->name));
+       strncpy(p->magic, MAGIC_PART, MAGIC_LENGTH);
+       strncpy(p->name, d->partition_name, sizeof(p->name));
+       p->index = htonl(d->partition_index);
+       p->data_size = htonl(d->stats.st_size);
+       p->part_size = htonl(d->partition_length);
+       p->baseaddr = htonl(d->partition_baseaddr);
+       p->memaddr = htonl(d->partition_memaddr);
+       p->entryaddr = htonl(d->partition_entryaddr);
+
+       crc->crc = htonl(crc32(0L, mem, d->stats.st_size + sizeof(part_t)));
+       crc->pad = 0L;
+
+       return 0;
+}
+
+static void usage(const char* progname)
+{
+       INFO("Version %s\n"
+             "Usage: %s [options]\n"
+            "\t-v <version string>\t - firmware version information, default: %s\n"
+            "\t-o <output file>\t - firmware output file, default: %s\n"
+            "\t-m <magic>\t - firmware magic, default: %s\n"
+            "\t-k <kernel file>\t\t - kernel file\n"
+            "\t-r <rootfs file>\t\t - rootfs file\n"
+            "\t-B <board name>\t\t - choose firmware layout for specified board (XS2, XS5, RS, XM)\n"
+            "\t-h\t\t\t - this help\n", VERSION,
+            progname, DEFAULT_VERSION, DEFAULT_OUTPUT_FILE, MAGIC_HEADER);
+}
+
+static void print_image_info(const image_info_t* im)
+{
+       int i = 0;
+       INFO("Firmware version: '%s'\n"
+            "Output file: '%s'\n"
+            "Part count: %u\n",
+            im->version, im->outputfile,
+            im->part_count);
+
+       for (i = 0; i < im->part_count; ++i)
+       {
+               const part_data_t* d = &im->parts[i];
+               INFO(" %10s: %8ld bytes (free: %8ld)\n",
+                    d->partition_name,
+                    d->stats.st_size,
+                    d->partition_length - d->stats.st_size);
+       }
+}
+
+
+
+static u_int32_t filelength(const char* file)
+{
+       FILE *p;
+       int ret = -1;
+
+       if ( (p = fopen(file, "rb") ) == NULL) return (-1);
+
+       fseek(p, 0, SEEK_END);
+       ret = ftell(p);
+
+       fclose (p);
+
+       return (ret);
+}
+
+static int create_image_layout(const char* kernelfile, const char* rootfsfile, char* board_name, image_info_t* im)
+{
+       part_data_t* kernel = &im->parts[0];
+       part_data_t* rootfs = &im->parts[1];
+
+       fw_layout_t* p;
+
+       p = &fw_layout_data[0];
+       while ((strlen(p->name) != 0) && (strncmp(p->name, board_name, sizeof(board_name)) != 0))
+               p++;
+       if (p->name == NULL) {
+               printf("BUG! Unable to find default fw layout!\n");
+               exit(-1);
+       }
+
+       printf("board = %s\n", p->name);
+       strcpy(kernel->partition_name, "kernel");
+       kernel->partition_index = 1;
+       kernel->partition_baseaddr = p->kern_start;
+       if ( (kernel->partition_length = filelength(kernelfile)) < 0) return (-1);
+       kernel->partition_memaddr = p->kern_entry;
+       kernel->partition_entryaddr = p->kern_entry;
+       strncpy(kernel->filename, kernelfile, sizeof(kernel->filename));
+
+       if (filelength(rootfsfile) + kernel->partition_length > p->firmware_max_length)
+               return (-2);
+
+       strcpy(rootfs->partition_name, "rootfs");
+       rootfs->partition_index = 2;
+       rootfs->partition_baseaddr = kernel->partition_baseaddr + kernel->partition_length;
+       rootfs->partition_length = p->firmware_max_length - kernel->partition_length;
+       rootfs->partition_memaddr = 0x00000000;
+       rootfs->partition_entryaddr = 0x00000000;
+       strncpy(rootfs->filename, rootfsfile, sizeof(rootfs->filename));
+
+printf("kernel: %d 0x%08x\n", kernel->partition_length, kernel->partition_baseaddr);
+printf("root: %d 0x%08x\n", rootfs->partition_length, rootfs->partition_baseaddr);
+       im->part_count = 2;
+
+       return 0;
+}
+
+/**
+ * Checks the availability and validity of all image components.
+ * Fills in stats member of the part_data structure.
+ */
+static int validate_image_layout(image_info_t* im)
+{
+       int i;
+
+       if (im->part_count == 0 || im->part_count > MAX_SECTIONS)
+       {
+               ERROR("Invalid part count '%d'\n", im->part_count);
+               return -1;
+       }
+
+       for (i = 0; i < im->part_count; ++i)
+       {
+               part_data_t* d = &im->parts[i];
+               int len = strlen(d->partition_name);
+               if (len == 0 || len > 16)
+               {
+                       ERROR("Invalid partition name '%s' of the part %d\n",
+                                       d->partition_name, i);
+                       return -1;
+               }
+               if (stat(d->filename, &d->stats) < 0)
+               {
+                       ERROR("Couldn't stat file '%s' from part '%s'\n",
+                                       d->filename, d->partition_name);
+                       return -2;
+               }
+               if (d->stats.st_size == 0)
+               {
+                       ERROR("File '%s' from part '%s' is empty!\n",
+                                       d->filename, d->partition_name);
+                       return -3;
+               }
+               if (d->stats.st_size > d->partition_length) {
+                       ERROR("File '%s' too big (%d) - max size: 0x%08X (exceeds %lu bytes)\n",
+                                       d->filename, i, d->partition_length,
+                                       d->stats.st_size - d->partition_length);
+                       return -4;
+               }
+       }
+
+       return 0;
+}
+
+static int build_image(image_info_t* im)
+{
+       char* mem;
+       char* ptr;
+       u_int32_t mem_size;
+       FILE* f;
+       int i;
+
+       // build in-memory buffer
+       mem_size = sizeof(header_t) + sizeof(signature_t);
+       for (i = 0; i < im->part_count; ++i)
+       {
+               part_data_t* d = &im->parts[i];
+               mem_size += sizeof(part_t) + d->stats.st_size + sizeof(part_crc_t);
+       }
+
+       mem = (char*)calloc(mem_size, 1);
+       if (mem == NULL)
+       {
+               ERROR("Cannot allocate memory chunk of size '%u'\n", mem_size);
+               return -1;
+       }
+
+       // write header
+       write_header(mem, im->magic, im->version);
+       ptr = mem + sizeof(header_t);
+       // write all parts
+       for (i = 0; i < im->part_count; ++i)
+       {
+               part_data_t* d = &im->parts[i];
+               int rc;
+               if ((rc = write_part(ptr, d)) != 0)
+               {
+                       ERROR("ERROR: failed writing part %u '%s'\n", i, d->partition_name);
+               }
+               ptr += sizeof(part_t) + d->stats.st_size + sizeof(part_crc_t);
+       }
+       // write signature
+       write_signature(mem, mem_size - sizeof(signature_t));
+
+       // write in-memory buffer into file
+       if ((f = fopen(im->outputfile, "w")) == NULL)
+       {
+               ERROR("Can not create output file: '%s'\n", im->outputfile);
+               return -10;
+       }
+
+       if (fwrite(mem, mem_size, 1, f) != 1)
+       {
+               ERROR("Could not write %d bytes into file: '%s'\n",
+                               mem_size, im->outputfile);
+               return -11;
+       }
+
+       free(mem);
+       fclose(f);
+       return 0;
+}
+
+
+int main(int argc, char* argv[])
+{
+       char kernelfile[PATH_MAX];
+       char rootfsfile[PATH_MAX];
+       char board_name[PATH_MAX];
+       int o, rc;
+       image_info_t im;
+
+       memset(&im, 0, sizeof(im));
+       memset(kernelfile, 0, sizeof(kernelfile));
+       memset(rootfsfile, 0, sizeof(rootfsfile));
+       memset(board_name, 0, sizeof(board_name));
+
+       strcpy(im.outputfile, DEFAULT_OUTPUT_FILE);
+       strcpy(im.version, DEFAULT_VERSION);
+       strncpy(im.magic, MAGIC_HEADER, sizeof(im.magic));
+
+       while ((o = getopt(argc, argv, OPTIONS)) != -1)
+       {
+               switch (o) {
+               case 'v':
+                       if (optarg)
+                               strncpy(im.version, optarg, sizeof(im.version));
+                       break;
+               case 'o':
+                       if (optarg)
+                               strncpy(im.outputfile, optarg, sizeof(im.outputfile));
+                       break;
+               case 'm':
+                       if (optarg)
+                               strncpy(im.magic, optarg, sizeof(im.magic));
+                       break;
+               case 'h':
+                       usage(argv[0]);
+                       return -1;
+               case 'k':
+                       if (optarg)
+                               strncpy(kernelfile, optarg, sizeof(kernelfile));
+                       break;
+               case 'r':
+                       if (optarg)
+                               strncpy(rootfsfile, optarg, sizeof(rootfsfile));
+                       break;
+               case 'B':
+                       if (optarg)
+                               strncpy(board_name, optarg, sizeof(board_name));
+                       break;
+               }
+       }
+       if (strlen(board_name) == 0)
+               strcpy(board_name, "XS2"); /* default to XS2 */
+
+       if (strlen(kernelfile) == 0)
+       {
+               ERROR("Kernel file is not specified, cannot continue\n");
+               usage(argv[0]);
+               return -2;
+       }
+
+       if (strlen(rootfsfile) == 0)
+       {
+               ERROR("Root FS file is not specified, cannot continue\n");
+               usage(argv[0]);
+               return -2;
+       }
+
+       if ((rc = create_image_layout(kernelfile, rootfsfile, board_name, &im)) != 0)
+       {
+               ERROR("Failed creating firmware layout description - error code: %d\n", rc);
+               return -3;
+       }
+
+       if ((rc = validate_image_layout(&im)) != 0)
+       {
+               ERROR("Failed validating firmware layout - error code: %d\n", rc);
+               return -4;
+       }
+
+       print_image_info(&im);
+
+       if ((rc = build_image(&im)) != 0)
+       {
+               ERROR("Failed building image file '%s' - error code: %d\n", im.outputfile, rc);
+               return -5;
+       }
+
+       return 0;
+}
diff --git a/trunk/tools/firmware-utils/src/mkfwimage2.c b/trunk/tools/firmware-utils/src/mkfwimage2.c
new file mode 100644 (file)
index 0000000..970d6e2
--- /dev/null
@@ -0,0 +1,447 @@
+/*
+ * Copyright (C) 2007 Ubiquiti Networks, Inc.
+ * Copyright (C) 2008 Lukas Kuna <ValXdater@seznam.cz>
+ * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <zlib.h>
+#include <sys/mman.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include "fw.h"
+
+#undef VERSION
+#define VERSION "1.2-libreCMC.1"
+
+#define MAX_SECTIONS           8
+#define DEFAULT_OUTPUT_FILE    "firmware-image.bin"
+#define DEFAULT_VERSION                "UNKNOWN"
+#define DEFAULT_FLASH_BASE     (0xbfc00000)
+
+#define FIRMWARE_MAX_LENGTH    (0x390000)
+
+typedef struct part_data {
+       char            partition_name[64];
+       int             partition_index;
+       u_int32_t       partition_baseaddr;
+       u_int32_t       partition_offset;
+       u_int32_t       partition_memaddr;
+       u_int32_t       partition_entryaddr;
+       u_int32_t       partition_length;
+
+       char            filename[PATH_MAX];
+       struct stat     stats;
+} part_data_t;
+
+typedef struct image_info {
+       char            version[256];
+       char            outputfile[PATH_MAX];
+       char            magic[MAGIC_LENGTH];
+       u_int32_t       flash_baseaddr;
+       u_int32_t       part_count;
+       part_data_t     parts[MAX_SECTIONS];
+} image_info_t;
+
+static image_info_t im;
+static int debug = 0;
+static int zero_part_baseaddr = 0;
+
+static void write_header(void* mem, const char* version)
+{
+       header_t* header = mem;
+       memset(header, 0, sizeof(header_t));
+
+       memcpy(header->magic, im.magic, MAGIC_LENGTH);
+       strncpy(header->version, version, sizeof(header->version));
+       header->crc = htonl(crc32(0L, (unsigned char *)header,
+                               sizeof(header_t) - 2 * sizeof(u_int32_t)));
+       header->pad = 0L;
+}
+
+static void write_signature(void* mem, u_int32_t sig_offset)
+{
+       /* write signature */
+       signature_t* sign = (signature_t*)(mem + sig_offset);
+       memset(sign, 0, sizeof(signature_t));
+
+       memcpy(sign->magic, MAGIC_END, MAGIC_LENGTH);
+       sign->crc = htonl(crc32(0L,(unsigned char *)mem, sig_offset));
+       sign->pad = 0L;
+}
+
+static int write_part(void* mem, part_data_t* d)
+{
+       char* addr;
+       int fd;
+       part_t* p = mem;
+       part_crc_t* crc = mem + sizeof(part_t) + d->stats.st_size;
+
+       fd = open(d->filename, O_RDONLY);
+       if (fd < 0) {
+               ERROR("Failed opening file '%s'\n", d->filename);
+               return -1;
+       }
+
+       if ((addr=(char*)mmap(0, d->stats.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
+               ERROR("Failed mmaping memory for file '%s'\n", d->filename);
+               close(fd);
+               return -2;
+       }
+
+       memcpy(mem + sizeof(part_t), addr, d->stats.st_size);
+       munmap(addr, d->stats.st_size);
+
+       memset(p->name, 0, sizeof(p->name));
+       strncpy(p->magic, MAGIC_PART, MAGIC_LENGTH);
+       strncpy(p->name, d->partition_name, sizeof(p->name));
+       p->index = htonl(d->partition_index);
+       p->data_size = htonl(d->stats.st_size);
+       p->part_size = htonl(d->partition_length);
+       p->baseaddr = htonl(d->partition_baseaddr);
+       p->memaddr = htonl(d->partition_memaddr);
+       p->entryaddr = htonl(d->partition_entryaddr);
+
+       crc->crc = htonl(crc32(0L, mem, d->stats.st_size + sizeof(part_t)));
+       crc->pad = 0L;
+
+       return 0;
+}
+
+static void usage(const char* progname)
+{
+       INFO("Version %s\n"
+             "Usage: %s [options]\n"
+            "\t-v <version string>\t - firmware version information, default: %s\n"
+            "\t-m <magic>\t\t - firmware magic, default: %s\n"
+            "\t-f <flash base>\t\t - flash base address, default: 0x%08x\n"
+            "\t-o <output file>\t - firmware output file, default: %s\n"
+            "\t-p <name>:<offset>:<len>:<memaddr>:<entry>:<file>\n "
+            "\t\t\t\t - create a partition from <file>\n"
+            "\t-z\t\t\t - set partition offsets to zero\n"
+            "\t-h\t\t\t - this help\n",
+            VERSION, progname, DEFAULT_VERSION, MAGIC_HEADER,
+            DEFAULT_FLASH_BASE, DEFAULT_OUTPUT_FILE);
+}
+
+static void print_image_info(void)
+{
+       int i;
+
+       INFO("Firmware version : '%s'\n"
+            "Output file      : '%s'\n"
+            "Part count       : %u\n",
+            im.version, im.outputfile, im.part_count);
+
+       for (i = 0; i < im.part_count; ++i) {
+               const part_data_t* d = &im.parts[i];
+               INFO("  %10s: %08x %08x %08x %08x %8ld bytes (free: %8ld)\n",
+                    d->partition_name,
+                    d->partition_baseaddr,
+                    d->partition_length,
+                    d->partition_entryaddr,
+                    d->partition_memaddr,
+                    d->stats.st_size,
+                    d->partition_length - d->stats.st_size);
+       }
+}
+
+static int filelength(const char* file)
+{
+       FILE *p;
+       int ret = -1;
+
+       if ( (p = fopen(file, "rb") ) == NULL) return (-1);
+
+       fseek(p, 0, SEEK_END);
+       ret = ftell(p);
+
+       fclose (p);
+
+       return (ret);
+}
+
+int str2u32(char *arg, u_int32_t *val)
+{
+       char *err = NULL;
+       uint32_t t;
+
+       errno = 0;
+       t = strtoul(arg, &err, 0);
+       if (errno || (err == arg) || ((err != NULL) && *err)) {
+               return -1;
+       }
+
+       *val = t;
+       return 0;
+}
+
+static int image_layout_add_partition(const char *part_desc)
+{
+       part_data_t *d;
+       char memaddr[16];
+       char entryaddr[16];
+       char offset[16];
+       char length[16];
+       int t;
+
+       if (im.part_count >= MAX_SECTIONS) {
+               ERROR("Too many partitions specified\n");
+               return (-1);
+       }
+
+       d = &im.parts[im.part_count];
+       t = sscanf(part_desc, "%15[0-9a-zA-Z]:%15[0-9a-fA-Fx]:%15[0-9a-fA-Fx]:%15[0-9a-fA-Fx]:%15[0-9a-fA-Fx]:%256s",
+                       d->partition_name,
+                       offset,
+                       length,
+                       memaddr,
+                       entryaddr,
+                       d->filename);
+
+       if (t != 6) {
+               ERROR("Bad partition parameter %d, '%s'\n", t, part_desc);
+               return (-1);
+       }
+
+       if (strlen(d->partition_name) == 0) {
+               ERROR("No partition name specified in '%s'\n", part_desc);
+               return (-1);
+       }
+
+       if (str2u32(offset, &d->partition_offset)) {
+               ERROR("Bad offset value '%s'\n", offset);
+               return (-1);
+       }
+
+       if (str2u32(length, &d->partition_length)) {
+               ERROR("Bad length value '%s'\n", length);
+               return (-1);
+       }
+
+       if (d->partition_length == 0) {
+               int flen;
+               flen = filelength(d->filename);
+               if (flen < 0) {
+                       ERROR("Unable to determine size of '%s'\n",
+                                       d->filename);
+                       return (-1);
+               }
+               d->partition_length = flen;
+       }
+
+       if (str2u32(memaddr, &d->partition_memaddr)) {
+               ERROR("Bad memaddr vaule '%s'\n", memaddr);
+               return (-1);
+       }
+
+       if (str2u32(entryaddr, &d->partition_entryaddr)) {
+               ERROR("Bad entry address value '%s'\n", entryaddr);
+               return (-1);
+       }
+
+       im.part_count++;
+       d->partition_index = im.part_count;
+
+       return 0;
+}
+
+static int image_layout_verify(void)
+{
+       u_int32_t offset;
+       int i;
+
+       if (im.part_count == 0) {
+               ERROR("No partitions specified\n");
+               return -1;
+       }
+
+       offset = im.parts[0].partition_offset;
+       for (i = 0; i < im.part_count; i++)
+       {
+               part_data_t* d = &im.parts[i];
+
+               if (stat(d->filename, &d->stats) < 0) {
+                       ERROR("Couldn't stat file '%s' from part '%s'\n",
+                                       d->filename, d->partition_name);
+                       return -2;
+               }
+
+               if (d->stats.st_size == 0) {
+                       ERROR("File '%s' from part '%s' is empty!\n",
+                                       d->filename, d->partition_name);
+                       return -3;
+               }
+
+               if (d->stats.st_size > d->partition_length) {
+                       ERROR("File '%s' too big (%d) - max size: 0x%08X (exceeds %lu bytes)\n",
+                               d->filename, i, d->partition_length,
+                               d->stats.st_size - d->partition_length);
+                       return -4;
+               }
+
+               if (d->partition_offset < offset)
+                       d->partition_offset = offset;
+
+               if (zero_part_baseaddr) {
+                       d->partition_baseaddr = 0;
+               } else {
+                       d->partition_baseaddr =
+                               im.flash_baseaddr + d->partition_offset;
+               }
+               offset += d->partition_length;
+       }
+
+       return 0;
+}
+
+static int build_image(void)
+{
+       char* mem;
+       char* ptr;
+       u_int32_t mem_size;
+       FILE* f;
+       int i;
+
+       /* build in-memory buffer */
+       mem_size = sizeof(header_t) + sizeof(signature_t);
+       for (i = 0; i < im.part_count; ++i) {
+               part_data_t* d = &im.parts[i];
+               mem_size += sizeof(part_t) + d->stats.st_size + sizeof(part_crc_t);
+       }
+
+       mem = (char*)calloc(mem_size, 1);
+       if (mem == NULL) {
+               ERROR("Cannot allocate memory chunk of size '%u'\n", mem_size);
+               return -1;
+       }
+
+       /* write header */
+       write_header(mem, im.version);
+       ptr = mem + sizeof(header_t);
+
+       /* write all parts */
+       for (i = 0; i < im.part_count; ++i) {
+               part_data_t* d = &im.parts[i];
+               int rc;
+               if ((rc = write_part(ptr, d)) != 0) {
+                       ERROR("ERROR: failed writing part %u '%s'\n", i, d->partition_name);
+                       return -1;
+               }
+               ptr += sizeof(part_t) + d->stats.st_size + sizeof(part_crc_t);
+       }
+
+
+       /* write signature */
+       write_signature(mem, mem_size - sizeof(signature_t));
+
+       /* write in-memory buffer into file */
+       if ((f = fopen(im.outputfile, "w")) == NULL) {
+               ERROR("Can not create output file: '%s'\n", im.outputfile);
+               return -10;
+       }
+
+       if (fwrite(mem, mem_size, 1, f) != 1) {
+               ERROR("Could not write %d bytes into file: '%s'\n",
+                               mem_size, im.outputfile);
+               return -11;
+       }
+
+       free(mem);
+       fclose(f);
+       return 0;
+}
+
+int main(int argc, char* argv[])
+{
+       int o, rc;
+
+       memset(&im, 0, sizeof(im));
+
+       strcpy(im.outputfile, DEFAULT_OUTPUT_FILE);
+       strcpy(im.version, DEFAULT_VERSION);
+       memcpy(im.magic, MAGIC_HEADER, MAGIC_LENGTH);
+       im.flash_baseaddr = DEFAULT_FLASH_BASE;
+
+       while ((o = getopt(argc, argv, "f:hm:o:p:v:z")) != -1)
+       {
+               switch (o) {
+               case 'f':
+                       if (optarg)
+                               if (str2u32(optarg, &im.flash_baseaddr)) {
+                                       ERROR("Invalid flash start address %s\n", optarg);
+                                       return -1;
+                               }
+                       break;
+               case 'h':
+                       usage(argv[0]);
+                       return -1;
+               case 'm':
+                       if (optarg) {
+                               if (strlen(optarg) != MAGIC_LENGTH) {
+                                       ERROR("Invalid magic %s\n", optarg);
+                                       return -1;
+                               }
+
+                               memcpy(im.magic, optarg, MAGIC_LENGTH);
+                       }
+                       break;
+               case 'o':
+                       if (optarg)
+                               strncpy(im.outputfile, optarg, sizeof(im.outputfile));
+                       break;
+               case 'p':
+                       if (optarg) {
+                               if (image_layout_add_partition(optarg))
+                                       return -1;
+                       }
+                       break;
+               case 'v':
+                       if (optarg)
+                               strncpy(im.version, optarg, sizeof(im.version));
+                       break;
+               case 'z':
+                       zero_part_baseaddr = 1;
+                       break;
+               }
+       }
+
+       rc = image_layout_verify();
+       if (rc) {
+               ERROR("Failed validating firmware layout - error code: %d\n",
+                               rc);
+               return -4;
+       }
+
+       print_image_info();
+
+       rc = build_image();
+       if (rc) {
+               ERROR("Failed building image file '%s' - error code: %d\n",
+                               im.outputfile, rc);
+               return -5;
+       }
+
+       return 0;
+}
diff --git a/trunk/tools/firmware-utils/src/mkheader_gemtek.c b/trunk/tools/firmware-utils/src/mkheader_gemtek.c
new file mode 100644 (file)
index 0000000..9e618ef
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2014  Claudio Leite <leitec@staticky.com>
+ *
+ * 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
+ */
+
+/*
+ * Builds a proper flash image for routers using some Gemtek
+ * OEM boards. These include the Airlink101 AR725W, the
+ * Asante SmartHub 600 (AWRT-600N), and Linksys WRT100/110.
+ *
+ * The resulting image is compatible with the factory firmware
+ * web upgrade and TFTP interface.
+ *
+ * To build:
+ *  gcc -O2 -o mkheader_gemtek mkheader_gemtek.c -lz
+ *
+ * Claudio Leite <leitec@staticky.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <zlib.h>              /* for crc32() */
+
+/*
+ * The header is in little-endian format. In case
+ * we are on a BE host, we need to swap binary
+ * values.
+ */
+#ifdef __APPLE__
+# include <libkern/OSByteOrder.h>
+# define le32 OSSwapHostToLittleInt32
+#else
+# if defined(__linux__)
+#  include <endian.h>
+#  if __BYTE_ORDER == __BIG_ENDIAN
+#   define CPU_BIG_ENDIAN
+#  endif
+# else
+#  include <sys/endian.h>              /* BSD's should have this */
+#  if _BYTE_ORDER == _BIG_ENDIAN
+#   define CPU_BIG_ENDIAN
+#  endif
+# endif
+# ifdef CPU_BIG_ENDIAN
+#  define le32(x) (((x & 0xff000000) >> 24) | \
+                   ((x & 0x00ff0000) >> 8)  | \
+                   ((x & 0x0000ff00) << 8)  | \
+                   ((x & 0x000000ff) << 24))
+# else
+#  define le32(x) (x)
+# endif
+#endif
+
+struct gemtek_header {
+       uint8_t         magic[4];
+       uint8_t         version[4];
+       uint32_t        product_id;
+       uint32_t        imagesz;
+       uint32_t        checksum;
+       uint32_t        fast_checksum;
+       uint8_t         build[4];
+       uint8_t         lang[4];
+};
+
+#define HDRLEN sizeof(struct gemtek_header)
+
+struct machines {
+       char           *desc;
+       char           *id;
+       uint32_t        maxsize;
+       struct gemtek_header header;
+};
+
+struct machines mach_def[] = {
+       {"Airlink101 AR725W", "ar725w", 0x340000,
+               {"GMTK", "1003", le32(0x03000001), 0, 0,
+                 0, "01\0\0", "EN\0\0"}},
+       {"Asante AWRT-600N", "awrt600n", 0x340000,
+               {"A600", "1005", le32(0x03000001), 0, 0,
+                 0, "01\0\0", "EN\0\0"}},
+       {"Linksys WRT100", "wrt100", 0x320000,
+               {"GMTK", "1007", le32(0x03040001), 0, 0,
+                 0, "2\0\0\0", "EN\0\0"}},
+       {"Linksys WRT110", "wrt110", 0x320000,
+               {"GMTK", "1007", le32(0x03040001), 0, 0,
+                 0, "2\0\0\0", "EN\0\0"}},
+       {0}
+};
+
+int
+main(int argc, char *argv[])
+{
+       unsigned long   res, flen;
+       struct gemtek_header my_hdr;
+       FILE           *f, *f_out;
+       int             image_type = -1, index;
+       uint8_t        *buf;
+       uint32_t        crc;
+
+       if (argc < 3) {
+               fprintf(stderr, "mkheader_gemtek <uImage> <webflash image> [machine ID]\n");
+               fprintf(stderr, "  where [machine ID] is one of:\n");
+               for (index = 0; mach_def[index].desc != 0; index++) {
+                       fprintf(stderr, "    %-10s  %s", mach_def[index].id, mach_def[index].desc);
+                       if (index == 0)
+                               fprintf(stderr, " (default)\n");
+                       else
+                               fprintf(stderr, "\n");
+               }
+
+               exit(-1);
+       }
+
+       if (argc == 4) {
+               for(index = 0; mach_def[index].id != 0; index++) {
+                       if(strcmp(mach_def[index].id, argv[3]) == 0) {
+                               image_type = index;
+                               break;
+                       }
+               }
+
+               if(image_type == -1) {
+                       fprintf(stderr, "\nERROR: invalid machine type\n");
+                       exit(-1);
+               }
+       } else
+               image_type = 0;
+
+       printf("Opening %s...\n", argv[1]);
+
+       f = fopen(argv[1], "r");
+       if(!f) {
+               fprintf(stderr, "\nERROR: couldn't open input image\n");
+               exit(-1);
+       }
+
+       fseek(f, 0, SEEK_END);
+       flen = (unsigned long) ftell(f);
+
+       printf("  %lu (0x%lX) bytes long\n", flen, flen);
+
+       if (flen > mach_def[image_type].maxsize) {
+               fprintf(stderr, "\nERROR: image exceeds maximum compatible size\n");
+               goto f_error;
+       }
+
+       buf = malloc(flen + HDRLEN);
+       if (!buf) {
+               fprintf(stderr, "\nERROR: couldn't allocate buffer\n");
+               goto f_error;
+       }
+       rewind(f);
+       res = fread(buf + HDRLEN, 1, flen, f);
+       if (res != flen) {
+               perror("Couldn't read entire file: fread()");
+               goto f_error;
+       }
+       fclose(f);
+
+       printf("\nCreating %s...\n", argv[2]);
+
+       memcpy(&my_hdr, &mach_def[image_type].header, HDRLEN);
+
+       printf("  Using %s magic\n", mach_def[image_type].desc);
+
+       my_hdr.imagesz = le32(flen + HDRLEN);
+       memcpy(my_hdr.lang, "EN", 2);
+
+       memcpy(buf, &my_hdr, HDRLEN);
+
+       crc = crc32(0, buf, flen + HDRLEN);
+       printf("  CRC32: %08X\n", crc);
+
+       my_hdr.checksum = le32(crc);
+       memcpy(buf, &my_hdr, HDRLEN);
+
+       printf("  Writing...\n");
+
+       f_out = fopen(argv[2], "w");
+       if(!f_out) {
+               fprintf(stderr, "\nERROR: couldn't open output image\n");
+               exit(-1);
+       }
+
+       fwrite(buf, 1, flen + HDRLEN, f_out);
+
+       fclose(f_out);
+
+       free(buf);
+       return 0;
+
+f_error:
+       fclose(f);
+       exit(-1);
+}
diff --git a/trunk/tools/firmware-utils/src/mkhilinkfw.c b/trunk/tools/firmware-utils/src/mkhilinkfw.c
new file mode 100644 (file)
index 0000000..99322d4
--- /dev/null
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2013 Jeff Kent <jeff@jkent.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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
+ *
+ * This tool encrypts and decrypts uImage formatted firmware for Hilink
+ * HLK-RM04 wireless modules.  It will also truncate a dump of mtd6 and make
+ * it an image suitable for flashing via the stock firmware upgrade page.
+ *
+ * Build instructions: 
+ *   gcc -lcrypto hlkcrypt.c -o hlkcrypt
+ */
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <openssl/des.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#define DES_KEY "H@L9K*(3"
+#ifndef min
+#define min(a,b) \
+   ({ __typeof__ (a) _a = (a); \
+       __typeof__ (b) _b = (b); \
+     _a < _b ? _a : _b; })
+#endif
+#define IH_MAGIC    0x27051956
+#define IH_NMLEN    32
+typedef struct image_header {
+    uint32_t    ih_magic;   /* Image Header Magic Number    */
+    uint32_t    ih_hcrc;    /* Image Header CRC Checksum    */
+    uint32_t    ih_time;    /* Image Creation Timestamp */
+    uint32_t    ih_size;    /* Image Data Size      */
+    uint32_t    ih_load;    /* Data  Load  Address      */
+    uint32_t    ih_ep;      /* Entry Point Address      */
+    uint32_t    ih_dcrc;    /* Image Data CRC Checksum  */
+    uint8_t     ih_os;      /* Operating System     */
+    uint8_t     ih_arch;    /* CPU architecture     */
+    uint8_t     ih_type;    /* Image Type           */
+    uint8_t     ih_comp;    /* Compression Type     */
+    uint8_t     ih_name[IH_NMLEN];  /* Image Name       */
+} image_header_t;
+static int temp_fd = -1;
+static DES_key_schedule schedule;
+static void show_usage(const char *arg0);
+static void exit_cleanup(void);
+static void copy_file(int src, int dst);
+static void do_encrypt(void *p, off_t len);
+static void do_decrypt(void *p, off_t len);
+int main(int argc, char **argv)
+{
+       int encrypt_opt = 0;
+       int decrypt_opt = 0;
+       int input_opt = 0;
+       int output_opt = 0;
+       char *input_filename = NULL;
+       char *output_filename = NULL;
+       int input_fd;
+       int output_fd;
+       off_t file_len;
+       char *p;
+       char buf[sizeof(image_header_t) + 3];
+       image_header_t *header;
+       while (1) {
+               static struct option long_options[] = {
+                       {"encrypt", no_argument,       0, 'e'},
+                       {"decrypt", no_argument,       0, 'd'},
+                       {"input",   required_argument, 0, 'i'},
+                       {"output",  required_argument, 0, 'o'},
+                       {0,         0,                 0, 0  }
+               };
+               int option_index = 0;
+               int c = getopt_long(argc, argv, "dei:o:",
+                               long_options, &option_index);
+               if (c == -1)
+                       break;
+               switch (c) {
+               case 'd':
+                       decrypt_opt++;
+                       if (decrypt_opt > 1) {
+                               fprintf(stderr, "%s: decrypt may only be specified once\n",
+                                       argv[0]);
+                               show_usage(argv[0]);
+                       }
+                       break;
+               case 'e':
+                       encrypt_opt++;
+                       if (encrypt_opt > 1) {
+                               fprintf(stderr, "%s: encrypt may only be specified once\n",
+                                       argv[0]);
+                               show_usage(argv[0]);
+                       }
+                       break;
+               case 'i':
+                       input_opt++;
+                       if (input_opt > 1) {
+                               fprintf(stderr, "%s: only one input file may be specified\n",
+                                       argv[0]);
+                               show_usage(argv[0]);
+                       }
+                       if (strcmp("-", optarg) != 0) {
+                               input_filename = optarg;
+                       }
+                       break;
+               case 'o':
+                       output_opt++;
+                       if (output_opt > 1) {
+                               fprintf(stderr, "%s: only one output file may be specified\n",
+                                       argv[0]);
+                               show_usage(argv[0]);
+                       }
+                       if (strcmp("-", optarg) != 0) {
+                               output_filename = optarg;
+                       }
+                       break;
+               case '?':
+                       exit(-1);
+               default:
+                       abort();
+               }
+       }
+       if (decrypt_opt && encrypt_opt) {
+               fprintf(stderr, "%s: decrypt and encrypt may not be used together\n",
+                       argv[0]);
+               show_usage(argv[0]);
+       }
+       if (!decrypt_opt && !encrypt_opt) {
+               fprintf(stderr, "%s: neither decrypt or encrypt were specified\n",
+                       argv[0]);
+               show_usage(argv[0]);
+       }
+       temp_fd = fileno(tmpfile());
+       if (temp_fd < 0) {
+               fprintf(stderr, "Can't create temporary file\n");
+               exit(EXIT_FAILURE);
+       }
+       atexit(exit_cleanup);
+       DES_set_key_unchecked((const_DES_cblock *)DES_KEY, &schedule);
+       if (input_filename) {
+               input_fd = open(input_filename, O_RDONLY);
+               if (input_fd < 0) {
+                       fprintf(stderr, "Can't open %s for reading: %s\n", input_filename,
+                               strerror(errno));
+                       exit(EXIT_FAILURE);
+               }
+               copy_file(input_fd, temp_fd);
+               close(input_fd);
+       }
+       else {
+               copy_file(STDIN_FILENO, temp_fd);
+       }
+       file_len = lseek(temp_fd, 0, SEEK_CUR);
+       if (file_len < 64) {
+               fprintf(stderr, "Not enough data\n");
+               exit(EXIT_FAILURE);
+       }
+       p = mmap(0, file_len, PROT_READ|PROT_WRITE, MAP_SHARED, temp_fd, 0);
+       if (p == MAP_FAILED) {
+               fprintf(stderr, "mmap failed: %s\n", strerror(errno));
+               exit(EXIT_FAILURE);
+       }       
+       if (encrypt_opt) {
+               header = (image_header_t *)p;
+               off_t len = min(file_len,
+                               ntohl(header->ih_size) + sizeof(image_header_t));
+               if (ntohl(header->ih_magic) != IH_MAGIC) {
+                       fprintf(stderr, "Header magic incorrect: "
+                               "expected 0x%08X, got 0x%08X\n",
+                               IH_MAGIC, ntohl(header->ih_magic));
+                       munmap(p, file_len);
+                       exit(EXIT_FAILURE);
+               }
+               do_encrypt(p, len);
+               munmap(p, file_len);
+               if (len != file_len) {
+                       if (ftruncate(temp_fd, len) < 0) {
+                               fprintf(stderr, "ftruncate failed: %s\n", strerror(errno));
+                               exit(EXIT_FAILURE);
+                       }
+               }               
+       }
+       if (decrypt_opt) {
+               off_t header_len = min(file_len, sizeof(image_header_t) + 3);
+               memcpy(buf, p, header_len);
+               do_decrypt(buf, header_len);
+               header = (image_header_t *)buf;
+               if (ntohl(header->ih_magic) != IH_MAGIC) {
+                       fprintf(stderr, "Header magic incorrect: "
+                               "expected 0x%08X, got 0x%08X\n",
+                               IH_MAGIC, ntohl(header->ih_magic));
+                       exit(EXIT_FAILURE);
+               }
+               do_decrypt(p, file_len);
+               munmap(p, file_len);
+       }
+       lseek(temp_fd, 0, SEEK_SET);
+       if (output_filename) {
+               output_fd = creat(output_filename, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+               if (output_fd < 0) {
+                       fprintf(stderr, "Can't open %s for writing: %s\n",
+                               output_filename, strerror(errno));
+                       exit(EXIT_FAILURE);
+               }
+               copy_file(temp_fd, output_fd);
+               close(output_fd);
+       }
+       else {
+               copy_file(temp_fd, STDOUT_FILENO);
+       }
+       exit(EXIT_SUCCESS);
+       return 0;
+}
+static void show_usage(const char *arg0)
+{
+       fprintf(stderr, "usage: %s -d|-e [-i FILE] [-o FILE]\n\n", arg0);
+       fprintf(stderr, "%-15s %s\n", "-d, --decrypt", "decrypt data");
+       fprintf(stderr, "%-15s %s\n", "-e, --encrypt", "encrypt data");
+       fprintf(stderr, "%-15s %s\n", "-i, --input", "intput file (defaults to stdin)");
+       fprintf(stderr, "%-15s %s\n", "-o, --output", "output file (defaults to stdout)");
+       exit(-1);
+}
+static void exit_cleanup(void)
+{
+       if (temp_fd >= 0) {
+               close(temp_fd);
+       }
+}
+static void copy_file(int src, int dst)
+{
+       char buf[4096];
+       ssize_t size;
+       while ((size = read(src, buf, 4096)) > 0) {
+        write(dst, buf, size);
+    }
+}
+static void do_encrypt(void *p, off_t len)
+{
+       DES_cblock *pblock;
+       int num_blocks;
+       num_blocks = len / 8;
+       pblock = (DES_cblock *) p;
+       while (num_blocks--) {
+               DES_ecb_encrypt(pblock, pblock, &schedule, DES_ENCRYPT);
+               pblock++;
+       }
+       num_blocks = (len - 3) / 8;
+       pblock = (DES_cblock *) (p + 3);
+       while (num_blocks--) {
+               DES_ecb_encrypt(pblock, pblock, &schedule, DES_ENCRYPT);
+               pblock++;
+       }
+}
+static void do_decrypt(void *p, off_t len)
+{
+       DES_cblock *pblock;
+       int num_blocks;
+       num_blocks = (len - 3) / 8;
+       pblock = (DES_cblock *) (p + 3);
+       while (num_blocks--) {
+               DES_ecb_encrypt(pblock, pblock, &schedule, DES_DECRYPT);
+               pblock++;
+       }
+       num_blocks = len / 8;
+       pblock = (DES_cblock *) p;
+       while (num_blocks--) {
+               DES_ecb_encrypt(pblock, pblock, &schedule, DES_DECRYPT);
+               pblock++;
+       }
+}
diff --git a/trunk/tools/firmware-utils/src/mkmylofw.c b/trunk/tools/firmware-utils/src/mkmylofw.c
new file mode 100644 (file)
index 0000000..b5958eb
--- /dev/null
@@ -0,0 +1,1297 @@
+/*
+ *  Copyright (C) 2006-2008 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA  02110-1301, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>     /* for unlink() */
+#include <libgen.h>
+#include <getopt.h>     /* for getopt() */
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <endian.h>     /* for __BYTE_ORDER */
+
+#if defined(__CYGWIN__)
+#  include <byteswap.h>
+#endif
+
+#if (__BYTE_ORDER == __LITTLE_ENDIAN)
+#  define HOST_TO_LE16(x)      (x)
+#  define HOST_TO_LE32(x)      (x)
+#else
+#  define HOST_TO_LE16(x)      bswap_16(x)
+#  define HOST_TO_LE32(x)      bswap_32(x)
+#endif
+
+#include "myloader.h"
+
+#define MAX_FW_BLOCKS          32
+#define MAX_ARG_COUNT   32
+#define MAX_ARG_LEN     1024
+#define FILE_BUF_LEN    (16*1024)
+#define PART_NAME_LEN  32
+
+struct fw_block {
+       uint32_t        addr;
+       uint32_t        blocklen; /* length of the block */
+       uint32_t        flags;
+
+       char            *name;  /* name of the file */
+       uint32_t        size;   /* length of the file */
+       uint32_t        crc;    /* crc value of the file */
+};
+
+struct fw_part {
+       struct mylo_partition   mylo;
+       char                    name[PART_NAME_LEN];
+};
+
+#define BLOCK_FLAG_HAVEHDR    0x0001
+
+struct cpx_board {
+       char            *model; /* model number*/
+       char            *name;  /* model name*/
+       char            *desc;  /* description */
+       uint16_t        vid;    /* vendor id */
+       uint16_t        did;    /* device id */
+       uint16_t        svid;   /* sub vendor id */
+       uint16_t        sdid;   /* sub device id */
+       uint32_t        flash_size;     /* size of flash */
+       uint32_t        part_offset;    /* offset of the partition_table */
+       uint32_t        part_size;      /* size of the partition_table */
+};
+
+#define BOARD(_vid, _did, _svid, _sdid, _flash, _mod, _name, _desc, _po, _ps) {                \
+       .model = _mod, .name = _name, .desc = _desc,                    \
+       .vid = _vid, .did = _did, .svid = _svid, .sdid = _sdid,         \
+       .flash_size = (_flash << 20),                                   \
+       .part_offset = _po, .part_size = _ps }
+
+#define CPX_BOARD(_did, _flash, _mod, _name, _desc, _po, _ps) \
+       BOARD(VENID_COMPEX, _did, VENID_COMPEX, _did, _flash, _mod, _name, _desc, _po, _ps)
+
+#define CPX_BOARD_ADM(_did, _flash, _mod, _name, _desc) \
+       CPX_BOARD(_did, _flash, _mod, _name, _desc, 0x10000, 0x10000)
+
+#define CPX_BOARD_AR71XX(_did, _flash, _mod, _name, _desc) \
+       CPX_BOARD(_did, _flash, _mod, _name, _desc, 0x20000, 0x8000)
+
+#define CPX_BOARD_AR23XX(_did, _flash, _mod, _name, _desc) \
+       CPX_BOARD(_did, _flash, _mod, _name, _desc, 0x10000, 0x10000)
+
+#define ALIGN(x,y)     ((x)+((y)-1)) & ~((y)-1)
+
+char   *progname;
+char   *ofname = NULL;
+
+uint32_t flash_size = 0;
+int    fw_num_partitions = 0;
+int    fw_num_blocks = 0;
+int    verblevel = 0;
+
+struct mylo_fw_header fw_header;
+struct fw_part fw_parts[MYLO_MAX_PARTITIONS];
+struct fw_block fw_blocks[MAX_FW_BLOCKS];
+struct cpx_board *board;
+
+struct cpx_board boards[] = {
+       CPX_BOARD_ADM(DEVID_COMPEX_NP18A, 4,
+               "NP18A", "Compex NetPassage 18A",
+               "Dualband Wireless A+G Internet Gateway"),
+       CPX_BOARD_ADM(DEVID_COMPEX_NP26G8M, 2,
+               "NP26G8M", "Compex NetPassage 26G (8M)",
+               "Wireless-G Broadband Multimedia Gateway"),
+       CPX_BOARD_ADM(DEVID_COMPEX_NP26G16M, 4,
+               "NP26G16M", "Compex NetPassage 26G (16M)",
+               "Wireless-G Broadband Multimedia Gateway"),
+       CPX_BOARD_ADM(DEVID_COMPEX_NP27G, 4,
+               "NP27G", "Compex NetPassage 27G",
+               "Wireless-G 54Mbps eXtended Range Router"),
+       CPX_BOARD_ADM(DEVID_COMPEX_NP28G, 4,
+               "NP28G", "Compex NetPassage 28G",
+               "Wireless 108Mbps Super-G XR Multimedia Router with 4 USB Ports"),
+       CPX_BOARD_ADM(DEVID_COMPEX_NP28GHS, 4,
+               "NP28GHS", "Compex NetPassage 28G (HotSpot)",
+               "HotSpot Solution"),
+       CPX_BOARD_ADM(DEVID_COMPEX_WP18, 4,
+               "WP18", "Compex NetPassage WP18",
+               "Wireless-G 54Mbps A+G Dualband Access Point"),
+       CPX_BOARD_ADM(DEVID_COMPEX_WP54G, 4,
+               "WP54G", "Compex WP54G",
+               "Wireless-G 54Mbps XR Access Point"),
+       CPX_BOARD_ADM(DEVID_COMPEX_WP54Gv1C, 2,
+               "WP54Gv1C", "Compex WP54G rev.1C",
+               "Wireless-G 54Mbps XR Access Point"),
+       CPX_BOARD_ADM(DEVID_COMPEX_WP54AG, 4,
+               "WP54AG", "Compex WP54AG",
+               "Wireless-AG 54Mbps XR Access Point"),
+       CPX_BOARD_ADM(DEVID_COMPEX_WPP54G, 4,
+               "WPP54G", "Compex WPP54G",
+               "Outdoor Access Point"),
+       CPX_BOARD_ADM(DEVID_COMPEX_WPP54AG, 4,
+               "WPP54AG", "Compex WPP54AG",
+               "Outdoor Access Point"),
+
+       CPX_BOARD_AR71XX(DEVID_COMPEX_WP543, 2,
+               "WP543", "Compex WP543",
+               "BareBoard"),
+       CPX_BOARD_AR71XX(DEVID_COMPEX_WPE72, 8,
+               "WPE72", "Compex WPE72",
+               "BareBoard"),
+
+       CPX_BOARD_AR23XX(DEVID_COMPEX_NP25G, 4,
+               "NP25G", "Compex NetPassage 25G",
+               "Wireless 54Mbps XR Router"),
+       CPX_BOARD_AR23XX(DEVID_COMPEX_WPE53G, 4,
+               "WPE53G", "Compex NetPassage 25G",
+               "Wireless 54Mbps XR Access Point"),
+       {.model = NULL}
+};
+
+void
+errmsgv(int syserr, const char *fmt, va_list arg_ptr)
+{
+       int save = errno;
+
+       fflush(0);
+       fprintf(stderr, "[%s] Error: ", progname);
+       vfprintf(stderr, fmt, arg_ptr);
+       if (syserr != 0) {
+               fprintf(stderr, ": %s", strerror(save));
+       }
+       fprintf(stderr, "\n");
+}
+
+void
+errmsg(int syserr, const char *fmt, ...)
+{
+       va_list arg_ptr;
+       va_start(arg_ptr, fmt);
+       errmsgv(syserr, fmt, arg_ptr);
+       va_end(arg_ptr);
+}
+
+void
+dbgmsg(int level, const char *fmt, ...)
+{
+       va_list arg_ptr;
+       if (verblevel >= level) {
+               fflush(0);
+               va_start(arg_ptr, fmt);
+               vfprintf(stderr, fmt, arg_ptr);
+               fprintf(stderr, "\n");
+               va_end(arg_ptr);
+       }
+}
+
+
+void
+usage(int status)
+{
+       FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+       struct cpx_board *board;
+
+       fprintf(stream, "Usage: %s [OPTION...] <file>\n", progname);
+       fprintf(stream,
+"\n"
+"  <file>          write output to the <file>\n"
+"\n"
+"Options:\n"
+"  -B <board>      create firmware for the board specified with <board>.\n"
+"                  This option set vendor id, device id, subvendor id,\n"
+"                  subdevice id, and flash size options to the right value.\n"
+"                  valid <board> values:\n");
+       for (board = boards; board->model != NULL; board++){
+               fprintf(stream,
+"                      %-12s: %s\n",
+                board->model, board->name);
+       };
+       fprintf(stream,
+"  -i <vid>:<did>[:<svid>[:<sdid>]]\n"
+"                  create firmware for board with vendor id <vid>, device\n"
+"                  id <did>, subvendor id <svid> and subdevice id <sdid>.\n"
+"  -r <rev>        set board revision to <rev>.\n"
+"  -s <size>       set flash size to <size>\n"
+"  -b <addr>:<len>[:[<flags>]:<file>]\n"
+"                  define block at <addr> with length of <len>.\n"
+"                  valid <flag> values:\n"
+"                      h : add crc header before the file data.\n"
+"  -p <addr>:<len>[:<flags>[:<param>[:<name>[:<file>]]]]\n"
+"                  add partition at <addr>, with size of <len> to the\n"
+"                  partition table, set partition name to <name>, partition \n"
+"                  flags to <flags> and partition parameter to <param>.\n"
+"                  If the <file> is specified content of the file will be \n"
+"                  added to the firmware image.\n"
+"                  valid <flag> values:\n"
+"                      a:  this is the active partition. The bootloader loads\n"
+"                          the firmware from this partition.\n"
+"                      h:  the partition data have a header.\n"
+"                      l:  the partition data uses LZMA compression.\n"
+"                      p:  the bootloader loads data from this partition to\n"
+"                          the RAM before decompress it.\n"
+"  -h              show this screen\n"
+       );
+
+       exit(status);
+}
+
+/*
+ * Code to compute the CRC-32 table. Borrowed from
+ * gzip-1.0.3/makecrc.c.
+ */
+
+static uint32_t crc_32_tab[256];
+
+void
+init_crc_table(void)
+{
+       /* Not copyrighted 1990 Mark Adler      */
+
+       uint32_t c;      /* crc shift register */
+       uint32_t e;      /* polynomial exclusive-or pattern */
+       int i;           /* counter for all possible eight bit values */
+       int k;           /* byte being shifted into crc apparatus */
+
+       /* terms of polynomial defining this crc (except x^32): */
+       static const int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+       /* Make exclusive-or pattern from polynomial */
+       e = 0;
+       for (i = 0; i < sizeof(p)/sizeof(int); i++)
+               e |= 1L << (31 - p[i]);
+
+       crc_32_tab[0] = 0;
+
+       for (i = 1; i < 256; i++) {
+               c = 0;
+               for (k = i | 256; k != 1; k >>= 1) {
+                       c = c & 1 ? (c >> 1) ^ e : c >> 1;
+                       if (k & 1)
+                               c ^= e;
+               }
+               crc_32_tab[i] = c;
+       }
+}
+
+
+void
+update_crc(uint8_t *p, uint32_t len, uint32_t *crc)
+{
+       uint32_t t;
+
+       t = *crc ^ 0xFFFFFFFFUL;
+       while (len--) {
+               t = crc_32_tab[(t ^ *p++) & 0xff] ^ (t >> 8);
+       }
+       *crc = t ^ 0xFFFFFFFFUL;
+}
+
+
+uint32_t
+get_crc(uint8_t *p, uint32_t len)
+{
+       uint32_t crc;
+
+       crc = 0;
+       update_crc(p ,len , &crc);
+       return crc;
+}
+
+
+int
+str2u32(char *arg, uint32_t *val)
+{
+       char *err = NULL;
+       uint32_t t;
+
+       errno=0;
+       t = strtoul(arg, &err, 0);
+       if (errno || (err==arg) || ((err != NULL) && *err)) {
+               return -1;
+       }
+
+       *val = t;
+       return 0;
+}
+
+
+int
+str2u16(char *arg, uint16_t *val)
+{
+       char *err = NULL;
+       uint32_t t;
+
+       errno=0;
+       t = strtoul(arg, &err, 0);
+       if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x10000)) {
+               return -1;
+       }
+
+       *val = t & 0xFFFF;
+       return 0;
+}
+
+
+struct cpx_board *
+find_board(char *model){
+       struct cpx_board *board;
+       struct cpx_board *tmp;
+
+       board = NULL;
+       for (tmp = boards; tmp->model != NULL; tmp++){
+               if (strcasecmp(model, tmp->model) == 0) {
+                       board = tmp;
+                       break;
+               }
+       };
+
+       return board;
+}
+
+
+int
+get_file_crc(struct fw_block *ff)
+{
+       FILE *f;
+       uint8_t buf[FILE_BUF_LEN];
+       uint32_t readlen = sizeof(buf);
+       int res = -1;
+       size_t len;
+
+       if ((ff->flags & BLOCK_FLAG_HAVEHDR) == 0) {
+               res = 0;
+               goto out;
+       }
+
+       errno = 0;
+       f = fopen(ff->name,"r");
+       if (errno) {
+               errmsg(1,"unable to open file %s", ff->name);
+               goto out;
+       }
+
+       ff->crc = 0;
+       len = ff->size;
+       while (len > 0) {
+               if (len < readlen)
+                       readlen = len;
+
+               errno = 0;
+               fread(buf, readlen, 1, f);
+               if (errno) {
+                       errmsg(1,"unable to read from file %s", ff->name);
+                       goto out_close;
+               }
+
+               update_crc(buf, readlen, &ff->crc);
+               len -= readlen;
+       }
+
+       res = 0;
+
+out_close:
+       fclose(f);
+out:
+       return res;
+}
+
+
+int
+process_files(void)
+{
+       struct fw_block *b;
+       struct stat st;
+       int i;
+
+       for (i = 0; i < fw_num_blocks; i++) {
+               b = &fw_blocks[i];
+               if ((b->addr + b->blocklen) > flash_size) {
+                       errmsg(0, "block at 0x%08X is too big", b->addr);
+                       return -1;
+               }
+               if (b->name == NULL)
+                       continue;
+
+               if (stat(b->name, &st) < 0) {
+                       errmsg(0, "stat failed on %s",b->name);
+                       return -1;
+               }
+               if (b->blocklen == 0) {
+                       b->blocklen = flash_size - b->addr;
+               }
+               if (st.st_size > b->blocklen) {
+                       errmsg(0,"file %s is too big",b->name);
+                       return -1;
+               }
+
+               b->size = st.st_size;
+       }
+
+       return 0;
+}
+
+
+int
+process_partitions(void)
+{
+       struct mylo_partition *part;
+       int i;
+
+       for (i = 0; i < fw_num_partitions; i++) {
+               part = &fw_parts[i].mylo;
+
+               if (part->addr > flash_size) {
+                       errmsg(0, "invalid partition at 0x%08X", part->addr);
+                       return -1;
+               }
+
+               if ((part->addr + part->size) > flash_size) {
+                       errmsg(0, "partition at 0x%08X is too big", part->addr);
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+
+/*
+ * routines to write data to the output file
+ */
+int
+write_out_data(FILE *outfile, uint8_t *data, size_t len, uint32_t *crc)
+{
+       errno = 0;
+
+       fwrite(data, len, 1, outfile);
+       if (errno) {
+               errmsg(1,"unable to write output file");
+               return -1;
+       }
+
+       if (crc) {
+               update_crc(data, len, crc);
+       }
+
+       return 0;
+}
+
+
+int
+write_out_desc(FILE *outfile, struct mylo_fw_blockdesc *desc, uint32_t *crc)
+{
+       return write_out_data(outfile, (uint8_t *)desc,
+               sizeof(*desc), crc);
+}
+
+
+int
+write_out_padding(FILE *outfile, size_t len, uint8_t padc, uint32_t *crc)
+{
+       uint8_t buff[512];
+       size_t  buflen = sizeof(buff);
+
+       memset(buff, padc, buflen);
+
+       while (len > 0) {
+               if (len < buflen)
+                       buflen = len;
+
+               if (write_out_data(outfile, buff, buflen, crc))
+                       return -1;
+
+               len -= buflen;
+       }
+
+       return 0;
+}
+
+
+int
+write_out_file(FILE *outfile, struct fw_block *block, uint32_t *crc)
+{
+       char buff[FILE_BUF_LEN];
+       size_t  buflen = sizeof(buff);
+       FILE *f;
+       size_t len;
+
+       errno = 0;
+
+       if (block->name == NULL) {
+               return 0;
+       }
+
+       if ((block->flags & BLOCK_FLAG_HAVEHDR) != 0) {
+               struct mylo_partition_header ph;
+
+               if (get_file_crc(block) != 0)
+                       return -1;
+
+               ph.crc = HOST_TO_LE32(block->crc);
+               ph.len = HOST_TO_LE32(block->size);
+
+               if (write_out_data(outfile, (uint8_t *)&ph, sizeof(ph), crc) != 0)
+                       return -1;
+       }
+
+       f = fopen(block->name,"r");
+       if (errno) {
+               errmsg(1,"unable to open file: %s", block->name);
+               return -1;
+       }
+
+       len = block->size;
+       while (len > 0) {
+               if (len < buflen)
+                       buflen = len;
+
+               /* read data from source file */
+               errno = 0;
+               fread(buff, buflen, 1, f);
+               if (errno != 0) {
+                       errmsg(1,"unable to read from file: %s",block->name);
+                       return -1;
+               }
+
+               if (write_out_data(outfile, buff, buflen, crc) != 0)
+                       return -1;
+
+               len -= buflen;
+       }
+
+       fclose(f);
+
+       /* align next block on a 4 byte boundary */
+       len = ALIGN(len,4) - block->size;
+       if (write_out_padding(outfile, len, 0xFF, crc))
+               return -1;
+
+       dbgmsg(1,"file %s written out", block->name);
+       return 0;
+}
+
+
+int
+write_out_header(FILE *outfile, uint32_t *crc)
+{
+       struct mylo_fw_header hdr;
+
+       memset(&hdr, 0, sizeof(hdr));
+
+       hdr.magic = HOST_TO_LE32(MYLO_MAGIC_FIRMWARE);
+       hdr.crc = HOST_TO_LE32(fw_header.crc);
+       hdr.vid = HOST_TO_LE16(fw_header.vid);
+       hdr.did = HOST_TO_LE16(fw_header.did);
+       hdr.svid = HOST_TO_LE16(fw_header.svid);
+       hdr.sdid = HOST_TO_LE16(fw_header.sdid);
+       hdr.rev = HOST_TO_LE32(fw_header.rev);
+       hdr.fwhi = HOST_TO_LE32(fw_header.fwhi);
+       hdr.fwlo = HOST_TO_LE32(fw_header.fwlo);
+       hdr.flags = HOST_TO_LE32(fw_header.flags);
+
+       if (fseek(outfile, 0, SEEK_SET) != 0) {
+               errmsg(1,"fseek failed on output file");
+               return -1;
+       }
+
+       return write_out_data(outfile, (uint8_t *)&hdr, sizeof(hdr), crc);
+}
+
+
+int
+write_out_partitions(FILE *outfile, uint32_t *crc)
+{
+       struct mylo_partition_table p;
+       char part_names[MYLO_MAX_PARTITIONS][PART_NAME_LEN];
+       int ret;
+       int i;
+
+       if (fw_num_partitions == 0)
+               return 0;
+
+       memset(&p, 0, sizeof(p));
+       memset(part_names, 0, sizeof(part_names));
+
+       p.magic = HOST_TO_LE32(MYLO_MAGIC_PARTITIONS);
+       for (i = 0; i < fw_num_partitions; i++) {
+               struct mylo_partition *mp;
+               struct fw_part *fp;
+
+               mp = &p.partitions[i];
+               fp = &fw_parts[i];
+               mp->flags = HOST_TO_LE16(fp->mylo.flags);
+               mp->type = HOST_TO_LE16(PARTITION_TYPE_USED);
+               mp->addr = HOST_TO_LE32(fp->mylo.addr);
+               mp->size = HOST_TO_LE32(fp->mylo.size);
+               mp->param = HOST_TO_LE32(fp->mylo.param);
+
+               memcpy(part_names[i], fp->name, PART_NAME_LEN);
+       }
+
+       ret = write_out_data(outfile, (uint8_t *)&p, sizeof(p), crc);
+       if (ret)
+               return ret;
+
+       ret = write_out_data(outfile, (uint8_t *)part_names, sizeof(part_names),
+                               crc);
+       return ret;
+}
+
+
+int
+write_out_blocks(FILE *outfile, uint32_t *crc)
+{
+       struct mylo_fw_blockdesc desc;
+       struct fw_block *b;
+       uint32_t dlen;
+       int i;
+
+       /*
+        * if at least one partition specified, write out block descriptor
+        * for the partition table
+        */
+       if (fw_num_partitions > 0) {
+               desc.type = HOST_TO_LE32(FW_DESC_TYPE_USED);
+               desc.addr = HOST_TO_LE32(board->part_offset);
+               desc.dlen = HOST_TO_LE32(sizeof(struct mylo_partition_table) +
+                                       (MYLO_MAX_PARTITIONS * PART_NAME_LEN));
+               desc.blen = HOST_TO_LE32(board->part_size);
+
+               if (write_out_desc(outfile, &desc, crc) != 0)
+                       return -1;
+       }
+
+       /*
+        * write out block descriptors for each files
+        */
+       for (i = 0; i < fw_num_blocks; i++) {
+               b = &fw_blocks[i];
+
+               /* detect block size */
+               dlen = b->size;
+               if ((b->flags & BLOCK_FLAG_HAVEHDR) != 0) {
+                       dlen += sizeof(struct mylo_partition_header);
+               }
+
+               /* round up to 4 bytes */
+               dlen = ALIGN(dlen, 4);
+
+               /* setup the descriptor */
+               desc.type = HOST_TO_LE32(FW_DESC_TYPE_USED);
+               desc.addr = HOST_TO_LE32(b->addr);
+               desc.dlen = HOST_TO_LE32(dlen);
+               desc.blen = HOST_TO_LE32(b->blocklen);
+
+               if (write_out_desc(outfile, &desc, crc) != 0)
+                       return -1;
+       }
+
+       /*
+        * write out the null block descriptor
+        */
+       memset(&desc, 0, sizeof(desc));
+       if (write_out_desc(outfile, &desc, crc) != 0)
+               return -1;
+
+       if (write_out_partitions(outfile, crc) != 0)
+               return -1;
+
+       /*
+        * write out data for each blocks
+        */
+       for (i = 0; i < fw_num_blocks; i++) {
+               b = &fw_blocks[i];
+               if (write_out_file(outfile, b, crc) != 0)
+                       return -1;
+       }
+
+       return 0;
+}
+
+
+/*
+ * argument parsing
+ */
+int
+parse_arg(char *arg, char *buf, char *argv[])
+{
+       int res = 0;
+       size_t argl;
+       char *tok;
+       char **ap = &buf;
+       int i;
+
+       if ((arg == NULL)) {
+               /* invalid argument string */
+               return -1;
+       }
+
+       argl = strlen(arg);
+       if (argl == 0) {
+               /* no arguments */
+               return res;
+       }
+
+       if (argl >= MAX_ARG_LEN) {
+               /* argument is too long */
+               argl = MAX_ARG_LEN-1;
+       }
+
+       memset(argv, 0, MAX_ARG_COUNT * sizeof(void *));
+       memcpy(buf, arg, argl);
+       buf[argl] = '\0';
+
+       for (i = 0; i < MAX_ARG_COUNT; i++) {
+               tok = strsep(ap, ":");
+               if (tok == NULL) {
+                       break;
+               }
+#if 0
+               else if (tok[0] == '\0') {
+                       break;
+               }
+#endif
+               argv[i] = tok;
+               res++;
+       }
+
+       return res;
+}
+
+
+int
+required_arg(char c, char *arg)
+{
+       if ((optarg != NULL) && (*arg == '-')){
+               errmsg(0,"option %c requires an argument\n", c);
+               return -1;
+       }
+
+       return 0;
+}
+
+
+int
+is_empty_arg(char *arg)
+{
+       int ret = 1;
+       if (arg != NULL) {
+               if (*arg) ret = 0;
+       };
+       return ret;
+}
+
+
+int
+parse_opt_flags(char ch, char *arg)
+{
+       if (required_arg(ch, arg)) {
+               goto err_out;
+       }
+
+       if (str2u32(arg, &fw_header.flags) != 0) {
+               errmsg(0,"invalid firmware flags: %s", arg);
+               goto err_out;
+       }
+
+       dbgmsg(1, "firmware flags set to %X bytes", fw_header.flags);
+
+       return 0;
+
+err_out:
+       return -1;
+}
+
+
+int
+parse_opt_size(char ch, char *arg)
+{
+       if (required_arg(ch, arg)) {
+               goto err_out;
+       }
+
+       if (str2u32(arg, &flash_size) != 0) {
+               errmsg(0,"invalid flash size: %s", arg);
+               goto err_out;
+       }
+
+       dbgmsg(1, "flash size set to %d bytes", flash_size);
+
+       return 0;
+
+err_out:
+       return -1;
+}
+
+
+int
+parse_opt_id(char ch, char *arg)
+{
+       char buf[MAX_ARG_LEN];
+       char *argv[MAX_ARG_COUNT];
+       int argc;
+       char *p;
+
+       if (required_arg(ch, arg)) {
+               goto err_out;
+       }
+
+       argc = parse_arg(arg, buf, argv);
+
+       /* processing vendor ID*/
+       p = argv[0];
+       if (is_empty_arg(p)) {
+               errmsg(0,"vendor id is missing from -%c %s",ch, arg);
+               goto err_out;
+       } else if (str2u16(p, &fw_header.vid) != 0) {
+               errmsg(0,"invalid vendor id: %s", p);
+               goto err_out;
+       }
+
+       dbgmsg(1, "vendor id is set to 0x%04X", fw_header.vid);
+
+       /* processing device ID*/
+       p = argv[1];
+       if (is_empty_arg(p)) {
+               errmsg(0,"device id is missing from -%c %s",ch, arg);
+               goto err_out;
+       } else if (str2u16(p, &fw_header.did) != 0) {
+               errmsg(0,"invalid device id: %s", p);
+               goto err_out;
+       }
+
+       dbgmsg(1, "device id is set to 0x%04X", fw_header.did);
+
+       /* processing sub vendor ID*/
+       p = argv[2];
+       if (is_empty_arg(p)) {
+               fw_header.svid = fw_header.vid;
+       } else if (str2u16(p, &fw_header.svid) != 0) {
+               errmsg(0,"invalid sub vendor id: %s", p);
+               goto err_out;
+       }
+
+       dbgmsg(1, "sub vendor id is set to 0x%04X", fw_header.svid);
+
+       /* processing device ID*/
+       p = argv[3];
+       if (is_empty_arg(p)) {
+               fw_header.sdid = fw_header.did;
+       } else if (str2u16(p, &fw_header.sdid) != 0) {
+               errmsg(0,"invalid sub device id: %s", p);
+               goto err_out;
+       }
+
+       dbgmsg(1, "sub device id is set to 0x%04X", fw_header.sdid);
+
+       /* processing revision */
+       p = argv[4];
+       if (is_empty_arg(p)) {
+               fw_header.rev = 0;
+       } else if (str2u32(arg, &fw_header.rev) != 0) {
+               errmsg(0,"invalid revision number: %s", p);
+               goto err_out;
+       }
+
+       dbgmsg(1, "board revision is set to 0x%08X", fw_header.rev);
+
+       return 0;
+
+err_out:
+       return -1;
+}
+
+
+int
+parse_opt_block(char ch, char *arg)
+{
+       char buf[MAX_ARG_LEN];
+       char *argv[MAX_ARG_COUNT];
+       int argc;
+       struct fw_block *b;
+       char *p;
+
+       if (required_arg(ch, arg)) {
+               goto err_out;
+       }
+
+       if (fw_num_blocks >= MAX_FW_BLOCKS) {
+               errmsg(0,"too many blocks specified");
+               goto err_out;
+       }
+
+       argc = parse_arg(arg, buf, argv);
+       dbgmsg(1,"processing block option %s, count %d", arg, argc);
+
+       b = &fw_blocks[fw_num_blocks++];
+
+       /* processing block address */
+       p = argv[0];
+       if (is_empty_arg(p)) {
+               errmsg(0,"no block address specified in %s", arg);
+               goto err_out;
+       } else if (str2u32(p, &b->addr) != 0) {
+               errmsg(0,"invalid block address: %s", p);
+               goto err_out;
+       }
+
+       /* processing block length */
+       p = argv[1];
+       if (is_empty_arg(p)) {
+               errmsg(0,"no block length specified in %s", arg);
+               goto err_out;
+       } else if (str2u32(p, &b->blocklen) != 0) {
+               errmsg(0,"invalid block length: %s", p);
+               goto err_out;
+       }
+
+       if (argc < 3) {
+               dbgmsg(1,"empty block %s", arg);
+               goto success;
+       }
+
+       /* processing flags */
+       p = argv[2];
+       if (is_empty_arg(p) == 0) {
+               for ( ; *p != '\0'; p++) {
+                       switch (*p) {
+                       case 'h':
+                               b->flags |= BLOCK_FLAG_HAVEHDR;
+                               break;
+                       default:
+                               errmsg(0, "invalid block flag \"%c\"", *p);
+                               goto err_out;
+                       }
+               }
+       }
+
+       /* processing file name */
+       p = argv[3];
+       if (is_empty_arg(p)) {
+               errmsg(0,"file name missing in %s", arg);
+               goto err_out;
+       }
+
+       b->name = strdup(p);
+       if (b->name == NULL) {
+               errmsg(0,"not enough memory");
+               goto err_out;
+       }
+
+success:
+
+       return 0;
+
+err_out:
+       return -1;
+}
+
+
+int
+parse_opt_partition(char ch, char *arg)
+{
+       char buf[MAX_ARG_LEN];
+       char *argv[MAX_ARG_COUNT];
+       int argc;
+       char *p;
+       struct mylo_partition *part;
+       struct fw_part *fp;
+
+       if (required_arg(ch, arg)) {
+               goto err_out;
+       }
+
+       if (fw_num_partitions >= MYLO_MAX_PARTITIONS) {
+               errmsg(0, "too many partitions specified");
+               goto err_out;
+       }
+
+       fp = &fw_parts[fw_num_partitions++];
+       part = &fp->mylo;
+
+       argc = parse_arg(arg, buf, argv);
+
+       /* processing partition address */
+       p = argv[0];
+       if (is_empty_arg(p)) {
+               errmsg(0,"partition address missing in -%c %s",ch, arg);
+               goto err_out;
+       } else if (str2u32(p, &part->addr) != 0) {
+               errmsg(0,"invalid partition address: %s", p);
+               goto err_out;
+       }
+
+       /* processing partition size */
+       p = argv[1];
+       if (is_empty_arg(p)) {
+               errmsg(0,"partition size missing in -%c %s",ch, arg);
+               goto err_out;
+       } else if (str2u32(p, &part->size) != 0) {
+               errmsg(0,"invalid partition size: %s", p);
+               goto err_out;
+       }
+
+       /* processing partition flags */
+       p = argv[2];
+       if (is_empty_arg(p) == 0) {
+               for ( ; *p != '\0'; p++) {
+                       switch (*p) {
+                       case 'a':
+                               part->flags |= PARTITION_FLAG_ACTIVE;
+                               break;
+                       case 'p':
+                               part->flags |= PARTITION_FLAG_PRELOAD;
+                               break;
+                       case 'l':
+                               part->flags |= PARTITION_FLAG_LZMA;
+                               break;
+                       case 'h':
+                               part->flags |= PARTITION_FLAG_HAVEHDR;
+                               break;
+                       default:
+                               errmsg(0, "invalid partition flag \"%c\"", *p);
+                               goto err_out;
+                       }
+               }
+       }
+
+       /* processing partition parameter */
+       p = argv[3];
+       if (is_empty_arg(p)) {
+               /* set default partition parameter */
+               part->param = 0;
+       } else if (str2u32(p, &part->param) != 0) {
+               errmsg(0,"invalid partition parameter: %s", p);
+               goto err_out;
+       }
+
+       p = argv[4];
+       if (is_empty_arg(p)) {
+               /* set default partition parameter */
+               fp->name[0] = '\0';
+       } else {
+               strncpy(fp->name, p, PART_NAME_LEN);
+       }
+
+#if 1
+       if (part->size == 0) {
+               part->size = flash_size - part->addr;
+       }
+
+       /* processing file parameter */
+       p = argv[5];
+       if (is_empty_arg(p) == 0) {
+               struct fw_block *b;
+
+               if (fw_num_blocks == MAX_FW_BLOCKS) {
+                       errmsg(0,"too many blocks specified", p);
+                       goto err_out;
+               }
+               b = &fw_blocks[fw_num_blocks++];
+               b->name = strdup(p);
+               b->addr = part->addr;
+               b->blocklen = part->size;
+               if (part->flags & PARTITION_FLAG_HAVEHDR) {
+                       b->flags |= BLOCK_FLAG_HAVEHDR;
+               }
+       }
+#endif
+
+       return 0;
+
+err_out:
+       return -1;
+}
+
+
+int
+parse_opt_board(char ch, char *arg)
+{
+       if (required_arg(ch, arg)) {
+               goto err_out;
+       }
+
+       board = find_board(arg);
+       if (board == NULL){
+               errmsg(0,"invalid/unknown board specified: %s", arg);
+               goto err_out;
+       }
+
+       fw_header.vid = board->vid;
+       fw_header.did = board->did;
+       fw_header.svid = board->svid;
+       fw_header.sdid = board->sdid;
+
+       flash_size = board->flash_size;
+
+       return 0;
+
+err_out:
+       return -1;
+}
+
+
+int
+parse_opt_rev(char ch, char *arg)
+{
+       if (required_arg(ch, arg)) {
+               return -1;
+       }
+
+       if (str2u32(arg, &fw_header.rev) != 0) {
+               errmsg(0,"invalid revision number: %s", arg);
+               return -1;
+       }
+
+       return 0;
+}
+
+
+/*
+ * main
+ */
+int
+main(int argc, char *argv[])
+{
+       int optinvalid = 0;   /* flag for invalid option */
+       int c;
+       int res = EXIT_FAILURE;
+
+       FILE  *outfile;
+       uint32_t crc;
+
+       progname=basename(argv[0]);
+
+       memset(&fw_header, 0, sizeof(fw_header));
+
+       /* init header defaults */
+       fw_header.vid = VENID_COMPEX;
+       fw_header.did = DEVID_COMPEX_WP54G;
+       fw_header.svid = VENID_COMPEX;
+       fw_header.sdid = DEVID_COMPEX_WP54G;
+       fw_header.fwhi = 0x20000;
+       fw_header.fwlo = 0x20000;
+       fw_header.flags = 0;
+
+       opterr = 0;  /* could not print standard getopt error messages */
+       while ((c = getopt(argc, argv, "b:B:f:hi:p:r:s:v")) != -1) {
+               optinvalid = 0;
+               switch (c) {
+               case 'b':
+                       optinvalid = parse_opt_block(c,optarg);
+                       break;
+               case 'B':
+                       optinvalid = parse_opt_board(c,optarg);
+                       break;
+               case 'f':
+                       optinvalid = parse_opt_flags(c,optarg);
+                       break;
+               case 'h':
+                       usage(EXIT_SUCCESS);
+                       break;
+               case 'i':
+                       optinvalid = parse_opt_id(c,optarg);
+                       break;
+               case 'p':
+                       optinvalid = parse_opt_partition(c,optarg);
+                       break;
+               case 'r':
+                       optinvalid = parse_opt_rev(c,optarg);
+                       break;
+               case 's':
+                       optinvalid = parse_opt_size(c,optarg);
+                       break;
+               case 'v':
+                       verblevel++;
+                       break;
+               default:
+                       optinvalid = 1;
+                       break;
+               }
+               if (optinvalid != 0 ){
+                       errmsg(0, "invalid option: -%c", optopt);
+                       goto out;
+               }
+       }
+
+       if (optind == argc) {
+               errmsg(0, "no output file specified");
+               goto out;
+       }
+
+       ofname = argv[optind++];
+
+       if (optind < argc) {
+               errmsg(0, "invalid option: %s", argv[optind]);
+               goto out;
+       }
+
+       if (!board) {
+               errmsg(0, "no board specified");
+               goto out;
+       }
+
+       if (flash_size == 0) {
+               errmsg(0, "no flash size specified");
+               goto out;
+       }
+
+       if (process_files() != 0) {
+               goto out;
+       }
+
+       if (process_partitions() != 0) {
+               goto out;
+       }
+
+       outfile = fopen(ofname, "w");
+       if (outfile == NULL) {
+               errmsg(1, "could not open \"%s\" for writing", ofname);
+               goto out;
+       }
+
+       crc = 0;
+       init_crc_table();
+
+       if (write_out_header(outfile, &crc) != 0)
+               goto out_flush;
+
+       if (write_out_blocks(outfile, &crc) != 0)
+               goto out_flush;
+
+       fw_header.crc = crc;
+       if (write_out_header(outfile, NULL) != 0)
+               goto out_flush;
+
+       dbgmsg(1,"Firmware file %s completed.", ofname);
+
+       res = EXIT_SUCCESS;
+
+out_flush:
+       fflush(outfile);
+       fclose(outfile);
+       if (res != EXIT_SUCCESS) {
+               unlink(ofname);
+       }
+out:
+       return res;
+}
diff --git a/trunk/tools/firmware-utils/src/mkplanexfw.c b/trunk/tools/firmware-utils/src/mkplanexfw.c
new file mode 100644 (file)
index 0000000..1bdccb7
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+ *  Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>     /* for unlink() */
+#include <libgen.h>
+#include <getopt.h>     /* for getopt() */
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include "sha1.h"
+
+#if (__BYTE_ORDER == __BIG_ENDIAN)
+#  define HOST_TO_BE32(x)      (x)
+#  define BE32_TO_HOST(x)      (x)
+#else
+#  define HOST_TO_BE32(x)      bswap_32(x)
+#  define BE32_TO_HOST(x)      bswap_32(x)
+#endif
+
+
+struct planex_hdr {
+       uint8_t         sha1sum[20];
+       char            version[8];
+       uint8_t         unk1[2];
+       uint32_t        datalen;
+} __attribute__ ((packed));
+
+struct board_info {
+       char            *id;
+       uint32_t        seed;
+       uint8_t         unk[2];
+       uint32_t        datalen;
+};
+
+/*
+ * Globals
+ */
+static char *ifname;
+static char *progname;
+static char *ofname;
+static char *version = "1.00.00";
+
+static char *board_id;
+static struct board_info *board;
+
+static struct board_info boards[] = {
+       {
+               .id             = "MZK-W04NU",
+               .seed           = 2,
+               .unk            = {0x04, 0x08},
+               .datalen        = 0x770000,
+       }, {
+               .id             = "MZK-W300NH",
+               .seed           = 4,
+               .unk            = {0x00, 0x00},
+               .datalen        = 0x770000,
+       }, {
+               /* terminating entry */
+       }
+};
+
+/*
+ * Message macros
+ */
+#define ERR(fmt, ...) do { \
+       fflush(0); \
+       fprintf(stderr, "[%s] *** error: " fmt "\n", \
+                       progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERRS(fmt, ...) do { \
+       int save = errno; \
+       fflush(0); \
+       fprintf(stderr, "[%s] *** error: " fmt "\n", \
+                       progname, ## __VA_ARGS__, strerror(save)); \
+} while (0)
+
+static struct board_info *find_board(char *id)
+{
+       struct board_info *ret;
+       struct board_info *board;
+
+       ret = NULL;
+       for (board = boards; board->id != NULL; board++){
+               if (strcasecmp(id, board->id) == 0) {
+                       ret = board;
+                       break;
+               }
+       };
+
+       return ret;
+}
+
+void usage(int status)
+{
+       FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+       struct board_info *board;
+
+       fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+       fprintf(stream,
+"\n"
+"Options:\n"
+"  -B <board>      create image for the board specified with <board>\n"
+"  -i <file>       read input from the file <file>\n"
+"  -o <file>       write output to the file <file>\n"
+"  -v <version>    set image version to <version>\n"
+"  -h              show this screen\n"
+       );
+
+       exit(status);
+}
+
+int main(int argc, char *argv[])
+{
+       int res = EXIT_FAILURE;
+       int buflen;
+       int err;
+       struct stat st;
+       char *buf;
+       struct planex_hdr *hdr;
+       sha1_context ctx;
+       uint32_t seed;
+
+       FILE *outfile, *infile;
+
+       progname = basename(argv[0]);
+
+       while ( 1 ) {
+               int c;
+
+               c = getopt(argc, argv, "B:i:o:v:h");
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'B':
+                       board_id = optarg;
+                       break;
+               case 'i':
+                       ifname = optarg;
+                       break;
+               case 'o':
+                       ofname = optarg;
+                       break;
+               case 'v':
+                       version = optarg;
+                       break;
+               case 'h':
+                       usage(EXIT_SUCCESS);
+                       break;
+               default:
+                       usage(EXIT_FAILURE);
+                       break;
+               }
+       }
+
+       if (board_id == NULL) {
+               ERR("no board specified");
+               goto err;
+       }
+
+       board = find_board(board_id);
+       if (board == NULL) {
+               ERR("unknown board '%s'", board_id);
+               goto err;
+       };
+
+       if (ifname == NULL) {
+               ERR("no input file specified");
+               goto err;
+       }
+
+       if (ofname == NULL) {
+               ERR("no output file specified");
+               goto err;
+       }
+
+       err = stat(ifname, &st);
+       if (err){
+               ERRS("stat failed on %s", ifname);
+               goto err;
+       }
+
+       if (st.st_size > board->datalen) {
+               ERR("file '%s' is too big - max size: 0x%08X (exceeds %lu bytes)\n",
+                   ifname, board->datalen, st.st_size - board->datalen);
+               goto err;
+       }
+
+       buflen = board->datalen + 0x10000;
+       buf = malloc(buflen);
+       if (!buf) {
+               ERR("no memory for buffer\n");
+               goto err;
+       }
+
+       memset(buf, 0xff, buflen);
+       hdr = (struct planex_hdr *)buf;
+
+       hdr->datalen = HOST_TO_BE32(board->datalen);
+       hdr->unk1[0] = board->unk[0];
+       hdr->unk1[1] = board->unk[1];
+
+       snprintf(hdr->version, sizeof(hdr->version), "%s", version);
+
+       infile = fopen(ifname, "r");
+       if (infile == NULL) {
+               ERRS("could not open \"%s\" for reading", ifname);
+               goto err_free;
+       }
+
+       errno = 0;
+       fread(buf +  sizeof(*hdr), st.st_size, 1, infile);
+       if (errno != 0) {
+               ERRS("unable to read from file %s", ifname);
+               goto err_close_in;
+       }
+
+       seed = HOST_TO_BE32(board->seed);
+       sha1_starts(&ctx);
+       sha1_update(&ctx, (uchar *) &seed, sizeof(seed));
+       sha1_update(&ctx, buf + sizeof(*hdr), board->datalen);
+       sha1_finish(&ctx, hdr->sha1sum);
+
+       outfile = fopen(ofname, "w");
+       if (outfile == NULL) {
+               ERRS("could not open \"%s\" for writing", ofname);
+               goto err_close_in;
+       }
+
+       errno = 0;
+       fwrite(buf, buflen, 1, outfile);
+       if (errno) {
+               ERRS("unable to write to file %s", ofname);
+               goto err_close_out;
+       }
+
+       res = EXIT_SUCCESS;
+
+ out_flush:
+       fflush(outfile);
+
+ err_close_out:
+       fclose(outfile);
+       if (res != EXIT_SUCCESS) {
+               unlink(ofname);
+       }
+
+ err_close_in:
+       fclose(infile);
+
+ err_free:
+       free(buf);
+
+ err:
+       return res;
+}
+
diff --git a/trunk/tools/firmware-utils/src/mkporayfw.c b/trunk/tools/firmware-utils/src/mkporayfw.c
new file mode 100644 (file)
index 0000000..802d5ef
--- /dev/null
@@ -0,0 +1,791 @@
+/*
+ * Builder/viewer/extractor utility for Poray firmware image files
+ *
+ * Copyright (C) 2013 Michel Stempin <michel.stempin@wanadoo.fr>
+ * Copyright (C) 2013 Felix Kaechele <felix@fetzig.org>
+ * Copyright (C) 2013 <admin@openschemes.com>
+ *
+ * This tool is based on:
+ *   TP-Link firmware upgrade tool.
+ *   Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Itself based on:
+ *   TP-Link WR941 V2 firmware checksum fixing tool.
+ *   Copyright (C) 2008,2009 Wang Jian <lark@linux.net.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <libgen.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#if (__BYTE_ORDER == __BIG_ENDIAN)
+#  define HOST_TO_BE32(x)      (x)
+#  define BE32_TO_HOST(x)      (x)
+#  define HOST_TO_LE32(x)      bswap_32(x)
+#  define LE32_TO_HOST(x)      bswap_32(x)
+#else
+#  define HOST_TO_BE32(x)      bswap_32(x)
+#  define BE32_TO_HOST(x)      bswap_32(x)
+#  define HOST_TO_LE32(x)      (x)
+#  define LE32_TO_HOST(x)      (x)
+#endif
+
+/* Fixed header flags */
+#define HEADER_FLAGS           0x020e0000
+
+/* Recognized Hardware ID magic */
+#define HWID_HAME_MPR_A1_L8    0x32473352
+#define HWID_PORAY_R50B                0x31353033
+#define HWID_PORAY_R50D                0x33353033
+#define HWID_PORAY_R50E                0x34353033
+#define HWID_PORAY_M3          0x31353335
+#define HWID_PORAY_M4          0x32353335
+#define HWID_PORAY_Q3          0x33353335
+#define HWID_PORAY_X5_X6       0x35353335
+#define HWID_PORAY_X8          0x36353335
+#define HWID_PORAY_X1          0x38353335
+#define HWID_NEXX_WT1520       0x30353332
+#define HWID_NEXX_WT3020       0x30323033
+#define HWID_A5_V11            0x32473352
+
+/* Recognized XOR obfuscation keys */
+#define KEY_HAME               0
+#define KEY_PORAY_1            1
+#define KEY_PORAY_2            2
+#define KEY_PORAY_3            3
+#define KEY_PORAY_4            4
+#define KEY_NEXX_1             5
+#define KEY_NEXX_2             6
+#define KEY_A5_V11             7
+
+/* XOR key length */
+#define KEY_LEN                        15
+
+struct file_info {
+       char            *file_name;     /* Name of the file */
+       uint32_t        file_size;      /* Length of the file */
+};
+
+struct fw_header {
+       uint32_t        hw_id;          /* Hardware id */
+       uint32_t        firmware_len;   /* Firmware data length */
+       uint32_t        flags;          /* Header flags */
+       uint8_t         pad[16];
+} __attribute__ ((packed));
+
+struct flash_layout {
+       char            *id;
+       uint32_t        fw_max_len;
+};
+
+struct board_info {
+       char            *id;
+       uint32_t        hw_id;
+       char            *layout_id;
+       uint32_t        key;
+};
+
+/*
+ * Globals
+ */
+static char *ofname;
+static char *progname;
+
+static char *board_id;
+static struct board_info *board;
+static char *layout_id;
+static struct flash_layout *layout;
+static char *opt_hw_id;
+static uint32_t hw_id;
+static struct file_info firmware_info;
+static uint32_t firmware_len = 0;
+
+static int inspect = 0;
+static int extract = 0;
+
+static uint8_t key[][KEY_LEN] = {
+  {0xC8, 0x3C, 0x3A, 0x93, 0xA2, 0x95, 0xC3, 0x63, 0x48, 0x45, 0x58, 0x09, 0x12, 0x03, 0x08},
+  {0x89, 0x6B, 0x5A, 0x93, 0x92, 0x95, 0xC3, 0x63, 0xD0, 0xA3, 0x9C, 0x92, 0x2E, 0xE6, 0xC7},
+  {0xC9, 0x1C, 0x3A, 0x93, 0x92, 0x95, 0xC3, 0x63, 0xD0, 0xA3, 0x9C, 0x92, 0x2E, 0xE6, 0xC7},
+  {0x19, 0x1B, 0x3A, 0x93, 0x92, 0x95, 0xC3, 0x63, 0xD0, 0xA3, 0x9C, 0x92, 0x2E, 0xE6, 0xC7},
+  {0x79, 0x7B, 0x7A, 0x93, 0x92, 0x95, 0xC3, 0x63, 0xD0, 0xA3, 0x9C, 0x92, 0x2E, 0xE6, 0xC7},
+  {0x19, 0x1C, 0x4A, 0x93, 0x96, 0x95, 0xC3, 0x63, 0xD0, 0xA3, 0x9C, 0x92, 0x2E, 0x16, 0xC6},
+  {0x39, 0x1C, 0x4A, 0x93, 0x96, 0x95, 0xC3, 0x63, 0xD0, 0xA3, 0x9C, 0x92, 0x2E, 0x16, 0xC6},
+  {0xC8, 0x3C, 0x3A, 0x93, 0xA2, 0x95, 0xC3, 0x63, 0x48, 0x45, 0x58, 0x09, 0x20, 0x11, 0x08},
+};
+
+static struct flash_layout layouts[] = {
+       {
+               .id             = "4M",
+               .fw_max_len     = 0x3c0000,
+       }, {
+               .id             = "8M",
+               .fw_max_len     = 0x7c0000,
+       }, {
+               /* terminating entry */
+       }
+};
+
+static struct board_info boards[] = {
+       {
+               .id             = "A5-V11",
+               .hw_id          = HWID_A5_V11,
+               .layout_id      = "4M",
+               .key            = KEY_A5_V11,
+        }, {
+               .id             = "MPR-A1",
+               .hw_id          = HWID_HAME_MPR_A1_L8,
+               .layout_id      = "4M",
+               .key            = KEY_HAME,
+       }, {
+               .id             = "MPR-L8",
+               .hw_id          = HWID_HAME_MPR_A1_L8,
+               .layout_id      = "4M",
+               .key            = KEY_HAME,
+       }, {
+               .id             = "R50B",
+               .hw_id          = HWID_PORAY_R50B,
+               .layout_id      = "4M",
+               .key            = KEY_PORAY_2,
+       }, {
+               .id             = "R50D",
+               .hw_id          = HWID_PORAY_R50D,
+               .layout_id      = "4M",
+               .key            = KEY_PORAY_3,
+       }, {
+               .id             = "R50E",
+               .hw_id          = HWID_PORAY_R50E,
+               .layout_id      = "4M",
+               .key            = KEY_PORAY_4,
+       }, {
+               .id             = "M3",
+               .hw_id          = HWID_PORAY_M3,
+               .layout_id      = "4M",
+               .key            = KEY_PORAY_1,
+       }, {
+               .id             = "M4",
+               .hw_id          = HWID_PORAY_M4,
+               .layout_id      = "4M",
+               .key            = KEY_PORAY_1,
+       }, {
+               .id             = "Q3",
+               .hw_id          = HWID_PORAY_Q3,
+               .layout_id      = "4M",
+               .key            = KEY_PORAY_1,
+       }, {
+               .id             = "X5 or X6",
+               .hw_id          = HWID_PORAY_X5_X6,
+               .layout_id      = "8M",
+               .key            = KEY_PORAY_1,
+       }, {
+               .id             = "X5",
+               .hw_id          = HWID_PORAY_X5_X6,
+               .layout_id      = "8M",
+               .key            = KEY_PORAY_1,
+       }, {
+               .id             = "X6",
+               .hw_id          = HWID_PORAY_X5_X6,
+               .layout_id      = "8M",
+               .key            = KEY_PORAY_1,
+       }, {
+               .id             = "X8",
+               .hw_id          = HWID_PORAY_X8,
+               .layout_id      = "8M",
+               .key            = KEY_PORAY_1,
+       }, {
+               .id             = "X1",
+               .hw_id          = HWID_PORAY_X1,
+               .layout_id      = "8M",
+               .key            = KEY_PORAY_1,
+       }, {
+               .id             = "WT1520",
+               .hw_id          = HWID_NEXX_WT1520,
+               .layout_id      = "4M",
+               .key            = KEY_NEXX_1,
+       }, {
+               .id             = "WT1520",
+               .hw_id          = HWID_NEXX_WT1520,
+               .layout_id      = "8M",
+               .key            = KEY_NEXX_1,
+        }, {
+                .id             = "WT3020",
+                .hw_id          = HWID_NEXX_WT3020,
+                .layout_id      = "4M",
+                .key            = KEY_NEXX_2,
+        }, {
+                .id             = "WT3020",
+                .hw_id          = HWID_NEXX_WT3020,
+                .layout_id      = "8M",
+                .key            = KEY_NEXX_2,
+        }, {
+
+
+
+
+               /* terminating entry */
+       }
+};
+
+/*
+ * Message macros
+ */
+#define ERR(fmt, ...) do { \
+       fflush(0); \
+       fprintf(stderr, "[%s] *** error: " fmt "\n", \
+                       progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERRS(fmt, ...) do { \
+       int save = errno; \
+       fflush(0); \
+       fprintf(stderr, "[%s] *** error: " fmt ":%s\n", \
+                       progname, ## __VA_ARGS__, strerror(save)); \
+} while (0)
+
+#define DBG(fmt, ...) do { \
+       fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
+} while (0)
+
+/*
+ * Find a board by its name
+ */
+static struct board_info *find_board(char *id)
+{
+       struct board_info *ret;
+       struct board_info *board;
+
+       ret = NULL;
+       for (board = boards; board->id != NULL; board++){
+               if (strcasecmp(id, board->id) == 0) {
+                       ret = board;
+                       break;
+               }
+       };
+
+       return ret;
+}
+
+/*
+ * Find a board by its hardware ID
+ */
+static struct board_info *find_board_by_hwid(uint32_t hw_id)
+{
+       struct board_info *board;
+
+       for (board = boards; board->id != NULL; board++) {
+               if (hw_id == board->hw_id)
+                       return board;
+       };
+
+       return NULL;
+}
+
+/*
+ * Find a Flash memory layout by its name
+ */
+static struct flash_layout *find_layout(char *id)
+{
+       struct flash_layout *ret;
+       struct flash_layout *l;
+
+       ret = NULL;
+       for (l = layouts; l->id != NULL; l++){
+               if (strcasecmp(id, l->id) == 0) {
+                       ret = l;
+                       break;
+               }
+       };
+
+       return ret;
+}
+
+/*
+ * Display usage
+ */
+static void usage(int status)
+{
+       FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+
+       fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+       fprintf(stream,
+"\n"
+"Options:\n"
+"  -B <board>      create image for the board specified with <board>\n"
+"  -H <hwid>       use hardware id specified with <hwid>\n"
+"  -F <id>         use flash layout specified with <id>\n"
+"  -f <file>       read firmware image from the file <file>\n"
+"  -o <file>       write output to the file <file>\n"
+"  -i              inspect given firmware file (requires -f)\n"
+"  -x              extract combined kernel and rootfs while inspecting (implies -i)\n"
+"  -h              show this screen\n"
+       );
+
+       exit(status);
+}
+
+/*
+ * Get file statistics
+ */
+static int get_file_stat(struct file_info *fdata)
+{
+       struct stat st;
+       int res;
+
+       if (fdata->file_name == NULL) {
+               return 0;
+       }
+       res = stat(fdata->file_name, &st);
+       if (res){
+               ERRS("stat failed on %s", fdata->file_name);
+               return res;
+       }
+
+       fdata->file_size = st.st_size;
+       return 0;
+}
+
+/*
+ * Read file into buffer
+ */
+static int read_to_buf(struct file_info *fdata, uint8_t *buf)
+{
+       FILE *f;
+       int ret = EXIT_FAILURE;
+
+       f = fopen(fdata->file_name, "rb");
+       if (f == NULL) {
+               ERRS("could not open \"%s\" for reading", fdata->file_name);
+               goto out;
+       }
+
+       errno = 0;
+       fread(buf, fdata->file_size, 1, f);
+       if (errno != 0) {
+               ERRS("unable to read from file \"%s\"", fdata->file_name);
+               goto out_close;
+       }
+
+       ret = EXIT_SUCCESS;
+
+ out_close:
+       fclose(f);
+ out:
+       return ret;
+}
+
+/*
+ * Check command line options
+ */
+static int check_options(void)
+{
+       int ret;
+
+       if (firmware_info.file_name == NULL) {
+               ERR("no firmware image specified");
+               return -1;
+       }
+
+       ret = get_file_stat(&firmware_info);
+       if (ret)
+               return ret;
+
+       if (inspect)
+               return 0;
+
+       if (board_id == NULL && opt_hw_id == NULL) {
+               ERR("either board or hardware id must be specified");
+               return -1;
+       }
+
+       if (board_id) {
+               board = find_board(board_id);
+               if (board == NULL) {
+                       ERR("unknown/unsupported board id \"%s\"", board_id);
+                       return -1;
+               }
+               if (layout_id == NULL) {
+                       layout_id = board->layout_id;
+               }
+               hw_id = board->hw_id;
+       } else {
+               hw_id = strtoul(opt_hw_id, NULL, 0);
+               board = find_board_by_hwid(hw_id);
+               if (layout_id == NULL) {
+                       layout_id = board->layout_id;
+               }
+       }
+
+       layout = find_layout(layout_id);
+       if (layout == NULL) {
+               ERR("unknown flash layout \"%s\"", layout_id);
+               return -1;
+       }
+
+       firmware_len = firmware_info.file_size;
+
+       if (firmware_info.file_size >
+               layout->fw_max_len - sizeof (struct fw_header)) {
+               ERR("firmware image is too big");
+               return -1;
+       }
+
+       if (ofname == NULL) {
+               ERR("no output file specified");
+               return -1;
+       }
+       return 0;
+}
+
+/*
+ * Fill in firmware header
+ */
+static void fill_header(uint8_t *buf)
+{
+       struct fw_header *hdr = (struct fw_header *) buf;
+
+       memset(hdr, 0, sizeof (struct fw_header));
+       hdr->hw_id = HOST_TO_LE32(hw_id);
+       hdr->firmware_len = HOST_TO_LE32(firmware_len);
+       hdr->flags = HOST_TO_LE32(HEADER_FLAGS);
+}
+
+/*
+ * Compute firmware checksum
+ */
+static uint16_t checksum_fw(uint8_t *data, int len)
+{
+       int i;
+       int32_t checksum = 0;
+
+       for (i = 0; i < len - 1; i += 2) {
+               checksum += (data[i + 1] << 8) | data[i];
+       }
+       if (i < len) {
+               checksum += data[i];
+       }
+       checksum = checksum + (checksum >> 16) + 0xffff;
+       checksum = ~(checksum + (checksum >> 16)) & 0xffff;
+       return (uint16_t) checksum;
+}
+
+/*
+ * (De)obfuscate firmware using an XOR operation with a fixed length key
+ */
+static void xor_fw(uint8_t *data, int len)
+{
+       int i;
+
+       for (i = 0; i <= len; i++) {
+               data[i] ^= key[board->key][i % KEY_LEN];
+       }
+}
+
+/*
+ * Write firmware to file
+ */
+static int write_fw(uint8_t *data, int len)
+{
+       FILE *f;
+       int ret = EXIT_FAILURE;
+
+       f = fopen(ofname, "wb");
+       if (f == NULL) {
+               ERRS("could not open \"%s\" for writing", ofname);
+               goto out;
+       }
+
+       errno = 0;
+       fwrite(data, len, 1, f);
+       if (errno) {
+               ERRS("unable to write output file");
+               goto out_flush;
+       }
+
+       DBG("firmware file \"%s\" completed", ofname);
+
+       ret = EXIT_SUCCESS;
+
+ out_flush:
+       fflush(f);
+       fclose(f);
+       if (ret != EXIT_SUCCESS) {
+               unlink(ofname);
+       }
+ out:
+       return ret;
+}
+
+/*
+ * Build firmware file
+ */
+static int build_fw(void)
+{
+       int buflen;
+       uint8_t *buf, *p;
+       int ret = EXIT_FAILURE;
+       int writelen = 0;
+       uint16_t checksum;
+
+       buflen = layout->fw_max_len;
+
+       buf = (uint8_t *) malloc(buflen);
+       if (!buf) {
+               ERR("no memory for buffer\n");
+               goto out;
+       }
+
+       memset(buf, 0xff, buflen);
+       p = buf + sizeof (struct fw_header);
+       ret = read_to_buf(&firmware_info, p);
+       if (ret) {
+               goto out_free_buf;
+       }
+       writelen = sizeof (struct fw_header) + firmware_len + 2;
+
+       /* Fill in header */
+       fill_header(buf);
+
+       /* Compute firmware checksum */
+       checksum = checksum_fw(buf + sizeof (struct fw_header), firmware_len);
+
+       /* Cannot use network order function because checksum is not word-aligned */
+       buf[writelen - 1] = checksum >> 8;
+       buf[writelen - 2] = checksum & 0xff;
+
+       /* XOR obfuscate firmware */
+       xor_fw(buf + sizeof (struct fw_header), firmware_len + 2);
+
+       /* Write firmware file */
+       ret = write_fw(buf, writelen);
+       if (ret) {
+               goto out_free_buf;
+       }
+       ret = EXIT_SUCCESS;
+
+ out_free_buf:
+       free(buf);
+ out:
+       return ret;
+}
+
+/* Helper functions to inspect_fw() representing different output formats */
+static inline void inspect_fw_pstr(char *label, char *str)
+{
+       printf("%-23s: %s\n", label, str);
+}
+
+static inline void inspect_fw_phex(char *label, uint32_t val)
+{
+       printf("%-23s: 0x%08x\n", label, val);
+}
+
+static inline void inspect_fw_phexpost(char *label,
+                                       uint32_t val, char *post)
+{
+       printf("%-23s: 0x%08x (%s)\n", label, val, post);
+}
+
+static inline void inspect_fw_phexdef(char *label,
+                                      uint32_t val, uint32_t defval)
+{
+       printf("%-23s: 0x%08x                  ", label, val);
+
+       if (val == defval) {
+               printf("(== libreCMC default)\n");
+       } else {
+               printf("(libreCMC default: 0x%08x)\n", defval);
+       }
+}
+
+static inline void inspect_fw_phexexp(char *label,
+                                      uint32_t val, uint32_t expval)
+{
+       printf("%-23s: 0x%08x ", label, val);
+
+       if (val == expval) {
+               printf("(ok)\n");
+       } else {
+               printf("(expected: 0x%08x)\n", expval);
+       }
+}
+
+static inline void inspect_fw_phexdec(char *label, uint32_t val)
+{
+       printf("%-23s: 0x%08x / %8u bytes\n", label, val, val);
+}
+
+static inline void inspect_fw_pchecksum(char *label,
+                                       uint16_t val, uint16_t expval)
+{
+       printf("%-23s: 0x%04x     ", label, val);
+       if (val == expval) {
+               printf("(ok)\n");
+       } else {
+               printf("(expected: 0x%04x)\n", expval);
+       }
+}
+
+static int inspect_fw(void)
+{
+       uint8_t *buf;
+       struct fw_header *hdr;
+       int ret = EXIT_FAILURE;
+       uint16_t computed_checksum, file_checksum;
+
+       buf = (uint8_t *) malloc(firmware_info.file_size);
+       if (!buf) {
+               ERR("no memory for buffer!\n");
+               goto out;
+       }
+
+       ret = read_to_buf(&firmware_info, buf);
+       if (ret) {
+               goto out_free_buf;
+       }
+       hdr = (struct fw_header *)buf;
+
+       inspect_fw_pstr("File name", firmware_info.file_name);
+       inspect_fw_phexdec("File size", firmware_info.file_size);
+
+       printf("\n");
+
+       inspect_fw_phexdec("Header size", sizeof (struct fw_header));
+       board = find_board_by_hwid(LE32_TO_HOST(hdr->hw_id));
+       if (board) {
+               layout = find_layout(board->layout_id);
+               inspect_fw_phexpost("Hardware ID",
+                                   LE32_TO_HOST( hdr->hw_id), board->id);
+       } else {
+               inspect_fw_phexpost("Hardware ID",
+                                   LE32_TO_HOST(hdr->hw_id), "unknown");
+       }
+       inspect_fw_phexdec("Firmware data length",
+                          LE32_TO_HOST(hdr->firmware_len));
+
+       inspect_fw_phexexp("Flags",
+                          LE32_TO_HOST(hdr->flags), HEADER_FLAGS);
+       printf("\n");
+
+       /* XOR unobfuscate firmware */
+       xor_fw(buf + sizeof (struct fw_header), LE32_TO_HOST(hdr->firmware_len) + 2);
+
+       /* Compute firmware checksum */
+       computed_checksum = checksum_fw(buf + sizeof (struct fw_header), LE32_TO_HOST(hdr->firmware_len));
+
+       /* Cannot use network order function because checksum is not word-aligned */
+       file_checksum = (buf[firmware_info.file_size - 1] << 8) | buf[firmware_info.file_size - 2];
+       inspect_fw_pchecksum("Firmware checksum", computed_checksum, file_checksum);
+
+       /* Verify checksum */
+       if (computed_checksum != file_checksum) {
+               ret = -1;
+               ERR("checksums do not match");
+               goto out_free_buf;
+       }
+
+       printf("\n");
+
+       if (extract) {
+               FILE *fp;
+               char *filename;
+
+               if (ofname == NULL) {
+                       filename = malloc(strlen(firmware_info.file_name) + 10);
+                       sprintf(filename, "%s-firmware", firmware_info.file_name);
+               } else {
+                       filename = ofname;
+               }
+               printf("Extracting firmware to \"%s\"...\n", filename);
+               fp = fopen(filename, "wb");
+               if (fp) {
+                 if (!fwrite(buf + sizeof (struct fw_header),
+                                   LE32_TO_HOST(hdr->firmware_len), 1, fp)) {
+                               ERRS("error in fwrite(): %s", strerror(errno));
+                       }
+                       fclose(fp);
+               } else {
+                       ERRS("error in fopen(): %s", strerror(errno));
+               }
+               if (ofname == NULL) {
+                       free(filename);
+               }
+               printf("\n");
+       }
+
+ out_free_buf:
+       free(buf);
+ out:
+       return ret;
+}
+
+/*
+ * Main entry point
+ */
+int main(int argc, char *argv[])
+{
+       int ret = EXIT_FAILURE;
+
+       progname = basename(argv[0]);
+
+       int c;
+
+       while ((c = getopt(argc, argv, "B:H:F:f:o:ixh")) != -1) {
+               switch (c) {
+               case 'B':
+                       board_id = optarg;
+                       break;
+               case 'H':
+                       opt_hw_id = optarg;
+                       break;
+               case 'F':
+                       layout_id = optarg;
+                       break;
+               case 'f':
+                       firmware_info.file_name = optarg;
+                       break;
+               case 'o':
+                       ofname = optarg;
+                       break;
+               case 'i':
+                       inspect = 1;
+                       break;
+               case 'x':
+                       inspect = 1;
+                       extract = 1;
+                       break;
+               case 'h':
+                       usage(EXIT_SUCCESS);
+                       break;
+               default:
+                       usage(EXIT_FAILURE);
+                       break;
+               }
+       }
+
+       ret = check_options();
+       if (ret) {
+               goto out;
+       }
+       if (!inspect) {
+               ret = build_fw();
+       } else {
+               ret = inspect_fw();
+       }
+
+ out:
+       return ret;
+}
diff --git a/trunk/tools/firmware-utils/src/mkrtn56uimg.c b/trunk/tools/firmware-utils/src/mkrtn56uimg.c
new file mode 100644 (file)
index 0000000..fe9ae2c
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ *
+ *  Copyright (C) 2014 OpenWrt.org
+ *  Copyright (C) 2014 Mikko Hissa <mikko.hissa@werzek.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ *
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+#include <zlib.h>
+
+#define IH_MAGIC       0x27051956
+#define IH_NMLEN       32
+#define IH_PRODLEN     23
+
+#define IH_TYPE_INVALID                0
+#define IH_TYPE_STANDALONE     1
+#define IH_TYPE_KERNEL         2
+#define IH_TYPE_RAMDISK                3
+#define IH_TYPE_MULTI          4
+#define IH_TYPE_FIRMWARE       5
+#define IH_TYPE_SCRIPT         6
+#define IH_TYPE_FILESYSTEM     7
+
+/*
+ * Compression Types
+ */
+#define IH_COMP_NONE           0
+#define IH_COMP_GZIP           1
+#define IH_COMP_BZIP2          2
+#define IH_COMP_LZMA           3
+
+typedef struct {
+       uint8_t major;
+       uint8_t minor;
+} version_t;
+
+typedef struct {
+       version_t       kernel;
+       version_t       fs;
+       uint8_t         productid[IH_PRODLEN];
+       uint8_t         sub_fs;
+       uint32_t        ih_ksz;
+} asus_t;
+
+typedef struct image_header {
+       uint32_t        ih_magic;
+       uint32_t        ih_hcrc;
+       uint32_t        ih_time;
+       uint32_t        ih_size;
+       uint32_t        ih_load;
+       uint32_t        ih_ep;
+       uint32_t        ih_dcrc;
+       uint8_t         ih_os;
+       uint8_t         ih_arch;
+       uint8_t         ih_type;
+       uint8_t         ih_comp;
+       union {
+               uint8_t ih_name[IH_NMLEN];
+               asus_t  asus;
+       } tail;
+} image_header_t;
+
+typedef struct squashfs_sb {
+       uint32_t        s_magic;
+       uint32_t        pad0[9];
+       uint64_t        bytes_used;
+} squashfs_sb_t;
+
+typedef enum {
+       NONE, FACTORY, SYSUPGRADE,
+} op_mode_t;
+
+void
+calc_crc(image_header_t *hdr, void *data, uint32_t len)
+{
+       /*
+        * Calculate payload checksum
+        */
+       hdr->ih_dcrc = htonl(crc32(0, (Bytef *)data, len));
+       hdr->ih_size = htonl(len);
+       /*
+        * Calculate header checksum
+        */
+       hdr->ih_hcrc = 0;
+       hdr->ih_hcrc = htonl(crc32(0, (Bytef *)hdr, sizeof(image_header_t)));
+}
+
+
+static void
+usage(const char *progname, int status)
+{
+       FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+       int i;
+
+       fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+       fprintf(stream, "\n"
+                       "Options:\n"
+                       "  -f <file>            generate a factory flash image <file>\n"
+                       "  -s <file>            generate a sysupgrade flash image <file>\n"
+                       "  -h                   show this screen\n");
+       exit(status);
+}
+
+int
+process_image(char *progname, char *filename, op_mode_t opmode)
+{
+       int             fd, len;
+       void            *data, *ptr;
+       char            namebuf[IH_NMLEN];
+       struct          stat sbuf;
+       uint32_t        checksum, offset_kernel, offset_sqfs, offset_end,
+                               offset_sec_header, offset_eb, offset_image_end;
+       squashfs_sb_t *sqs;
+       image_header_t *hdr;
+
+       if ((fd = open(filename, O_RDWR, 0666)) < 0) {
+               fprintf (stderr, "%s: Can't open %s: %s\n",
+                       progname, filename, strerror(errno));
+               return (EXIT_FAILURE);
+       }
+
+       if (fstat(fd, &sbuf) < 0) {
+               fprintf (stderr, "%s: Can't stat %s: %s\n",
+                       progname, filename, strerror(errno));
+               return (EXIT_FAILURE);
+       }
+
+       if ((unsigned)sbuf.st_size < sizeof(image_header_t)) {
+               fprintf (stderr,
+                       "%s: Bad size: \"%s\" is no valid image\n",
+                       progname, filename);
+               return (EXIT_FAILURE);
+       }
+
+       ptr = (void *)mmap(0, sbuf.st_size,
+                               PROT_READ | PROT_WRITE,
+                               MAP_SHARED,
+                               fd, 0);
+
+       if ((caddr_t)ptr == (caddr_t)-1) {
+               fprintf (stderr, "%s: Can't read %s: %s\n",
+                       progname, filename, strerror(errno));
+               return (EXIT_FAILURE);
+       }
+
+       hdr = ptr;
+
+       if (ntohl(hdr->ih_magic) != IH_MAGIC) {
+               fprintf (stderr,
+                       "%s: Bad Magic Number: \"%s\" is no valid image\n",
+                       progname, filename);
+               return (EXIT_FAILURE);
+       }
+
+       if (opmode == FACTORY) {
+               strncpy(namebuf, hdr->tail.ih_name, IH_NMLEN);
+               hdr->tail.asus.kernel.major = 0;
+               hdr->tail.asus.kernel.minor = 0;
+               hdr->tail.asus.fs.major = 0;
+               hdr->tail.asus.fs.minor = 0;
+               strncpy((char *)&hdr->tail.asus.productid, "RT-N56U", IH_PRODLEN);
+       }
+
+       if (hdr->tail.asus.ih_ksz == 0)
+               hdr->tail.asus.ih_ksz = htonl(ntohl(hdr->ih_size) + sizeof(image_header_t));
+
+       offset_kernel = sizeof(image_header_t);
+       offset_sqfs = ntohl(hdr->tail.asus.ih_ksz);
+       sqs = ptr + offset_sqfs;
+       offset_sec_header = offset_sqfs + sqs->bytes_used;
+
+       /*
+        * Reserve space for the second header.
+        */
+       offset_end = offset_sec_header + sizeof(image_header_t);
+       offset_eb = ((offset_end>>16)+1)<<16;
+
+       if (opmode == FACTORY)
+               offset_image_end = offset_eb + 4;
+       else
+               offset_image_end = sbuf.st_size;
+       /*
+        * Move the second header at the end of the image.
+        */
+       offset_end = offset_sec_header;
+       offset_sec_header = offset_eb - sizeof(image_header_t);
+
+       /*
+        * Remove jffs2 markers between squashfs and eb boundary.
+        */
+       if (opmode == FACTORY)
+               memset(ptr+offset_end, 0xff ,offset_eb - offset_end);
+
+       /*
+        * Grow the image if needed.
+        */
+       if (offset_image_end > sbuf.st_size) {
+               (void) munmap((void *)ptr, sbuf.st_size);
+               ftruncate(fd, offset_image_end);
+               ptr = (void *)mmap(0, offset_image_end,
+                                               PROT_READ | PROT_WRITE,
+                                               MAP_SHARED,
+                                               fd, 0);
+               /*
+                * jffs2 marker
+                */
+               if (opmode == FACTORY) {
+                       *(uint8_t *)(ptr+offset_image_end-4) = 0xde;
+                       *(uint8_t *)(ptr+offset_image_end-3) = 0xad;
+                       *(uint8_t *)(ptr+offset_image_end-2) = 0xc0;
+                       *(uint8_t *)(ptr+offset_image_end-1) = 0xde;
+               }
+       }
+
+       /*
+        * Calculate checksums for the second header to be used after flashing.
+        */
+       if (opmode == FACTORY) {
+               hdr = ptr+offset_sec_header;
+               memcpy(hdr, ptr, sizeof(image_header_t));
+               strncpy(hdr->tail.ih_name, namebuf, IH_NMLEN);
+               calc_crc(hdr, ptr+offset_kernel, offset_sqfs - offset_kernel);
+               calc_crc((image_header_t *)ptr, ptr+offset_kernel, offset_image_end - offset_kernel);
+       } else {
+               calc_crc((image_header_t *)ptr, ptr+offset_kernel, offset_sqfs - offset_kernel);
+       }
+
+       if (sbuf.st_size > offset_image_end)
+               (void) munmap((void *)ptr, sbuf.st_size);
+       else
+               (void) munmap((void *)ptr, offset_image_end);
+
+       ftruncate(fd, offset_image_end);
+       (void) close (fd);
+
+       return EXIT_SUCCESS;
+}
+
+int
+main(int argc, char **argv)
+{
+       int             opt;
+       char            *filename, *progname;
+       op_mode_t       opmode = NONE;
+
+       progname = argv[0];
+
+       while ((opt = getopt(argc, argv,":s:f:h?")) != -1) {
+               switch (opt) {
+               case 's':
+                       opmode = SYSUPGRADE;
+                       filename = optarg;
+                       break;
+               case 'f':
+                       opmode = FACTORY;
+                       filename = optarg;
+                       break;
+               case 'h':
+                       opmode = NONE;
+               default:
+                       usage(progname, EXIT_FAILURE);
+                       opmode = NONE;
+               }
+       }
+
+       if(filename == NULL)
+               opmode = NONE;
+
+       switch (opmode) {
+       case NONE:
+               usage(progname, EXIT_FAILURE);
+               break;
+       case FACTORY:
+       case SYSUPGRADE:
+               return process_image(progname, filename, opmode);
+               break;
+       }
+
+       return EXIT_SUCCESS;
+}
+
diff --git a/trunk/tools/firmware-utils/src/mksenaofw.c b/trunk/tools/firmware-utils/src/mksenaofw.c
new file mode 100644 (file)
index 0000000..7ea58f5
--- /dev/null
@@ -0,0 +1,417 @@
+/*
+ *
+ *  Copyright (C) 2012 OpenWrt.org
+ *  Copyright (C) 2012 Mikko Hissa <mikko.hissa@uta.fi>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <libgen.h>
+#include <errno.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include "md5.h"
+
+#define HDR_LEN                 0x60
+#define BUF_SIZE                0x200
+#define VERSION_SIZE            0x10
+#define MD5_SIZE                0x10
+#define PAD_SIZE                0x20
+
+#define DEFAULT_BLOCK_SIZE      65535
+
+#define DEFAULT_HEAD_VALUE      0x0
+#define DEFAULT_VERSION         "123"
+#define DEFAULT_MAGIC           0x12345678
+
+typedef struct {
+       uint32_t head;
+       uint32_t vendor_id;
+       uint32_t product_id;
+       uint8_t  version[VERSION_SIZE];
+       uint32_t firmware_type;
+       uint32_t filesize;
+       uint32_t zero;
+       uint8_t  md5sum[MD5_SIZE];
+       uint8_t  pad[PAD_SIZE];
+       uint32_t chksum;
+       uint32_t magic;
+} img_header;
+
+typedef struct {
+       uint8_t id;
+       char * name;
+} firmware_type;
+
+typedef enum {
+       NONE, ENCODE, DECODE
+} op_mode;
+
+static firmware_type FIRMWARE_TYPES[] = {
+       { 0x01, "bootloader" },
+       { 0x02, "kernel" },
+       { 0x03, "kernelapp" },
+       { 0x04, "apps" },
+       /* The types below this line vary by manufacturer */
+       { 0x05, "littleapps (D-Link)/factoryapps (EnGenius)" },
+       { 0x06, "sounds (D-Link)/littleapps (EnGenius)" },
+       { 0x07, "userconfig (D-Link)/appdata (EnGenius)" },
+       { 0x08, "userconfig (EnGenius)"},
+       { 0x09, "odmapps (EnGenius)"},
+       { 0x0a, "factoryapps (D-Link)" },
+       { 0x0b, "odmapps (D-Link)" },
+       { 0x0c, "langpack (D-Link)" }
+};
+
+static long get_file_size(const char *filename)
+{
+       FILE *fp_file;
+       long result;
+
+       fp_file = fopen(filename, "r");
+       if (!fp_file)
+               return -1;
+       fseek(fp_file, 0, SEEK_END);
+       result = ftell(fp_file);
+       fclose(fp_file);
+       return result;
+}
+
+static int header_checksum(void *data, int len)
+{
+       int i;
+       int sum;
+
+       sum = 0;
+       if (data != NULL && len >= 0) {
+               for (i = 0; i < len; ++i)
+                       sum += *(unsigned char *) (data + i);
+               return sum;
+       }
+
+       return -1;
+}
+
+static int md5_file(const char *filename, uint8_t *dst)
+{
+       FILE *fp_src;
+       MD5_CTX ctx;
+       char buf[BUF_SIZE];
+       size_t bytes_read;
+
+       MD5_Init(&ctx);
+
+       fp_src = fopen(filename, "r+b");
+       if (!fp_src) {
+               return -1;
+       }
+       while (!feof(fp_src)) {
+               bytes_read = fread(&buf, 1, BUF_SIZE, fp_src);
+               MD5_Update(&ctx, &buf, bytes_read);
+       }
+       fclose(fp_src);
+
+       MD5_Final(dst, &ctx);
+
+       return 0;
+}
+
+static int encode_image(const char *input_file_name,
+               const char *output_file_name, img_header *header, int block_size)
+{
+       char buf[BUF_SIZE];
+       size_t bytes_read;
+       size_t pad_len = 0;
+       size_t bytes_avail;
+
+       FILE *fp_input;
+       FILE *fp_output;
+
+       int i;
+       long magic;
+
+       fp_input = fopen(input_file_name, "r+b");
+       if (!fp_input) {
+               fprintf(stderr, "Cannot open %s !!\n", input_file_name);
+               return -1;
+       }
+
+       fp_output = fopen(output_file_name, "w+b");
+       if (!fp_output) {
+               fprintf(stderr, "Cannot open %s !!\n", output_file_name);
+               fclose(fp_input);
+               return -1;
+       }
+
+       header->filesize = get_file_size(input_file_name);
+       if (!header->filesize) {
+               fprintf(stderr, "File %s open/size error!\n", input_file_name);
+               fclose(fp_input);
+               fclose(fp_output);
+               return -1;
+       }
+       /*
+        * Zero padding
+        */
+       if (block_size > 0) {
+               pad_len = block_size - (header->filesize % block_size);
+       }
+
+       if (md5_file(input_file_name, (uint8_t *) &header->md5sum) < 0) {
+               fprintf(stderr, "MD5 failed on file %s\n", input_file_name);
+               fclose(fp_input);
+               fclose(fp_output);
+               return -1;
+       }
+       header->zero = 0;
+       header->chksum = header_checksum(header, HDR_LEN);
+       header->head = htonl(header->head);
+       header->vendor_id = htonl(header->vendor_id);
+       header->product_id = htonl(header->product_id);
+       header->firmware_type = htonl(header->firmware_type);
+       header->filesize = htonl(header->filesize);
+       header->chksum = htonl(header->chksum);
+       magic = header->magic;
+       header->magic = htonl(header->magic);
+
+       fwrite(header, HDR_LEN, 1, fp_output);
+
+       while (!feof(fp_input) || pad_len > 0) {
+
+               if (!feof(fp_input))
+                       bytes_read = fread(&buf, 1, BUF_SIZE, fp_input);
+               else
+                       bytes_read = 0;
+
+               /*
+                * No more bytes read, start padding
+                */
+               if (bytes_read < BUF_SIZE && pad_len > 0) {
+                       bytes_avail = BUF_SIZE - bytes_read;
+                       memset( &buf[bytes_read], 0, bytes_avail);
+                       bytes_read += bytes_avail < pad_len ? bytes_avail : pad_len;
+                       pad_len -= bytes_avail < pad_len ? bytes_avail : pad_len;
+               }
+
+               for (i = 0; i < bytes_read; i++)
+                       buf[i] ^= magic >> (i % 8) & 0xff;
+               fwrite(&buf, bytes_read, 1, fp_output);
+       }
+
+       fclose(fp_input);
+       fclose(fp_output);
+       return 1;
+}
+
+int decode_image(const char *input_file_name, const char *output_file_name)
+{
+       img_header header;
+       char buf[BUF_SIZE];
+
+       FILE *fp_input;
+       FILE *fp_output;
+       unsigned int i;
+
+       size_t bytes_read;
+       size_t bytes_written;
+
+       fp_input = fopen(input_file_name, "r+b");
+       if (!fp_input) {
+               fprintf(stderr, "Cannot open %s !!\n", input_file_name);
+               fclose(fp_input);
+               return -1;
+       }
+
+       fp_output = fopen(output_file_name, "w+b");
+       if (!fp_output) {
+               fprintf(stderr, "Cannot open %s !!\n", output_file_name);
+               fclose(fp_output);
+               return -1;
+       }
+
+       if (fread(&header, 1, HDR_LEN, fp_input) != HDR_LEN) {
+               fprintf(stderr, "Incorrect header size!!");
+               fclose(fp_input);
+               fclose(fp_output);
+               return -1;
+       }
+
+       header.head = ntohl(header.head);
+       header.vendor_id = ntohl(header.vendor_id);
+       header.product_id = ntohl(header.product_id);
+       header.firmware_type = ntohl(header.firmware_type);
+       header.filesize = ntohl(header.filesize);
+       header.chksum = ntohl(header.chksum);
+       header.magic = ntohl(header.magic);
+
+       bytes_written = 0;
+       while (!feof(fp_input)) {
+
+               bytes_read = fread(&buf, 1, BUF_SIZE, fp_input);
+               for (i = 0; i < bytes_read; i++)
+                       buf[i] ^= header.magic >> (i % 8) & 0xff;
+
+               /*
+                * Handle padded source file
+                */
+               if (bytes_written + bytes_read > header.filesize) {
+                       bytes_read = header.filesize - bytes_written;
+                       if (bytes_read > 0)
+                               fwrite(&buf, bytes_read, 1, fp_output);
+                       break;
+               }
+
+               fwrite(&buf, bytes_read, 1, fp_output);
+               bytes_written += bytes_read;
+       }
+
+       fclose(fp_input);
+       fclose(fp_output);
+
+       return 1;
+}
+
+static void usage(const char *progname, int status)
+{
+       FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+       int i;
+
+       fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+       fprintf(stream, "\n"
+                       "Options:\n"
+                       "  -e <file>            encode image file <file>\n"
+                       "  -d <file>            decode image file <file>\n"
+                       "  -o <file>            write output to the file <file>\n"
+                       "  -t <type>            set image type to <type>\n"
+                       "                       valid image <type> values:\n");
+       for (i = 0; i < sizeof(FIRMWARE_TYPES) / sizeof(firmware_type); i++) {
+               fprintf(stream, "                       %-5i= %s\n", FIRMWARE_TYPES[i].id,
+                               FIRMWARE_TYPES[i].name);
+       }
+       fprintf(stream, "  -v <version>         set image version to <version>\n"
+                       "  -r <vendor>          set image vendor id to <vendor>\n"
+                       "  -p <product>         set image product id to <product>\n"
+                       "  -m <magic>           set encoding magic <magic>\n"
+                       "  -z                   enable image padding to <blocksize>\n"
+                       "  -b <blocksize>       set image <blocksize>, defaults to %u\n"
+                       "  -h                   show this screen\n", DEFAULT_BLOCK_SIZE);
+       exit(status);
+}
+
+int main(int argc, char *argv[])
+{
+       int opt;
+       char *input_file, *output_file, *progname = NULL;
+       op_mode mode = NONE;
+       int tmp, i, pad = 0;
+       int block_size;
+       img_header header;
+
+       block_size = DEFAULT_BLOCK_SIZE;
+       progname = basename(argv[0]);
+
+       memset(&header, 0, sizeof( img_header ));
+       header.magic = DEFAULT_MAGIC;
+       header.head = DEFAULT_HEAD_VALUE;
+       strncpy( (char*)&header.version, DEFAULT_VERSION, VERSION_SIZE - 1);
+
+       while ((opt = getopt(argc, argv, ":o:e:d:t:v:r:p:m:b:h?z")) != -1) {
+               switch (opt) {
+               case 'e':
+                       input_file = optarg;
+                       mode = ENCODE;
+                       break;
+               case 'd':
+                       input_file = optarg;
+                       mode = DECODE;
+                       break;
+               case 'o':
+                       output_file = optarg;
+                       break;
+               case 't':
+                       tmp = strtol(optarg, 0, 10);
+                       for (i = 0; i < sizeof(FIRMWARE_TYPES) / sizeof(firmware_type);
+                                       i++) {
+                               if (FIRMWARE_TYPES[i].id == tmp) {
+                                       header.firmware_type = FIRMWARE_TYPES[i].id;
+                                       break;
+                               }
+                       }
+                       if (header.firmware_type == 0) {
+                               fprintf(stderr, "Invalid firmware type \"0\"!\n");
+                               usage(progname, EXIT_FAILURE);
+                       }
+                       break;
+               case 'v':
+                       strncpy( (char*)&header.version, optarg,
+                                       VERSION_SIZE - 1);
+                       break;
+               case 'r':
+                       header.vendor_id = strtol(optarg, 0, 0);
+                       break;
+               case 'p':
+                       header.product_id = strtol(optarg, 0, 0);
+                       break;
+               case 'm':
+                       header.magic = strtoul(optarg, 0, 16);
+                       break;
+               case 'z':
+                       pad = 1;
+                       break;
+               case 'b':
+                       block_size = strtol(optarg, 0, 10);
+                       break;
+               case 'h':
+                       usage(progname, EXIT_SUCCESS);
+                       break;
+               case ':':
+                       fprintf(stderr, "Option -%c requires an operand\n", optopt);
+                       usage(progname, EXIT_FAILURE);
+                       break;
+               case '?':
+                       fprintf(stderr, "Unrecognized option: -%c\n", optopt);
+                       usage(progname, EXIT_FAILURE);
+                       break;
+               default:
+                       usage(progname, EXIT_FAILURE);
+                       break;
+               }
+       }
+
+       /* Check required arguments*/
+       if (header.firmware_type == 0) {
+               fprintf(stderr, "Firmware type must be defined\n");
+               usage(progname, EXIT_FAILURE);
+       } else if (input_file == 0 || output_file == 0) {
+               fprintf(stderr, "Input and output files must be defined\n");
+               usage(progname, EXIT_FAILURE);
+       } else if (header.vendor_id == 0 || header.product_id == 0) {
+               fprintf(stderr, "Vendor ID and Product ID must be defined and non-zero\n");
+               usage(progname, EXIT_FAILURE);
+       }
+
+       switch (mode) {
+       case NONE:
+               fprintf(stderr, "A mode must be defined\n");
+               usage(progname, EXIT_FAILURE);
+               break;
+       case ENCODE:
+               if (encode_image(input_file, output_file, &header, pad ? block_size : 0)
+                               < 0)
+                       return EXIT_FAILURE;
+               break;
+       case DECODE:
+               if (decode_image(input_file, output_file) < 0)
+                       return EXIT_FAILURE;
+               break;
+       }
+
+       return EXIT_SUCCESS;
+}
diff --git a/trunk/tools/firmware-utils/src/mktitanimg.c b/trunk/tools/firmware-utils/src/mktitanimg.c
new file mode 100644 (file)
index 0000000..cca4a0e
--- /dev/null
@@ -0,0 +1,1040 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libgen.h>
+#include "mktitanimg.h"
+
+
+struct checksumrecord
+{
+               unsigned int magic;
+        unsigned int    chksum;     /* The checksum for the complete header.
+ Excepting the
+                                           checksum block */
+};
+/***************************************************************************
+ * void print_help(void)
+ ***************************************************************************/
+void print_help(void)
+{
+       static char* help_page[]=
+       {
+               "mknspimg version 1.0, Texas Instruments, 2004",
+               "Syntax:",
+               "        mknspimg -o outfile -i image1 image2 -a align1 align2 [-v] [-b] [-p prod_id] [-r rel_id] [-s rel_name] [-f flags]",
+               "Example:",
+               "        mknspimg -o nsp_image.bin -i kernel.bin files.img -a 0 4096",
+               "This generates 'nsp_image.bin' from two input files aligning first to 0 and second to 4096 bytes."
+       };
+
+       int num_lines = sizeof(help_page)/sizeof(char*);
+       int i;
+       for(i=0; i < num_lines; i++) {
+               printf("%s\n", help_page[i]);
+       }
+}
+
+/***************************************************************************
+ * void mknspimg_print_hdr(NSP_IMG_HDR* p_img_hdr)
+ ***************************************************************************/
+void mknspimg_print_hdr(struct nsp_img_hdr *hdr)
+{
+       struct nsp_img_hdr_chksum       *chksum;
+       struct nsp_img_hdr_section_info *sect_info;
+       struct nsp_img_hdr_sections     *section;
+       int i;
+
+       printf("****************** NSP Image Summary ******************\n");
+       printf("Magic:             0x%x\n",             hdr->head.magic);
+       printf("Image Header Size: 0x%x bytes\n",       hdr->head.hdr_size);
+       printf("Total Image Size:  %d bytes\n",         hdr->head.image_size);
+       printf("Product ID:        0x%x\n",             hdr->head.prod_id);
+       printf("Release ID:        0x%x\n",             hdr->head.rel_id);
+       printf("Version ID:        0x%x\n",             hdr->head.version);
+
+       printf("Offset Info:       0x%x\n",             hdr->head.info_offset);
+       printf("Offset Sect info:  0x%x\n",             hdr->head.sect_info_offset);
+       printf("Offset Sections:   0x%x\n",             hdr->sect_info.sections_offset);
+
+       chksum=(struct nsp_img_hdr_chksum *)(hdr+hdr->head.chksum_offset);
+       printf("Header Checksum:   0x%x\n",             chksum->hdr_chksum);
+
+       printf("+++ Section Information +++\n");
+       printf("# of sections:     %u\n", hdr->sect_info.num_sects);
+       section=&(hdr->sections);
+       for(i = 0; i < hdr->sect_info.num_sects; i++, section++) {
+               printf("+++++ Section %d +++++\n", i);
+               printf("Total size:  %u bytes\n",       section->total_size);
+               printf("Raw Size:    %u bytes\n",       section->raw_size);
+               printf("Offset:      0x%x\n",           section->offset);
+               printf("Type:        0x%x\n",           section->type);
+               printf("Name:        %s\n",             section->name);
+       }
+       printf("*******************************************************\n");
+}
+
+CMDLINE_CFG    cmd_line_cfg =
+{
+       {
+               /*      MIN     MAX     FLAGS                                   OPTION  */
+               {       2,      2,      (CMDLINE_OPTFLAG_ALLOW | CMDLINE_OPTFLAG_MANDAT) },     /* '-a' align1 align2 */
+               {       0,      0,      CMDLINE_OPTFLAG_ALLOW },                /* '-b' bootstrap */
+               {       0,      0,      !CMDLINE_OPTFLAG_ALLOW },               /* '-c' */
+               {       0,      0,      !CMDLINE_OPTFLAG_ALLOW },               /* '-d' */
+               {       0,      0,      !CMDLINE_OPTFLAG_ALLOW },               /* '-e' */
+               {       1,      1,      CMDLINE_OPTFLAG_ALLOW },                /* '-f' flags */
+               {       0,      0,      !CMDLINE_OPTFLAG_ALLOW },               /* '-g' */
+               {       1,      1,      CMDLINE_OPTFLAG_ALLOW },                /* '-h' */
+               {       2,      2,      (CMDLINE_OPTFLAG_ALLOW | CMDLINE_OPTFLAG_MANDAT) },     /* '-i arg1 arg2 ' */
+               {       0,      0,      !CMDLINE_OPTFLAG_ALLOW },               /* '-j' */
+               {       0,      0,      !CMDLINE_OPTFLAG_ALLOW },               /* '-k' */
+               {       0,      0,      !CMDLINE_OPTFLAG_ALLOW },               /* '-l' */
+               {       0,      0,      !CMDLINE_OPTFLAG_ALLOW },               /* '-m' */
+               {       0,      0,      !CMDLINE_OPTFLAG_ALLOW },               /* '-n' */
+               {       1,      1,      (CMDLINE_OPTFLAG_ALLOW | CMDLINE_OPTFLAG_MANDAT) },     /* '-o arg' */
+               {       1,      1,      CMDLINE_OPTFLAG_ALLOW },                /* '-p' PROD_ID */
+               {       0,      0,      !CMDLINE_OPTFLAG_ALLOW },               /* '-q' */
+               {       1,      1,      CMDLINE_OPTFLAG_ALLOW },                /* '-r' REL_ID */
+               {       1,      1,      CMDLINE_OPTFLAG_ALLOW },                /* '-s' "Release XXX.XXX" */
+               {       0,      0,      !CMDLINE_OPTFLAG_ALLOW },               /* '-t' */
+               {       0,      0,      !CMDLINE_OPTFLAG_ALLOW },               /* '-u' */
+               {       0,      0,      CMDLINE_OPTFLAG_ALLOW },                /* '-v' control VERBOSE/NON-VERBOSE mode */
+               {       0,      0,      !CMDLINE_OPTFLAG_ALLOW },               /* '-w' */
+               {       0,      0,      !CMDLINE_OPTFLAG_ALLOW },               /* '-x' */
+               {       0,      0,      !CMDLINE_OPTFLAG_ALLOW },               /* '-y' */
+               {       0,      0,      !CMDLINE_OPTFLAG_ALLOW }                /* '-z' */
+       },
+       {       0,              0,      !CMDLINE_OPTFLAG_ALLOW },               /* global arguments */
+};
+
+/***************************************************************************
+ * int nsp_img_write(void* image, char* file, int padding)
+ * Write out the image.
+ ***************************************************************************/
+int main(int argc, char* argv[], char* env[])
+{
+       FILE*   nsp_image       = NULL;
+       int header_version=1;
+       int     cmdline_err;
+       char*   cmdline_error_msg;
+
+       char*   filen_kernel;
+       char*   filen_files;
+       char*   filen_out;
+
+       int     i,count;                        /* loop variables */
+       int     num_sects = 2;                  /* We require exactly two image with -i option
+                                                          (see CMDLINE_CFG structure above) */
+       int     desc_count=0;
+       int     total = 0;
+
+       int     header_size=0;
+       struct nsp_img_hdr_head         *img_hdr_head;  /* Start of image header */
+       struct nsp_img_hdr_info *img_hdr_info;
+       struct nsp_img_hdr_section_info *img_hdr_section_info ;
+       struct nsp_img_hdr_sections     *img_hdr_sections, *section;    /* Section pointers */
+       
+
+       /* Configure the command line. */
+       cmdline_configure(&cmd_line_cfg);
+
+       /* Read and parse the command line. */
+       cmdline_err = cmdline_read(argc, argv);
+
+       /* Check for parsing errors. */
+       if(cmdline_err != 0) {
+               /* Get the parse error message */
+               cmdline_error_msg = cmdline_error(cmdline_err);
+
+               /* Print it out */
+               printf("%s\n", cmdline_error_msg);
+
+               /* Print our help too */
+               print_help();
+               return -1;
+       }
+       if(cmdline_getopt_count('h') > 0)
+       {
+               header_version=atoi(argv[cmdline_getarg(cmdline_getarg_list('h'),0)]);
+       }
+       /* Set up arguments */
+       filen_kernel    = argv[cmdline_getarg(cmdline_getarg_list('i'),0)];
+       filen_files     = argv[cmdline_getarg(cmdline_getarg_list('i'),1)];
+       filen_out       = argv[cmdline_getarg(cmdline_getarg_list('o'),0)];
+       /* Command line arguments have been parsed. Start doing our work. */
+
+       /* Caculate the header size, and allocate the memory, and assign the sub pointers */
+       header_size =   sizeof(struct nsp_img_hdr_head) +               /* This has a single section
+                                                                  desc block already */
+                               (header_version==1?0:4) + 
+                               sizeof(struct nsp_img_hdr_info) + 
+                               sizeof(struct nsp_img_hdr_section_info) + 
+                       sizeof(struct nsp_img_hdr_sections) * num_sects ;
+
+       img_hdr_head = (struct nsp_img_hdr_head *)malloc(header_size);
+       memset(img_hdr_head, 0x0, header_size);
+       img_hdr_info = (struct nsp_img_hdr_info*)((char *)img_hdr_head + sizeof(struct nsp_img_hdr_head) + (header_version==1?0:4));
+       img_hdr_section_info = (struct nsp_img_hdr_section_info*)((char *)img_hdr_info + sizeof(struct nsp_img_hdr_info));
+       img_hdr_sections = (struct nsp_img_hdr_sections*)((char *)img_hdr_section_info + sizeof(struct nsp_img_hdr_section_info));
+       section = img_hdr_sections;
+       memset(img_hdr_head, 0xff, (void*)img_hdr_info - (void*)img_hdr_head);
+       
+       img_hdr_head->hdr_version = header_version;
+       img_hdr_head->hdr_size = header_size;
+       img_hdr_head->info_offset = (void*)img_hdr_info - (void*)img_hdr_head;
+       img_hdr_head->sect_info_offset = (void*)img_hdr_section_info - (void*)img_hdr_head;
+       
+       img_hdr_section_info->num_sects = num_sects;
+       img_hdr_section_info->sect_size = sizeof(struct nsp_img_hdr_sections);
+       img_hdr_section_info->sections_offset = (void*)img_hdr_sections - (void*)img_hdr_head;
+       
+/*     chksum = (struct nsp_img_hdr_chksum *)
+                       ((unsigned int)image_hdr + header_size - sizeof(struct nsp_img_hdr_chksum));*/
+
+       /* Open the out file */
+       nsp_image = fopen(filen_out,"wb+");
+       if(nsp_image==NULL) {
+               printf("ERROR: can't open %s for writing.\n", filen_out);
+               return -1;
+       }
+
+       /* Skip image header. We'll come back to it after we've written out the images. */      
+       fseek(nsp_image,header_size,SEEK_SET);
+       total = ftell(nsp_image);
+       total = header_size;
+       printf("total=%x\n",total);
+       {
+               int align;
+               int     padding;
+               char * buf;
+               align = (header_version==1?0x10000:0x4000);
+               if(align==0) {
+                       /* The user indicated no padding */
+                       padding = 0;
+               } else {
+                       /* Calculate number padding bytes */
+                       if((total %align) ==0)
+                               padding=0;
+                       else
+                               padding = align - (total % align);
+               }
+               if(padding>0)
+               {
+                       buf=malloc(padding);
+                       memset(buf, 0xff, padding);
+                       if(fwrite((void*)buf,1,padding,nsp_image)!=padding) {
+                               printf("ERROR: can't write to %s.\n", filen_out);
+                               free(buf);
+                               return -1;
+                       }
+                       free(buf);
+                       
+               }
+               total+=padding;
+               
+
+       }
+       /* Write out all specified images (with -i option) */
+       for(i=0; i < num_sects; i++) {
+               char*   file_name;              /* input file name */
+               FILE*   filep;                  /* input file pointer */
+               int     padding;                /* number of padding bytes to prepend */
+               int     align;                  /* align factor from command line */
+               int     result;                 /* intermediate result */
+               char * buf;
+
+               /* Open the specified image for reading */
+               file_name       = argv[cmdline_getarg(cmdline_getarg_list('i'),i)];
+               filep           = fopen(file_name, "rb");
+               if(filep==NULL) {
+                       printf("ERROR: can't open file %s for reading.\n", file_name);
+                       return -1;
+               }
+               section->flags = ~0x00;
+               /* Determine file size */
+               fseek(filep,0,SEEK_END);
+               section->raw_size=ftell(filep);
+               fseek(filep,0,SEEK_SET);
+               cs_calc_sum(filep,(unsigned long *)&section->chksum,0);
+               fseek(filep,0,SEEK_SET);
+
+               /* Retrieve the alignment constant */
+               /* Set image offset from the beginning of the out file */
+               section->offset=total;// + padding;
+
+               //total += padding;
+
+               /* Copy the image file into nsp_image */
+               count = section->raw_size;
+               buf=malloc(count);
+               result=fread(buf, 1, count, filep);
+               fwrite(buf, 1, result, nsp_image);
+               free(buf);
+               
+               /* HACK: This is a hack to get the names and types to the files.
+                       TODO: Fix this to be a real method */
+               if(i==0){
+                       section->type=NSP_IMG_SECTION_TYPE_KERNEL;
+                       strncpy(section->name, "kernel", 16);
+               } else if(i==1){
+                       section->type=NSP_IMG_SECTION_TYPE_FILESYSTEM_ROOT;
+                       strncpy(section->name, "root", 16);
+               }
+
+               /* Account for the total */
+               align   =  strtoul(argv[cmdline_getarg(cmdline_getarg_list('a'),i)],NULL,0);
+               if(i==0){
+                       if(align==0 || (((section->raw_size+ section->offset)%align)==0))
+                               padding=0;
+                       else
+                               padding = align - ((section->raw_size+ section->offset) % align);
+
+                               section->total_size=section->raw_size + padding;
+               }
+               else{
+                       #define EXTRA_BLOCK 0x10000
+                       unsigned int squash_padding;
+                       squash_padding = EXTRA_BLOCK - section->raw_size % EXTRA_BLOCK;
+                       buf=malloc(EXTRA_BLOCK + 4);
+                       memset(buf, 0, squash_padding);
+                       fwrite(buf, 1, squash_padding, nsp_image);
+                       memset(buf, 0, EXTRA_BLOCK + 4);
+                       *((unsigned int *)buf)=0xdec0adde;
+                       *((unsigned int *)(buf+EXTRA_BLOCK))=0xdec0adde;
+                       fwrite(buf, 1, EXTRA_BLOCK+4, nsp_image);
+                       free(buf);
+                       
+                       if(align==0 || (((section->raw_size + (EXTRA_BLOCK + 4 + squash_padding)) %align)==0))
+                               padding=0;
+                       else
+                               padding = align - ((section->raw_size + (EXTRA_BLOCK + 4 + squash_padding)) % align);
+                       section->total_size=section->raw_size + (EXTRA_BLOCK + 4 + squash_padding) + padding;
+               }
+               if(padding>0){
+                       buf=malloc(padding);
+                       memset(buf, 0xff, padding);
+                       fwrite(buf, 1, padding, nsp_image);
+                       free(buf);
+               }
+               printf("*****padding is %d\ttotal_size=%d\traw_size=%d\n",padding, section->total_size, section->raw_size);
+
+               //total += section->raw_size;
+               total = section->total_size + section->offset;
+               printf("total=0x%x\n",total);
+               /* Close the input file */
+               fclose(filep);
+
+               /* Move the section pointer to the next slot */
+               section++;
+       }
+
+       /* Take care of the NSP image header fields */
+
+       /* head fields */
+       img_hdr_head->magic             = NSP_IMG_MAGIC_NUMBER;
+       img_hdr_head->boot_offset       = img_hdr_sections->offset;
+       img_hdr_head->flags             = ~0x00;                        /* Set to all 1's */
+
+       if(cmdline_getopt_count('b'))
+               img_hdr_head->flags     &= ~(NSP_IMG_FLAG_FAILBACK_5 | NSP_IMG_FLAG_FAILBACK_1);
+
+       if(cmdline_getopt_count('f'))
+               img_hdr_head->flags     = strtoul(argv[cmdline_getarg(cmdline_getarg_list('f'),0)], 0, 16);
+
+#if 0
+       img_hdr_head->hdr_version       = 2;
+       img_hdr_head->hdr_size  = header_size;
+#endif
+
+       if(cmdline_getopt_count('p'))
+               img_hdr_head->prod_id           = strtoul(argv[cmdline_getarg(cmdline_getarg_list('p'),0)], 0, 16);
+       else
+               img_hdr_head->prod_id           = 0x4C575943;
+
+       if(cmdline_getopt_count('r'))
+               img_hdr_head->rel_id            = strtoul(argv[cmdline_getarg(cmdline_getarg_list('r'),0)], 0, 0);
+       else
+               img_hdr_head->rel_id            = 0x10203040;
+
+       if(cmdline_getopt_count('s'))
+               img_hdr_head->version           = strtoul(argv[cmdline_getarg(cmdline_getarg_list('s'),0)], 0, 0);
+       else
+               img_hdr_head->version           = 0x0b040000;
+       img_hdr_head->image_size        = total;
+#if 0
+       img_hdr_head->info_offset       = (unsigned int)(&(image_hdr->info)) -
+                                               (unsigned int)image_hdr;
+       img_hdr_head->sect_info_offset= (unsigned int)(&(image_hdr->sect_info)) -
+                                               (unsigned int)image_hdr;
+#endif
+//     image_hdr->head.chksum_offset   = (unsigned int)chksum - (unsigned int)image_hdr;
+       img_hdr_head->chksum_offset = 0xffffffff;
+//     image_hdr->head.pad1 = 0xffffffff;
+       /* info fields */
+       /* TODO: Fix. Do nothing yet */
+//     strncpy(nsp_img_hdr.id.prod_info,NSP_PRODINFO_STRING,sizeof(NSP_PRODINFO_STRING));
+       strcpy(img_hdr_info->image_filename, (const char *)basename(filen_out));
+       /* section fields */
+#if 0
+       img_hdr_section_info->num_sects=                num_sects;
+       img_hdr_section_info->sect_size=                sizeof(struct nsp_img_hdr_sections);
+       img_hdr_section_info->sections_offset=  (unsigned int)(&(image_hdr->sections)) -
+                                               (unsigned int)image_hdr;
+#endif
+
+       /* Calculate checksum(s) */
+#if 0
+       chksum->hdr_chksum = cs_calc_buf_sum((char*)image_hdr,
+                       header_size - sizeof(struct nsp_img_hdr_chksum));
+#endif
+       /* Write out the NSP header. */
+       fseek(nsp_image,0,SEEK_SET);
+       count = fwrite((void*)img_hdr_head, header_size, 1, nsp_image);
+       if(count!=1) {
+               printf("ERROR: can't write to %s.\n", filen_out);
+               return -1;
+       }
+
+       /* Check if -v option was specified (no arg needed) */
+       if(cmdline_getopt_count('v') > 0)
+       {
+               struct nsp_img_hdr_head head;
+               struct nsp_img_hdr      *hdr;
+
+               /* Rewind the file back to the beginning */
+               fseek(nsp_image,0,SEEK_SET);
+
+               /* Read header from the file */
+               fread((void*)&head, sizeof(struct nsp_img_hdr_head),
+                               1, nsp_image);
+
+               /* Get memory to store the complete header */
+               hdr = (struct nsp_img_hdr *)malloc(head.hdr_size);
+
+               /* Read header from the file */
+               fseek(nsp_image,0,SEEK_SET);
+               fread((void*)hdr, head.hdr_size, 1, nsp_image);
+
+               /* Print it out */
+               mknspimg_print_hdr(hdr);
+               printf("Generated total %d bytes\n",total);
+               free(hdr);
+       }
+
+       free(img_hdr_head);
+
+      {
+         struct checksumrecord cr;
+      cr.magic=CKSUM_MAGIC_NUMBER;
+      cs_calc_sum(nsp_image, (unsigned long *)&cr.chksum, 0);
+      fseek(nsp_image,0, SEEK_END);
+      fwrite(&cr, 1, sizeof(cr), nsp_image);
+         }
+         {
+               FILE * non_web;
+               char fname[256];
+               char * img_buf;
+               unsigned int len;
+               strcpy(fname, filen_out);
+               strcat(fname, ".non_web");
+               non_web = fopen(fname,"wb+");
+               fseek(nsp_image, 0, SEEK_END);
+               len = ftell(nsp_image);
+               img_buf=malloc(len);
+               fseek(nsp_image, 0, SEEK_SET);
+               fread(img_buf, 1, len, nsp_image);
+               img_buf[0xb] = 0x17;
+               fwrite(img_buf, 1, len-sizeof(struct checksumrecord), non_web);
+               fclose(non_web);
+               free(img_buf);
+         }
+         /* Close NSP image file */
+       fclose(nsp_image);
+
+       /* return result */
+       return(0);
+}
+
+#ifdef DMALLOC
+#include <dmalloc.h>
+#endif /* DMALLOC */
+
+#define BUFLEN (1 << 16)
+
+static unsigned long crctab[256] =
+{
+       0x0,
+       0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B,
+       0x1A864DB2, 0x1E475005, 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6,
+       0x2B4BCB61, 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD,
+       0x4C11DB70, 0x48D0C6C7, 0x4593E01E, 0x4152FDA9, 0x5F15ADAC,
+       0x5BD4B01B, 0x569796C2, 0x52568B75, 0x6A1936C8, 0x6ED82B7F,
+       0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3, 0x709F7B7A,
+       0x745E66CD, 0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039,
+       0x8B27C03C, 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5, 0xBE2B5B58,
+       0xBAEA46EF, 0xB7A96036, 0xB3687D81, 0xAD2F2D84, 0xA9EE3033,
+       0xA4AD16EA, 0xA06C0B5D, 0xD4326D90, 0xD0F37027, 0xDDB056FE,
+       0xD9714B49, 0xC7361B4C, 0xC3F706FB, 0xCEB42022, 0xCA753D95,
+       0xF23A8028, 0xF6FB9D9F, 0xFBB8BB46, 0xFF79A6F1, 0xE13EF6F4,
+       0xE5FFEB43, 0xE8BCCD9A, 0xEC7DD02D, 0x34867077, 0x30476DC0,
+       0x3D044B19, 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5,
+       0x2AC12072, 0x128E9DCF, 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16,
+       0x018AEB13, 0x054BF6A4, 0x0808D07D, 0x0CC9CDCA, 0x7897AB07,
+       0x7C56B6B0, 0x71159069, 0x75D48DDE, 0x6B93DDDB, 0x6F52C06C,
+       0x6211E6B5, 0x66D0FB02, 0x5E9F46BF, 0x5A5E5B08, 0x571D7DD1,
+       0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA,
+       0xACA5C697, 0xA864DB20, 0xA527FDF9, 0xA1E6E04E, 0xBFA1B04B,
+       0xBB60ADFC, 0xB6238B25, 0xB2E29692, 0x8AAD2B2F, 0x8E6C3698,
+       0x832F1041, 0x87EE0DF6, 0x99A95DF3, 0x9D684044, 0x902B669D,
+       0x94EA7B2A, 0xE0B41DE7, 0xE4750050, 0xE9362689, 0xEDF73B3E,
+       0xF3B06B3B, 0xF771768C, 0xFA325055, 0xFEF34DE2, 0xC6BCF05F,
+       0xC27DEDE8, 0xCF3ECB31, 0xCBFFD686, 0xD5B88683, 0xD1799B34,
+       0xDC3ABDED, 0xD8FBA05A, 0x690CE0EE, 0x6DCDFD59, 0x608EDB80,
+       0x644FC637, 0x7A089632, 0x7EC98B85, 0x738AAD5C, 0x774BB0EB,
+       0x4F040D56, 0x4BC510E1, 0x46863638, 0x42472B8F, 0x5C007B8A,
+       0x58C1663D, 0x558240E4, 0x51435D53, 0x251D3B9E, 0x21DC2629,
+       0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5, 0x3F9B762C,
+       0x3B5A6B9B, 0x0315D626, 0x07D4CB91, 0x0A97ED48, 0x0E56F0FF,
+       0x1011A0FA, 0x14D0BD4D, 0x19939B94, 0x1D528623, 0xF12F560E,
+       0xF5EE4BB9, 0xF8AD6D60, 0xFC6C70D7, 0xE22B20D2, 0xE6EA3D65,
+       0xEBA91BBC, 0xEF68060B, 0xD727BBB6, 0xD3E6A601, 0xDEA580D8,
+       0xDA649D6F, 0xC423CD6A, 0xC0E2D0DD, 0xCDA1F604, 0xC960EBB3,
+       0xBD3E8D7E, 0xB9FF90C9, 0xB4BCB610, 0xB07DABA7, 0xAE3AFBA2,
+       0xAAFBE615, 0xA7B8C0CC, 0xA379DD7B, 0x9B3660C6, 0x9FF77D71,
+       0x92B45BA8, 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74,
+       0x857130C3, 0x5D8A9099, 0x594B8D2E, 0x5408ABF7, 0x50C9B640,
+       0x4E8EE645, 0x4A4FFBF2, 0x470CDD2B, 0x43CDC09C, 0x7B827D21,
+       0x7F436096, 0x7200464F, 0x76C15BF8, 0x68860BFD, 0x6C47164A,
+       0x61043093, 0x65C52D24, 0x119B4BE9, 0x155A565E, 0x18197087,
+       0x1CD86D30, 0x029F3D35, 0x065E2082, 0x0B1D065B, 0x0FDC1BEC,
+       0x3793A651, 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D,
+       0x2056CD3A, 0x2D15EBE3, 0x29D4F654, 0xC5A92679, 0xC1683BCE,
+       0xCC2B1D17, 0xC8EA00A0, 0xD6AD50A5, 0xD26C4D12, 0xDF2F6BCB,
+       0xDBEE767C, 0xE3A1CBC1, 0xE760D676, 0xEA23F0AF, 0xEEE2ED18,
+       0xF0A5BD1D, 0xF464A0AA, 0xF9278673, 0xFDE69BC4, 0x89B8FD09,
+       0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662,
+       0x933EB0BB, 0x97FFAD0C, 0xAFB010B1, 0xAB710D06, 0xA6322BDF,
+       0xA2F33668, 0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4
+};
+
+int cs_is_tagged(FILE *fp)
+{
+       char buf[8];
+
+       fseek(fp, -8, SEEK_END);
+       fread(buf, 8, 1, fp);
+       if(*(unsigned long*)buf == CKSUM_MAGIC_NUMBER)
+               return 1;
+       return 0;
+}
+
+unsigned long cs_read_sum(FILE *fp)
+{
+       char buf[8];
+
+       fseek(fp, -8, SEEK_END);
+       fread(buf, 8, 1, fp);
+       return *((unsigned long*)&buf[4]);
+}
+
+int cs_calc_sum(FILE *fp, unsigned long *res, int tagged)
+{
+       unsigned char buf[BUFLEN];
+       unsigned long crc = 0;
+       uintmax_t length = 0;
+       size_t bytes_read;
+
+       fseek(fp, 0, SEEK_SET);
+
+       while((bytes_read = fread(buf, 1, BUFLEN, fp)) > 0)
+       {
+               unsigned char *cp = buf;
+
+               if(length + bytes_read < length)
+                       return 0;
+
+               if(bytes_read != BUFLEN && tagged)
+                       bytes_read -= 8;
+
+               length += bytes_read;
+               while(bytes_read--)
+                       crc =(crc << 8) ^ crctab[((crc >> 24) ^ *cp++) & 0xFF];
+       }
+
+       if(ferror(fp))
+               return 0;
+
+       for(; length; length >>= 8)
+               crc =(crc << 8) ^ crctab[((crc >> 24) ^ length) & 0xFF];
+
+       crc = ~crc & 0xFFFFFFFF;
+
+       *res = crc;
+
+       return 1;
+}
+
+unsigned long cs_calc_buf_sum(char *buf, int size)
+{
+       unsigned long crc = 0;
+       char *cp = buf;
+       unsigned long length = size;
+
+       while(size--)
+               crc =(crc << 8) ^ crctab[((crc >> 24) ^ *cp++) & 0xFF];
+
+       for(; length; length >>= 8)
+               crc =(crc << 8) ^ crctab[((crc >> 24) ^ length) & 0xFF];
+
+       crc = ~crc & 0xFFFFFFFF;
+
+       return crc;
+}
+
+unsigned long cs_calc_buf_sum_ds(char *buf, int buf_size, char *sign, int sign_len)
+{
+       unsigned long crc = 0;
+       char *cp = buf;
+       unsigned long length = buf_size+sign_len;
+
+       while(buf_size--)
+               crc =(crc << 8) ^ crctab[((crc >> 24) ^ *cp++) & 0xFF];
+
+       cp = sign;
+       while(sign_len--)
+               crc =(crc << 8) ^ crctab[((crc >> 24) ^ *cp++) & 0xFF];
+
+
+       for(; length; length >>= 8)
+               crc =(crc << 8) ^ crctab[((crc >> 24) ^ length) & 0xFF];
+
+       crc = ~crc & 0xFFFFFFFF;
+
+       return crc;
+}
+
+int cs_set_sum(FILE *fp, unsigned long sum, int tagged)
+{
+       unsigned long magic = CKSUM_MAGIC_NUMBER;
+
+       if(tagged)
+               fseek(fp, -8, SEEK_END);
+       else
+               fseek(fp, 0, SEEK_END);
+
+       if(fwrite(&magic, 1, 4, fp) < 4)
+               return 0;
+       if(fwrite(&sum, 1, 4, fp) < 4)
+               return 0;
+
+       return 1;
+}
+
+void cs_get_sum(FILE *fp, unsigned long *sum)
+{
+       unsigned long magic = 0;
+
+       fseek(fp, -8, SEEK_END);
+
+       fread(&magic, 4, 1, fp);
+       fread(sum, 4, 1, fp);
+}
+
+int cs_validate_file(char *filename)
+{
+       FILE *pFile = NULL;
+       unsigned long sum = 0, res = 0;
+
+       if((pFile = fopen(filename, "r")) == NULL)
+               return 0;
+
+       if(!cs_is_tagged(pFile))
+       {
+               fclose(pFile);
+               return 0;
+       }
+       if(!cs_calc_sum(pFile, &sum, 1))
+       {
+               fclose(pFile);
+               return 0;
+       }
+       cs_get_sum(pFile, &res);
+       fclose(pFile);
+
+       if(sum != res)
+               return 0;
+       return 1;
+}
+
+/* ********* Library internal data ********* */
+#define        CMDLINE_TRUE                    1
+#define        CMDLINE_FALSE                   0
+
+typedef        enum CMDLINE_ERR
+{
+       CMDLINE_ERR_OK          = 0,    /* No Error (OK) */
+       CMDLINE_ERR_ERROR       = -1,   /* Unspecified error */
+       CMDLINE_ERR_INVKEY      = -3,   /* Invalid option key */
+       CMDLINE_ERR_MANYARG     = -4,   /* Too many arguments */
+       CMDLINE_ERR_FEWARG      = -5,   /* Too few arguments */
+       CMDLINE_ERR_ILLOPT      = -6,   /* Option not allowed (illegal option) */
+       CMDLINE_ERR_NOMEM       = -7,   /* No memory */
+       CMDLINE_ERR_OPTMIS      = -8    /* A mandatory option is missing */
+} CMDLINE_ERR;
+
+/* Argument list */
+typedef        struct CMDLINE_ARG
+{
+       int                             index;          /* Index of the argument in the command line */
+       struct CMDLINE_ARG*     p_next; /* Next node in the linked list */
+} CMDLINE_ARG;
+
+/* Master control block for an option */
+typedef struct CMDLINE_ARGS
+{
+       int                             argc;           /* Total count of arguments found */
+       int                             optc;           /* Total count of options found */
+       CMDLINE_ARG*    list;           /* Argument list */
+} CMDLINE_ARGS;
+
+/* Master control block for all found arguments */
+typedef        struct CMDLINE_DATA
+{
+       CMDLINE_ARGS    opt_args[26];   /* Array of MCBs for each option ('a' through 'z') */
+       CMDLINE_ARGS    glb_args;               /* Global arguments */
+       int                             parsed;                 /* Internal flag to prevent client calls if library is not initialized */
+} CMDLINE_DATA;
+
+/* ********* Local Data ********* */
+static CMDLINE_CFG cmdline_cfg;
+static CMDLINE_DATA cmdline_data;
+
+char*  cmdline_errmsg = "CMDLINE ERROR";
+
+/* ***************************************************************
+* Print all found command line options and their arguments
+****************************************************************** */
+void* cmdline_getarg_list(char opt)
+{
+       int index = (opt - 'a');
+
+       /* Check the validity of the index */
+       if((index < 0) || (index > 25))
+       {
+               /* ERROR: Wrong option */
+               return NULL;
+       }
+
+       /* Return a pointer to the ARGS control structure */
+       return((void*)(&cmdline_data.opt_args[index]));
+}
+
+/* ***************************************************************
+* Print all found command line options and their arguments
+****************************************************************** */
+int cmdline_getarg_count(void* list)
+{
+       CMDLINE_ARGS*   p_args = (CMDLINE_ARGS*)list;
+
+       /* Return number of arguments for this option */
+       return(p_args->argc);
+}
+
+/* ***************************************************************
+* Print all found command line options and their arguments
+****************************************************************** */
+int cmdline_getopt_count(char opt)
+{
+       int                             index;
+
+       /* Calculate index value */
+       index = opt - 'a';
+       if(index < 0 || index > 25) return -1;
+
+       /* Return number of arguments for this option */
+       return(cmdline_data.opt_args[index].optc);
+}
+
+/* ***************************************************************
+* Print all found command line options and their arguments
+****************************************************************** */
+int cmdline_getarg(void* list, int num)
+{
+       int i;
+       CMDLINE_ARGS*   p_args = (CMDLINE_ARGS*)list;
+       CMDLINE_ARG*    p_arg;
+
+       /* Search the 'num' argument in the list for this option */
+       for(i=0,p_arg=p_args->list; (p_arg!=NULL) && (i<p_args->argc); i++, p_arg=p_arg->p_next)
+       {
+               /* if num matches i, we found it */
+               if(i==num) return(p_arg->index);
+       }
+       /* We did not find the specified argument or the list was empty */
+       return -1;
+}
+
+/* ***************************************************************
+* Print all found command line options and their arguments
+****************************************************************** */
+int cmdline_configure(CMDLINE_CFG* p_cfg)
+{
+       /* reset global data */
+       memset(&cmdline_cfg,0,sizeof(cmdline_cfg));
+       memset(&cmdline_data,0,sizeof(cmdline_data));
+
+       /* Copy the user's config structure */
+       cmdline_cfg = *p_cfg;
+       return 0;
+}
+
+/* ***************************************************************
+* Print all found command line options and their arguments
+****************************************************************** */
+char* cmdline_error(int err)
+{
+       /* TODO: implement a table of error messages */
+       return(cmdline_errmsg);
+}
+
+/* ***************************************************************
+* Print all found command line options and their arguments
+****************************************************************** */
+static void cmdline_print_args(CMDLINE_ARGS* p_arglist, char* argv[])
+{
+       CMDLINE_ARG*    p_arg;
+
+       printf("   Number of times option was specified: %d\n", p_arglist->optc);
+       printf("   Number of Arguments:                  %d\n", p_arglist->argc);
+
+       if(p_arglist->argc > 0)
+       {
+               printf("   Argument List: ");
+
+               for(p_arg=p_arglist->list; p_arg != NULL; p_arg=p_arg->p_next)
+                       printf("%s ", argv[p_arg->index]);
+       }
+
+       printf("\n");
+}
+
+/* ***************************************************************
+* Print all found command line options and their arguments
+****************************************************************** */
+void cmdline_print(char* argv[])
+{
+       int i;
+
+       /* Check if the command line was parsed */
+       if(cmdline_data.parsed != CMDLINE_TRUE)
+       {
+               printf("The command line has not been parsed yet.\n");
+               return;
+       }
+
+       /* Print out option arguments */
+       for( i = 0; i < 26; i++ )
+       {
+               /* Check if the option was specified */
+               if(cmdline_data.opt_args[i].optc !=0 )
+               {
+                       /* Print out option name and arguments */
+                       printf("Option: -%c\n", (char)('a'+i));
+                       cmdline_print_args(&(cmdline_data.opt_args[i]), argv);
+               }
+       }
+
+       /* Print out global arguments */
+       printf("Global arguments:\n");
+       cmdline_print_args(&(cmdline_data.glb_args), argv);
+}
+
+/* ***************************************************************
+* Print configuration
+****************************************************************** */
+void cmdline_print_cfg(void)
+{
+
+}
+
+static void cmdline_argadd(CMDLINE_ARGS* p_arglist, CMDLINE_ARG* p_arg)
+{
+       CMDLINE_ARG*    p_list;
+       CMDLINE_ARG*    p_prev=NULL;
+
+       /* See if we had anything in the list */
+       if(p_arglist->argc == 0)
+       {
+               /* Link the argument in */
+               p_arglist->list = p_arg;
+       }
+       else
+       {
+               /* Find the tail of the list */
+               for(p_list=p_arglist->list; p_list != NULL; p_list=p_list->p_next)
+                       p_prev = p_list;
+
+               /* Link the argument in */
+               p_prev->p_next=p_arg;
+       }
+
+       /* Keep track of arg number */
+       p_arglist->argc++;
+}
+
+/* ***************************************************************
+* cmdline_read()
+* Read and parse command line arguments
+****************************************************************** */
+int cmdline_read(int argc, char* argv[])
+{
+       int i, option=0;
+
+       /* Process every command line argument in argv[] array */
+       for( i = 1; i < argc; i++ )
+       {
+               /* Does the argument start with a dash? */
+               if( *argv[i] == '-' )
+               {
+                       /* The argument must be two characters: a dash, and a letter */
+                       if( strlen(argv[i]) != 2 )
+                       {
+                               /* ERROR: option syntax (needs to be a dash and one letter) */
+                               return(CMDLINE_ERR_ERROR);
+                       }
+
+                       /* Check validity of the option key ('a' through 'z') */
+                       if( ((*(argv[i] + 1)) < 'a') || ((*(argv[i] + 1)) > 'z') )
+                       {
+                               /* ERROR: option sysntax (invalid option key) */
+                               return(CMDLINE_ERR_INVKEY);
+                       }
+
+                       /* Calculate the option index */
+                       option = (*(argv[i] + 1)) - 'a';
+                       if((option < 0) || (option > 25)) return(CMDLINE_ERR_INVKEY);
+
+                       /* Check to see if the option is allowed */
+                       if( cmdline_cfg.opts[option].flags & CMDLINE_OPTFLAG_ALLOW )
+                       {
+                               /* Option allowed. */
+                               cmdline_data.opt_args[option].optc++;
+                               continue;
+                       }
+                       else
+                       {
+                               /* ERROR: Option is not allowed */
+                               return(CMDLINE_ERR_ILLOPT);
+                       }
+               }
+               else
+               {
+                       /* Read the arguments for the option */
+                       CMDLINE_ARG*    p_arg;
+
+                       /* Allocate space for the argument node */
+                       p_arg = (CMDLINE_ARG*)calloc(1,sizeof(CMDLINE_ARG));
+                       if( p_arg== NULL )
+                       {
+                               /* ERROR: Can't allocate memory for the argument index */
+                               return(CMDLINE_ERR_NOMEM);
+                       }
+
+                       /* Initialize the argument */
+                       p_arg->index    = i;
+                       p_arg->p_next   = NULL;
+
+                       /* Check if we can add to the list of arguments for this option */
+                       if( (option < 0)                                                                                                                                /* Do we have to add to the global list? */
+                               || (cmdline_data.opt_args[option].argc == cmdline_cfg.opts[option].max)         /* Did we reach MAX arguments? */
+                               )
+                       {
+                               /* This option does not require arguments. Keep the argument in the global list. */
+                               cmdline_argadd(&(cmdline_data.glb_args), p_arg);
+                               continue;
+                       }
+                       else
+                       {
+                               /* See if the current count has reached max for this option */
+                               if( cmdline_data.opt_args[option].argc == cmdline_cfg.opts[option].max )
+                               {
+                                       /* ERROR: too many arguments for an option */
+                                       return(CMDLINE_ERR_MANYARG);
+                               }
+                               else
+                               {
+                                       /* Link the argument to the arg list of the option */
+                                       cmdline_argadd(&(cmdline_data.opt_args[option]), p_arg);
+                                       continue;
+                               }
+                       }
+               }
+       }
+
+       /* ****** We read the complete command line. See if what we collected matches the configuration ******* */
+
+       /* Check every collected option against its configuration */
+       for( i=0; i < 26; i++ )
+       {
+               /* Check if this option was allowed */
+               if(cmdline_cfg.opts[i].flags & CMDLINE_OPTFLAG_ALLOW)
+               {
+                       /* See if it was mandatory */
+                       if(cmdline_cfg.opts[i].flags & CMDLINE_OPTFLAG_MANDAT)
+                       {
+                               /* Check if we really collected this option on the command line. */
+                               if(cmdline_data.opt_args[i].optc == 0)
+                               {
+                                       /* ERROR: a missing mandatory option */
+                                       return(CMDLINE_ERR_OPTMIS);
+                               }
+                               else
+                               {
+                                       /* Option was there. Check how many args we got for it. */
+                                       if(cmdline_data.opt_args[i].argc < cmdline_cfg.opts[i].min)
+                                       {
+                                               /* ERROR: too few arguments for an option */
+                                               return(CMDLINE_ERR_FEWARG);
+                                       }
+                                       else
+                                       {
+                                               /* This mandatory option was proper. */
+                                               continue;
+                                       }
+                               }
+                       }
+                       else    /* This is non-mandatory option: */
+                       {
+                               /* Check if the option was specified on the command line */
+                               if(cmdline_data.opt_args[i].optc == 0)
+                               {
+                                       /* option wasn't specified, go to the next */
+                                       continue;
+                               }
+                               else
+                               {
+                                       /* Option was there. Check how many args we collected for it. */
+                                       if(cmdline_data.opt_args[i].argc < cmdline_cfg.opts[i].min)
+                                       {
+                                               /* ERROR: too few arguments for a non-mandatory option */
+                                               return(CMDLINE_ERR_FEWARG);
+                                       }
+                                       else
+                                       {
+                                               /* This non-mandatory option was proper. */
+                                               continue;
+                                       }
+                               }
+                       }
+               }
+               else    /* Option was not allowed. */
+               {
+                       /* We should not get here as the non-allowed options should have been
+                       trapped eariler. */
+               }
+       }
+
+       /* Command line was proper as far as the number of options and their arguments */
+       cmdline_data.parsed = CMDLINE_TRUE;
+       return(CMDLINE_ERR_OK);
+}
diff --git a/trunk/tools/firmware-utils/src/mktitanimg.h b/trunk/tools/firmware-utils/src/mktitanimg.h
new file mode 100644 (file)
index 0000000..9ff30f6
--- /dev/null
@@ -0,0 +1,171 @@
+#ifndef __MKTITANIMG_H
+#define __MKTITANIMG_H
+
+#ifndef CFGMGR_CKSUM_H
+#define CFGMGR_CKSUM_H
+
+#define CKSUM_MAGIC_NUMBER 0xC453DE23
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <errno.h>
+
+int cs_is_tagged(FILE*);
+unsigned long cs_read_sum(FILE*);
+int cs_calc_sum(FILE*, unsigned long*, int);
+int cs_set_sum(FILE*, unsigned long, int);
+void cs_get_sum(FILE*, unsigned long*);
+unsigned long cs_calc_buf_sum(char*, int);
+int cs_validate_file(char*);
+
+#endif
+#ifndef ___CMDLINE_H___
+#define        ___CMDLINE_H___
+
+/* ********* Library Configuration ********* */
+typedef        struct CMDLINE_OPT
+{
+       int     min;                                    /* Minimum number of arguments this option takes */
+       int     max;                                    /* Maximum number of arguments this option takes */
+       int     flags;                                  /* Controlling flags (whether to accept or not, etc) */
+} CMDLINE_OPT;
+
+typedef        struct CMDLINE_CFG
+{
+       CMDLINE_OPT     opts[26];               /* Options 'a' through 'z' */
+       CMDLINE_OPT     global;                 /* Global option (outside 'a'..'z') */
+} CMDLINE_CFG;
+/* ******************************************** */
+
+#define        CMDLINE_OPTFLAG_ALLOW   0x1                     /* The option is allowed */
+#define        CMDLINE_OPTFLAG_MANDAT  0x2                     /* The option is mandatory */
+
+extern void    cmdline_print(char* argv[]);
+
+extern int             cmdline_configure(CMDLINE_CFG* p_cfg);
+extern int             cmdline_read(int argc, char* argv[]);
+
+extern void*   cmdline_getarg_list(char opt);
+extern int             cmdline_getarg_count(void* list);
+extern int             cmdline_getopt_count(char opt);
+extern int             cmdline_getarg(void* list, int num);
+
+extern char*   cmdline_error(int err);
+#endif
+
+
+#ifndef _NSPIMGHDR_H_
+#define _NSPIMGHDR_H_
+
+/* This file describes the header format for the single image. The image is broken
+   up into several pieces. The image contains this header plus 1 or more sections.
+   Each section contains a binary block that could be a kernel, filesystem, etc. The
+   only garentee for this is that the very first section MUST be executable. Meaning
+   that the bootloader will be able to take the address of the header start, add the
+   header size, and execute that binary block. The header has its own checksum. It
+   starts hdr_size-4 bytes from the start of the header.
+ */
+
+struct nsp_img_hdr_head
+{
+       unsigned int    magic;          /* Magic number to identify this image header */
+       unsigned int    boot_offset;    /* Offset from start of header to kernel code. */
+       unsigned int    flags;          /* Image flags. */
+       unsigned int    hdr_version;    /* Version of this header. */
+       unsigned int    hdr_size;       /* The complete size of all portions of the header */
+       unsigned int    prod_id;        /* This product id */
+       unsigned int    rel_id;         /* Which release this is */
+       unsigned int    version;        /* name-MMM.nnn.ooo-rxx => 0xMMnnooxx. See comment
+                                          below */
+       unsigned int    image_size;     /* Image size (including header) */
+       unsigned int    info_offset;    /* Offset from start of header to info block */
+       unsigned int    sect_info_offset;       /* Offset from start of header to section desc */
+       unsigned int    chksum_offset;  /* Offset from start of header to chksum block */
+//     unsigned int    pad1;
+};
+
+/* The patch id is a machine readable value that takes the normal patch level, and encodes
+   the correct numbers inside of it. The format of the patches are name-MM.NN.oo-rxx.bin.
+   Convert MM, NN, oo, and xx into hex, and encode them as 0xMMNNooxx. Thus:
+   att-1.2.18-r14.bin => 0x0102120e */
+
+/* The following are the flag bits for the above flags variable */
+/* List of NSP status flags: */
+#define NSP_IMG_FLAG_FAILBACK_MASK     0xF8000000
+
+/* NSP Image status flag: Flag indicates individual sections image */
+#define NSP_IMG_FLAG_INDIVIDUAL                0x00000001
+
+/* NSP Image status flag 1: Image contains a bootable image when this bit is 0 */
+#define NSP_IMG_FLAG_FAILBACK_1                0x08000000
+
+/* NSP Image status flag 2: Image contains a non-bootable image when this bit is 0 */
+#define NSP_IMG_FLAG_FAILBACK_2                0x10000000
+
+/* NSP Image status flag 3: PSPBoot has tried the image when this bit is 0 */
+#define NSP_IMG_FLAG_FAILBACK_3                0x20000000
+
+/* NSP Image status flag 4: Image is now secondary image when this bit is 0 */
+#define NSP_IMG_FLAG_FAILBACK_4                0x40000000
+
+/* NSP Image status flag 5: Image contains a valid image when this bit is 0 */
+#define NSP_IMG_FLAG_FAILBACK_5                0x80000000
+
+/* NSP Single image magic number */
+#define NSP_IMG_MAGIC_NUMBER           0x4D544443
+
+
+struct nsp_img_hdr_info
+{
+       char    release_name[64];       /* Name of release */
+       char    image_filename[64];     /* name-mm.nn.oo-rxx.bin format */
+};
+
+struct nsp_img_hdr_section_info
+{
+       unsigned int    num_sects;      /* Number of section (and section desc blocks) in this
+                                          image */
+       unsigned int    sect_size;      /* Size of a SINGLE section_desc block */
+       unsigned int    sections_offset;        /* Offset to from start of header to the start of
+                                                  the section blocks */
+};
+
+/* There will be one of more of the following stuctures in the image header. Each
+   section will have one of these blocks. */
+struct nsp_img_hdr_sections
+{
+       unsigned int    offset;         /* Offset of section from start of NSP_IMG_HDR_HEAD */
+       unsigned int    total_size;     /* Size of section (including pad size.) */
+       unsigned int    raw_size;       /* Size of section only */
+       unsigned int    flags;          /* Section flags */
+       unsigned int    chksum;         /* Section checksum */
+       unsigned int    type;           /* Section type. What kind of info does this section
+                                          describe */
+       char            name[16];       /* Reference name for this section. */
+};
+#define NSP_IMG_SECTION_TYPE_KERNEL            (0x01)
+#define NSP_IMG_SECTION_TYPE_FILESYSTEM_ROOT   (0x02)
+#define NSP_IMG_SECTION_TYPE_FILESYSTEM                (0x03)
+
+struct nsp_img_hdr
+{
+       struct nsp_img_hdr_head         head;   /* Head portion */
+       struct nsp_img_hdr_info         info;   /* Info */
+       struct nsp_img_hdr_section_info sect_info;      /* Section block */
+       struct nsp_img_hdr_sections     sections;       /* 1 or more section_description blocks. More
+                                                  section_desc blocks will be appended here
+                                                  for each additional section needed */
+};
+
+struct nsp_img_hdr_chksum
+{
+       unsigned int    hdr_chksum;     /* The checksum for the complete header. Excepting the
+                                          checksum block */
+};
+
+struct nsp_img_hdr_sections *nsp_img_hdr_get_section_ptr_by_name(struct nsp_img_hdr *hdr, char *name);
+unsigned int nsp_img_hdr_get_section_offset_by_name(struct nsp_img_hdr *hdr, char *name);
+unsigned int nsp_img_hdr_get_section_size_by_name(struct nsp_img_hdr *hdr, char *name);
+
+#endif
+#endif /* __MKTITANIMG_H */
diff --git a/trunk/tools/firmware-utils/src/mktplinkfw.c b/trunk/tools/firmware-utils/src/mktplinkfw.c
new file mode 100644 (file)
index 0000000..8100445
--- /dev/null
@@ -0,0 +1,1170 @@
+/*
+ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This tool was based on:
+ *   TP-Link WR941 V2 firmware checksum fixing tool.
+ *   Copyright (C) 2008,2009 Wang Jian <lark@linux.net.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>     /* for unlink() */
+#include <libgen.h>
+#include <getopt.h>     /* for getopt() */
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include "md5.h"
+
+#define ALIGN(x,a) ({ typeof(a) __a = (a); (((x) + __a - 1) & ~(__a - 1)); })
+
+#define HEADER_VERSION_V1      0x01000000
+#define HWID_GL_INET_V1                0x08000001
+#define HWID_GS_OOLITE_V1      0x3C000101
+#define HWID_TL_MR10U_V1       0x00100101
+#define HWID_TL_MR13U_V1       0x00130101
+#define HWID_TL_MR3020_V1      0x30200001
+#define HWID_TL_MR3220_V1      0x32200001
+#define HWID_TL_MR3220_V2      0x32200002
+#define HWID_TL_MR3420_V1      0x34200001
+#define HWID_TL_MR3420_V2      0x34200002
+#define HWID_TL_WA701N_V1      0x07010001
+#define HWID_TL_WA701N_V2      0x07010002
+#define HWID_TL_WA7210N_V2     0x72100002
+#define HWID_TL_WA7510N_V1     0x75100001
+#define HWID_TL_WA801ND_V1     0x08010001
+#define HWID_TL_WA830RE_V1     0x08300010
+#define HWID_TL_WA830RE_V2     0x08300002
+#define HWID_TL_WA801ND_V2     0x08010002
+#define HWID_TL_WA901ND_V1     0x09010001
+#define HWID_TL_WA901ND_V2     0x09010002
+#define HWID_TL_WDR4300_V1_IL  0x43008001
+#define HWID_TL_WDR4900_V1     0x49000001
+#define HWID_TL_WR703N_V1      0x07030101
+#define HWID_TL_WR720N_V3      0x07200103
+#define HWID_TL_WR741ND_V1     0x07410001
+#define HWID_TL_WR741ND_V4     0x07410004
+#define HWID_TL_WR740N_V1      0x07400001
+#define HWID_TL_WR740N_V3      0x07400003
+#define HWID_TL_WR743ND_V1     0x07430001
+#define HWID_TL_WR743ND_V2     0x07430002
+#define HWID_TL_WR841N_V1_5    0x08410002
+#define HWID_TL_WR841ND_V3     0x08410003
+#define HWID_TL_WR841ND_V5     0x08410005
+#define HWID_TL_WR841ND_V7     0x08410007
+#define HWID_TL_WR941ND_V2     0x09410002
+#define HWID_TL_WR941ND_V4     0x09410004
+#define HWID_TL_WR1043ND_V1    0x10430001
+#define HWID_TL_WR1043ND_V2    0x10430002
+#define HWID_TL_WR1041N_V2     0x10410002
+#define HWID_TL_WR2543N_V1     0x25430001
+
+#define MD5SUM_LEN     16
+
+struct file_info {
+       char            *file_name;     /* name of the file */
+       uint32_t        file_size;      /* length of the file */
+};
+
+struct fw_header {
+       uint32_t        version;        /* header version */
+       char            vendor_name[24];
+       char            fw_version[36];
+       uint32_t        hw_id;          /* hardware id */
+       uint32_t        hw_rev;         /* hardware revision */
+       uint32_t        unk1;
+       uint8_t         md5sum1[MD5SUM_LEN];
+       uint32_t        unk2;
+       uint8_t         md5sum2[MD5SUM_LEN];
+       uint32_t        unk3;
+       uint32_t        kernel_la;      /* kernel load address */
+       uint32_t        kernel_ep;      /* kernel entry point */
+       uint32_t        fw_length;      /* total length of the firmware */
+       uint32_t        kernel_ofs;     /* kernel data offset */
+       uint32_t        kernel_len;     /* kernel data length */
+       uint32_t        rootfs_ofs;     /* rootfs data offset */
+       uint32_t        rootfs_len;     /* rootfs data length */
+       uint32_t        boot_ofs;       /* bootloader data offset */
+       uint32_t        boot_len;       /* bootloader data length */
+       uint16_t        ver_hi;
+       uint16_t        ver_mid;
+       uint16_t        ver_lo;
+       uint8_t         pad[354];
+} __attribute__ ((packed));
+
+struct flash_layout {
+       char            *id;
+       uint32_t        fw_max_len;
+       uint32_t        kernel_la;
+       uint32_t        kernel_ep;
+       uint32_t        rootfs_ofs;
+};
+
+struct board_info {
+       char            *id;
+       uint32_t        hw_id;
+       uint32_t        hw_rev;
+       char            *layout_id;
+};
+
+/*
+ * Globals
+ */
+static char *ofname;
+static char *progname;
+static char *vendor = "TP-LINK Technologies";
+static char *version = "ver. 1.0";
+static char *fw_ver = "0.0.0";
+
+static char *board_id;
+static struct board_info *board;
+static char *layout_id;
+static struct flash_layout *layout;
+static char *opt_hw_id;
+static uint32_t hw_id;
+static char *opt_hw_rev;
+static uint32_t hw_rev;
+static int fw_ver_lo;
+static int fw_ver_mid;
+static int fw_ver_hi;
+static struct file_info kernel_info;
+static uint32_t kernel_la = 0;
+static uint32_t kernel_ep = 0;
+static uint32_t kernel_len = 0;
+static struct file_info rootfs_info;
+static uint32_t rootfs_ofs = 0;
+static uint32_t rootfs_align;
+static struct file_info boot_info;
+static int combined;
+static int strip_padding;
+static int add_jffs2_eof;
+static unsigned char jffs2_eof_mark[4] = {0xde, 0xad, 0xc0, 0xde};
+static uint32_t fw_max_len;
+static uint32_t reserved_space;
+
+static struct file_info inspect_info;
+static int extract = 0;
+
+char md5salt_normal[MD5SUM_LEN] = {
+       0xdc, 0xd7, 0x3a, 0xa5, 0xc3, 0x95, 0x98, 0xfb,
+       0xdd, 0xf9, 0xe7, 0xf4, 0x0e, 0xae, 0x47, 0x38,
+};
+
+char md5salt_boot[MD5SUM_LEN] = {
+       0x8c, 0xef, 0x33, 0x5b, 0xd5, 0xc5, 0xce, 0xfa,
+       0xa7, 0x9c, 0x28, 0xda, 0xb2, 0xe9, 0x0f, 0x42,
+};
+
+static struct flash_layout layouts[] = {
+       {
+               .id             = "4M",
+               .fw_max_len     = 0x3c0000,
+               .kernel_la      = 0x80060000,
+               .kernel_ep      = 0x80060000,
+               .rootfs_ofs     = 0x140000,
+       }, {
+               .id             = "4Mlzma",
+               .fw_max_len     = 0x3c0000,
+               .kernel_la      = 0x80060000,
+               .kernel_ep      = 0x80060000,
+               .rootfs_ofs     = 0x100000,
+       }, {
+               .id             = "8M",
+               .fw_max_len     = 0x7c0000,
+               .kernel_la      = 0x80060000,
+               .kernel_ep      = 0x80060000,
+               .rootfs_ofs     = 0x140000,
+       }, {
+               .id             = "8Mlzma",
+               .fw_max_len     = 0x7c0000,
+               .kernel_la      = 0x80060000,
+               .kernel_ep      = 0x80060000,
+               .rootfs_ofs     = 0x100000,
+       }, {
+               .id             = "16M",
+               .fw_max_len     = 0xf80000,
+               .kernel_la      = 0x80060000,
+               .kernel_ep      = 0x80060000,
+               .rootfs_ofs     = 0x140000,
+       }, {
+               .id             = "16Mlzma",
+               .fw_max_len     = 0xf80000,
+               .kernel_la      = 0x80060000,
+               .kernel_ep      = 0x80060000,
+               .rootfs_ofs     = 0x100000,
+       }, {
+               .id             = "16Mppc",
+               .fw_max_len     = 0xf80000,
+               .kernel_la      = 0x00000000,
+               .kernel_ep      = 0xc0000000,
+               .rootfs_ofs     = 0x2a0000,
+       }, {
+               /* terminating entry */
+       }
+};
+
+static struct board_info boards[] = {
+       {
+               .id             = "TL-MR10Uv1",
+               .hw_id          = HWID_TL_MR10U_V1,
+               .hw_rev         = 1,
+               .layout_id      = "4Mlzma",
+       }, {
+               .id             = "TL-MR13Uv1",
+               .hw_id          = HWID_TL_MR13U_V1,
+               .hw_rev         = 1,
+               .layout_id      = "4Mlzma",
+       }, {
+               .id             = "TL-MR3020v1",
+               .hw_id          = HWID_TL_MR3020_V1,
+               .hw_rev         = 1,
+               .layout_id      = "4Mlzma",
+       }, {
+               .id             = "TL-MR3220v1",
+               .hw_id          = HWID_TL_MR3220_V1,
+               .hw_rev         = 1,
+               .layout_id      = "4M",
+       }, {
+               .id             = "TL-MR3220v2",
+               .hw_id          = HWID_TL_MR3220_V2,
+               .hw_rev         = 1,
+               .layout_id      = "4Mlzma",
+       }, {
+               .id             = "TL-MR3420v1",
+               .hw_id          = HWID_TL_MR3420_V1,
+               .hw_rev         = 1,
+               .layout_id      = "4M",
+       }, {
+               .id             = "TL-MR3420v2",
+               .hw_id          = HWID_TL_MR3420_V2,
+               .hw_rev         = 1,
+               .layout_id      = "4Mlzma",
+       }, {
+               .id             = "TL-WA701Nv1",
+               .hw_id          = HWID_TL_WA701N_V1,
+               .hw_rev         = 1,
+               .layout_id      = "4M",
+       }, {
+               .id             = "TL-WA701Nv2",
+               .hw_id          = HWID_TL_WA701N_V2,
+               .hw_rev         = 1,
+               .layout_id      = "4Mlzma",
+       }, {
+               .id             = "TL-WA7210N",
+               .hw_id          = HWID_TL_WA7210N_V2,
+               .hw_rev         = 2,
+               .layout_id      = "4Mlzma",
+       }, {
+               .id             = "TL-WA7510N",
+               .hw_id          = HWID_TL_WA7510N_V1,
+               .hw_rev         = 1,
+               .layout_id      = "4M",
+       }, {
+               .id             = "TL-WA801NDv1",
+               .hw_id          = HWID_TL_WA801ND_V1,
+               .hw_rev         = 1,
+               .layout_id      = "4M",
+       }, {
+               .id             = "TL-WA830REv1",
+               .hw_id          = HWID_TL_WA830RE_V1,
+               .hw_rev         = 1,
+               .layout_id      = "4M",
+       }, {
+               .id             = "TL-WA830REv2",
+               .hw_id          = HWID_TL_WA830RE_V2,
+               .hw_rev         = 1,
+               .layout_id      = "4M",
+       }, {
+               .id             = "TL-WA801NDv2",
+               .hw_id          = HWID_TL_WA801ND_V2,
+               .hw_rev         = 1,
+               .layout_id      = "4Mlzma",
+       }, {
+               .id             = "TL-WA901NDv1",
+               .hw_id          = HWID_TL_WA901ND_V1,
+               .hw_rev         = 1,
+               .layout_id      = "4M",
+       }, {
+               .id             = "TL-WA901NDv2",
+               .hw_id          = HWID_TL_WA901ND_V2,
+               .hw_rev         = 1,
+               .layout_id      = "4M",
+       }, {
+               .id             = "TL-WDR4300v1",
+               .hw_id          = HWID_TL_WDR4300_V1_IL,
+               .hw_rev         = 1,
+               .layout_id      = "8Mlzma",
+       }, {
+               .id             = "TL-WDR4900v1",
+               .hw_id          = HWID_TL_WDR4900_V1,
+               .hw_rev         = 1,
+               .layout_id      = "16Mppc",
+       }, {
+               .id             = "TL-WR741NDv1",
+               .hw_id          = HWID_TL_WR741ND_V1,
+               .hw_rev         = 1,
+               .layout_id      = "4M",
+       }, {
+               .id             = "TL-WR741NDv4",
+               .hw_id          = HWID_TL_WR741ND_V4,
+               .hw_rev         = 1,
+               .layout_id      = "4Mlzma",
+       }, {
+               .id             = "TL-WR740Nv1",
+               .hw_id          = HWID_TL_WR740N_V1,
+               .hw_rev         = 1,
+               .layout_id      = "4M",
+       }, {
+               .id             = "TL-WR740Nv3",
+               .hw_id          = HWID_TL_WR740N_V3,
+               .hw_rev         = 1,
+               .layout_id      = "4M",
+       }, {
+               .id             = "TL-WR743NDv1",
+               .hw_id          = HWID_TL_WR743ND_V1,
+               .hw_rev         = 1,
+               .layout_id      = "4M",
+       }, {
+               .id             = "TL-WR743NDv2",
+               .hw_id          = HWID_TL_WR743ND_V2,
+               .hw_rev         = 1,
+               .layout_id      = "4Mlzma",
+       }, {
+               .id             = "TL-WR841Nv1.5",
+               .hw_id          = HWID_TL_WR841N_V1_5,
+               .hw_rev         = 2,
+               .layout_id      = "4M",
+       }, {
+               .id             = "TL-WR841NDv3",
+               .hw_id          = HWID_TL_WR841ND_V3,
+               .hw_rev         = 3,
+               .layout_id      = "4M",
+       }, {
+               .id             = "TL-WR841NDv5",
+               .hw_id          = HWID_TL_WR841ND_V5,
+               .hw_rev         = 1,
+               .layout_id      = "4M",
+       }, {
+               .id             = "TL-WR841NDv7",
+               .hw_id          = HWID_TL_WR841ND_V7,
+               .hw_rev         = 1,
+               .layout_id      = "4M",
+       }, {
+               .id             = "TL-WR941NDv2",
+               .hw_id          = HWID_TL_WR941ND_V2,
+               .hw_rev         = 2,
+               .layout_id      = "4M",
+       }, {
+               .id             = "TL-WR941NDv4",
+               .hw_id          = HWID_TL_WR941ND_V4,
+               .hw_rev         = 1,
+               .layout_id      = "4M",
+       }, {
+               .id             = "TL-WR1041Nv2",
+               .hw_id          = HWID_TL_WR1041N_V2,
+               .hw_rev         = 1,
+               .layout_id      = "4Mlzma",
+       }, {
+               .id             = "TL-WR1043NDv1",
+               .hw_id          = HWID_TL_WR1043ND_V1,
+               .hw_rev         = 1,
+               .layout_id      = "8M",
+       }, {
+               .id             = "TL-WR1043NDv2",
+               .hw_id          = HWID_TL_WR1043ND_V2,
+               .hw_rev         = 1,
+               .layout_id      = "8Mlzma",
+       }, {
+               .id             = "TL-WR2543Nv1",
+               .hw_id          = HWID_TL_WR2543N_V1,
+               .hw_rev         = 1,
+               .layout_id      = "8Mlzma",
+       }, {
+               .id             = "TL-WR703Nv1",
+               .hw_id          = HWID_TL_WR703N_V1,
+               .hw_rev         = 1,
+               .layout_id      = "4Mlzma",
+       }, {
+               .id             = "TL-WR720Nv3",
+               .hw_id          = HWID_TL_WR720N_V3,
+               .hw_rev         = 1,
+               .layout_id      = "4Mlzma",
+       }, {
+               .id             = "GL-INETv1",
+               .hw_id          = HWID_GL_INET_V1,
+               .hw_rev         = 1,
+               .layout_id      = "8Mlzma",
+       }, {
+               .id             = "GS-OOLITEv1",
+               .hw_id          = HWID_GS_OOLITE_V1,
+               .hw_rev         = 1,
+               .layout_id      = "16Mlzma",
+       }, {
+               /* terminating entry */
+       }
+};
+
+/*
+ * Message macros
+ */
+#define ERR(fmt, ...) do { \
+       fflush(0); \
+       fprintf(stderr, "[%s] *** error: " fmt "\n", \
+                       progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERRS(fmt, ...) do { \
+       int save = errno; \
+       fflush(0); \
+       fprintf(stderr, "[%s] *** error: " fmt "\n", \
+                       progname, ## __VA_ARGS__, strerror(save)); \
+} while (0)
+
+#define DBG(fmt, ...) do { \
+       fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
+} while (0)
+
+static struct board_info *find_board(char *id)
+{
+       struct board_info *ret;
+       struct board_info *board;
+
+       ret = NULL;
+       for (board = boards; board->id != NULL; board++){
+               if (strcasecmp(id, board->id) == 0) {
+                       ret = board;
+                       break;
+               }
+       };
+
+       return ret;
+}
+
+static struct board_info *find_board_by_hwid(uint32_t hw_id)
+{
+       struct board_info *board;
+
+       for (board = boards; board->id != NULL; board++) {
+               if (hw_id == board->hw_id)
+                       return board;
+       };
+
+       return NULL;
+}
+
+static struct flash_layout *find_layout(char *id)
+{
+       struct flash_layout *ret;
+       struct flash_layout *l;
+
+       ret = NULL;
+       for (l = layouts; l->id != NULL; l++){
+               if (strcasecmp(id, l->id) == 0) {
+                       ret = l;
+                       break;
+               }
+       };
+
+       return ret;
+}
+
+static void usage(int status)
+{
+       FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+       struct board_info *board;
+
+       fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+       fprintf(stream,
+"\n"
+"Options:\n"
+"  -B <board>      create image for the board specified with <board>\n"
+"  -c              use combined kernel image\n"
+"  -E <ep>         overwrite kernel entry point with <ep> (hexval prefixed with 0x)\n"
+"  -L <la>         overwrite kernel load address with <la> (hexval prefixed with 0x)\n"
+"  -H <hwid>       use hardware id specified with <hwid>\n"
+"  -W <hwrev>      use hardware revision specified with <hwrev>\n"
+"  -F <id>         use flash layout specified with <id>\n"
+"  -k <file>       read kernel image from the file <file>\n"
+"  -r <file>       read rootfs image from the file <file>\n"
+"  -a <align>      align the rootfs start on an <align> bytes boundary\n"
+"  -R <offset>     overwrite rootfs offset with <offset> (hexval prefixed with 0x)\n"
+"  -o <file>       write output to the file <file>\n"
+"  -s              strip padding from the end of the image\n"
+"  -j              add jffs2 end-of-filesystem markers\n"
+"  -N <vendor>     set image vendor to <vendor>\n"
+"  -V <version>    set image version to <version>\n"
+"  -v <version>    set firmware version to <version>\n"
+"  -i <file>       inspect given firmware file <file>\n"
+"  -x              extract kernel and rootfs while inspecting (requires -i)\n"
+"  -X <size>       reserve <size> bytes in the firmware image (hexval prefixed with 0x)\n"
+"  -h              show this screen\n"
+       );
+
+       exit(status);
+}
+
+static int get_md5(char *data, int size, char *md5)
+{
+       MD5_CTX ctx;
+
+       MD5_Init(&ctx);
+       MD5_Update(&ctx, data, size);
+       MD5_Final(md5, &ctx);
+}
+
+static int get_file_stat(struct file_info *fdata)
+{
+       struct stat st;
+       int res;
+
+       if (fdata->file_name == NULL)
+               return 0;
+
+       res = stat(fdata->file_name, &st);
+       if (res){
+               ERRS("stat failed on %s", fdata->file_name);
+               return res;
+       }
+
+       fdata->file_size = st.st_size;
+       return 0;
+}
+
+static int read_to_buf(struct file_info *fdata, char *buf)
+{
+       FILE *f;
+       int ret = EXIT_FAILURE;
+
+       f = fopen(fdata->file_name, "r");
+       if (f == NULL) {
+               ERRS("could not open \"%s\" for reading", fdata->file_name);
+               goto out;
+       }
+
+       errno = 0;
+       fread(buf, fdata->file_size, 1, f);
+       if (errno != 0) {
+               ERRS("unable to read from file \"%s\"", fdata->file_name);
+               goto out_close;
+       }
+
+       ret = EXIT_SUCCESS;
+
+ out_close:
+       fclose(f);
+ out:
+       return ret;
+}
+
+static int check_options(void)
+{
+       int ret;
+
+       if (inspect_info.file_name) {
+               ret = get_file_stat(&inspect_info);
+               if (ret)
+                       return ret;
+
+               return 0;
+       } else if (extract) {
+               ERR("no firmware for inspection specified");
+               return -1;
+       }
+
+       if (board_id == NULL && opt_hw_id == NULL) {
+               ERR("either board or hardware id must be specified");
+               return -1;
+       }
+
+       if (board_id) {
+               board = find_board(board_id);
+               if (board == NULL) {
+                       ERR("unknown/unsupported board id \"%s\"", board_id);
+                       return -1;
+               }
+               if (layout_id == NULL)
+                       layout_id = board->layout_id;
+
+               hw_id = board->hw_id;
+               hw_rev = board->hw_rev;
+       } else {
+               if (layout_id == NULL) {
+                       ERR("flash layout is not specified");
+                       return -1;
+               }
+               hw_id = strtoul(opt_hw_id, NULL, 0);
+
+               if (opt_hw_rev)
+                       hw_rev = strtoul(opt_hw_rev, NULL, 0);
+               else
+                       hw_rev = 1;
+       }
+
+       layout = find_layout(layout_id);
+       if (layout == NULL) {
+               ERR("unknown flash layout \"%s\"", layout_id);
+               return -1;
+       }
+
+       if (!kernel_la)
+               kernel_la = layout->kernel_la;
+       if (!kernel_ep)
+               kernel_ep = layout->kernel_ep;
+       if (!rootfs_ofs)
+               rootfs_ofs = layout->rootfs_ofs;
+
+       if (reserved_space > layout->fw_max_len) {
+               ERR("reserved space is not valid");
+               return -1;
+       }
+
+       fw_max_len = layout->fw_max_len - reserved_space;
+
+       if (kernel_info.file_name == NULL) {
+               ERR("no kernel image specified");
+               return -1;
+       }
+
+       ret = get_file_stat(&kernel_info);
+       if (ret)
+               return ret;
+
+       kernel_len = kernel_info.file_size;
+
+       if (combined) {
+               if (kernel_info.file_size >
+                   fw_max_len - sizeof(struct fw_header)) {
+                       ERR("kernel image is too big");
+                       return -1;
+               }
+       } else {
+               if (rootfs_info.file_name == NULL) {
+                       ERR("no rootfs image specified");
+                       return -1;
+               }
+
+               ret = get_file_stat(&rootfs_info);
+               if (ret)
+                       return ret;
+
+               if (rootfs_align) {
+                       kernel_len += sizeof(struct fw_header);
+                       kernel_len = ALIGN(kernel_len, rootfs_align);
+                       kernel_len -= sizeof(struct fw_header);
+
+                       DBG("kernel length aligned to %u", kernel_len);
+
+                       if (kernel_len + rootfs_info.file_size >
+                           fw_max_len - sizeof(struct fw_header)) {
+                               ERR("images are too big");
+                               return -1;
+                       }
+               } else {
+                       if (kernel_info.file_size >
+                           rootfs_ofs - sizeof(struct fw_header)) {
+                               ERR("kernel image is too big");
+                               return -1;
+                       }
+
+                       if (rootfs_info.file_size >
+                           (fw_max_len - rootfs_ofs)) {
+                               ERR("rootfs image is too big");
+                               return -1;
+                       }
+               }
+       }
+
+       if (ofname == NULL) {
+               ERR("no output file specified");
+               return -1;
+       }
+
+       ret = sscanf(fw_ver, "%d.%d.%d", &fw_ver_hi, &fw_ver_mid, &fw_ver_lo);
+       if (ret != 3) {
+               ERR("invalid firmware version '%s'", fw_ver);
+               return -1;
+       }
+
+       return 0;
+}
+
+static void fill_header(char *buf, int len)
+{
+       struct fw_header *hdr = (struct fw_header *)buf;
+
+       memset(hdr, 0, sizeof(struct fw_header));
+
+       hdr->version = htonl(HEADER_VERSION_V1);
+       strncpy(hdr->vendor_name, vendor, sizeof(hdr->vendor_name));
+       strncpy(hdr->fw_version, version, sizeof(hdr->fw_version));
+       hdr->hw_id = htonl(hw_id);
+       hdr->hw_rev = htonl(hw_rev);
+
+       if (boot_info.file_size == 0)
+               memcpy(hdr->md5sum1, md5salt_normal, sizeof(hdr->md5sum1));
+       else
+               memcpy(hdr->md5sum1, md5salt_boot, sizeof(hdr->md5sum1));
+
+       hdr->kernel_la = htonl(kernel_la);
+       hdr->kernel_ep = htonl(kernel_ep);
+       hdr->fw_length = htonl(layout->fw_max_len);
+       hdr->kernel_ofs = htonl(sizeof(struct fw_header));
+       hdr->kernel_len = htonl(kernel_len);
+       if (!combined) {
+               hdr->rootfs_ofs = htonl(rootfs_ofs);
+               hdr->rootfs_len = htonl(rootfs_info.file_size);
+       }
+
+       hdr->ver_hi = htons(fw_ver_hi);
+       hdr->ver_mid = htons(fw_ver_mid);
+       hdr->ver_lo = htons(fw_ver_lo);
+
+       get_md5(buf, len, hdr->md5sum1);
+}
+
+static int pad_jffs2(char *buf, int currlen)
+{
+       int len;
+       uint32_t pad_mask;
+
+       len = currlen;
+       pad_mask = (64 * 1024);
+       while ((len < layout->fw_max_len) && (pad_mask != 0)) {
+               uint32_t mask;
+               int i;
+
+               for (i = 10; i < 32; i++) {
+                       mask = 1 << i;
+                       if (pad_mask & mask)
+                               break;
+               }
+
+               len = ALIGN(len, mask);
+
+               for (i = 10; i < 32; i++) {
+                       mask = 1 << i;
+                       if ((len & (mask - 1)) == 0)
+                               pad_mask &= ~mask;
+               }
+
+               for (i = 0; i < sizeof(jffs2_eof_mark); i++)
+                       buf[len + i] = jffs2_eof_mark[i];
+
+               len += sizeof(jffs2_eof_mark);
+       }
+
+       return len;
+}
+
+static int write_fw(char *data, int len)
+{
+       FILE *f;
+       int ret = EXIT_FAILURE;
+
+       f = fopen(ofname, "w");
+       if (f == NULL) {
+               ERRS("could not open \"%s\" for writing", ofname);
+               goto out;
+       }
+
+       errno = 0;
+       fwrite(data, len, 1, f);
+       if (errno) {
+               ERRS("unable to write output file");
+               goto out_flush;
+       }
+
+       DBG("firmware file \"%s\" completed", ofname);
+
+       ret = EXIT_SUCCESS;
+
+ out_flush:
+       fflush(f);
+       fclose(f);
+       if (ret != EXIT_SUCCESS) {
+               unlink(ofname);
+       }
+ out:
+       return ret;
+}
+
+static int build_fw(void)
+{
+       int buflen;
+       char *buf;
+       char *p;
+       int ret = EXIT_FAILURE;
+       int writelen = 0;
+
+       buflen = layout->fw_max_len;
+
+       buf = malloc(buflen);
+       if (!buf) {
+               ERR("no memory for buffer\n");
+               goto out;
+       }
+
+       memset(buf, 0xff, buflen);
+       p = buf + sizeof(struct fw_header);
+       ret = read_to_buf(&kernel_info, p);
+       if (ret)
+               goto out_free_buf;
+
+       writelen = sizeof(struct fw_header) + kernel_len;
+
+       if (!combined) {
+               if (rootfs_align)
+                       p = buf + writelen;
+               else
+                       p = buf + rootfs_ofs;
+
+               ret = read_to_buf(&rootfs_info, p);
+               if (ret)
+                       goto out_free_buf;
+
+               if (rootfs_align)
+                       writelen += rootfs_info.file_size;
+               else
+                       writelen = rootfs_ofs + rootfs_info.file_size;
+
+               if (add_jffs2_eof)
+                       writelen = pad_jffs2(buf, writelen);
+       }
+
+       if (!strip_padding)
+               writelen = buflen;
+
+       fill_header(buf, writelen);
+       ret = write_fw(buf, writelen);
+       if (ret)
+               goto out_free_buf;
+
+       ret = EXIT_SUCCESS;
+
+ out_free_buf:
+       free(buf);
+ out:
+       return ret;
+}
+
+/* Helper functions to inspect_fw() representing different output formats */
+static inline void inspect_fw_pstr(char *label, char *str)
+{
+       printf("%-23s: %s\n", label, str);
+}
+
+static inline void inspect_fw_phex(char *label, uint32_t val)
+{
+       printf("%-23s: 0x%08x\n", label, val);
+}
+
+static inline void inspect_fw_phexpost(char *label,
+                                       uint32_t val, char *post)
+{
+       printf("%-23s: 0x%08x (%s)\n", label, val, post);
+}
+
+static inline void inspect_fw_phexdef(char *label,
+                                      uint32_t val, uint32_t defval)
+{
+       printf("%-23s: 0x%08x                  ", label, val);
+
+       if (val == defval)
+               printf("(== libreCMC default)\n");
+       else
+               printf("(libreCMC default: 0x%08x)\n", defval);
+}
+
+static inline void inspect_fw_phexexp(char *label,
+                                      uint32_t val, uint32_t expval)
+{
+       printf("%-23s: 0x%08x ", label, val);
+
+       if (val == expval)
+               printf("(ok)\n");
+       else
+               printf("(expected: 0x%08x)\n", expval);
+}
+
+static inline void inspect_fw_phexdec(char *label, uint32_t val)
+{
+       printf("%-23s: 0x%08x / %8u bytes\n", label, val, val);
+}
+
+static inline void inspect_fw_phexdecdef(char *label,
+                                         uint32_t val, uint32_t defval)
+{
+       printf("%-23s: 0x%08x / %8u bytes ", label, val, val);
+
+       if (val == defval)
+               printf("(== libreCMC default)\n");
+       else
+               printf("(libreCMC default: 0x%08x)\n", defval);
+}
+
+static inline void inspect_fw_pmd5sum(char *label, uint8_t *val, char *text)
+{
+       int i;
+
+       printf("%-23s:", label);
+       for (i=0; i<MD5SUM_LEN; i++)
+               printf(" %02x", val[i]);
+       printf(" %s\n", text);
+}
+
+static int inspect_fw(void)
+{
+       char *buf;
+       struct fw_header *hdr;
+       uint8_t md5sum[MD5SUM_LEN];
+       struct board_info *board;
+       int ret = EXIT_FAILURE;
+
+       buf = malloc(inspect_info.file_size);
+       if (!buf) {
+               ERR("no memory for buffer!\n");
+               goto out;
+       }
+
+       ret = read_to_buf(&inspect_info, buf);
+       if (ret)
+               goto out_free_buf;
+       hdr = (struct fw_header *)buf;
+
+       inspect_fw_pstr("File name", inspect_info.file_name);
+       inspect_fw_phexdec("File size", inspect_info.file_size);
+
+       if (ntohl(hdr->version) != HEADER_VERSION_V1) {
+               ERR("file does not seem to have V1 header!\n");
+               goto out_free_buf;
+       }
+
+       inspect_fw_phexdec("Version 1 Header size", sizeof(struct fw_header));
+
+       if (ntohl(hdr->unk1) != 0)
+               inspect_fw_phexdec("Unknown value 1", hdr->unk1);
+
+       memcpy(md5sum, hdr->md5sum1, sizeof(md5sum));
+       if (ntohl(hdr->boot_len) == 0)
+               memcpy(hdr->md5sum1, md5salt_normal, sizeof(md5sum));
+       else
+               memcpy(hdr->md5sum1, md5salt_boot, sizeof(md5sum));
+       get_md5(buf, inspect_info.file_size, hdr->md5sum1);
+
+       if (memcmp(md5sum, hdr->md5sum1, sizeof(md5sum))) {
+               inspect_fw_pmd5sum("Header MD5Sum1", md5sum, "(*ERROR*)");
+               inspect_fw_pmd5sum("          --> expected", hdr->md5sum1, "");
+       } else {
+               inspect_fw_pmd5sum("Header MD5Sum1", md5sum, "(ok)");
+       }
+       if (ntohl(hdr->unk2) != 0)
+               inspect_fw_phexdec("Unknown value 2", hdr->unk2);
+       inspect_fw_pmd5sum("Header MD5Sum2", hdr->md5sum2,
+                          "(purpose yet unknown, unchecked here)");
+       if (ntohl(hdr->unk3) != 0)
+               inspect_fw_phexdec("Unknown value 3", hdr->unk3);
+
+       printf("\n");
+
+       inspect_fw_pstr("Vendor name", hdr->vendor_name);
+       inspect_fw_pstr("Firmware version", hdr->fw_version);
+       board = find_board_by_hwid(ntohl(hdr->hw_id));
+       if (board) {
+               layout = find_layout(board->layout_id);
+               inspect_fw_phexpost("Hardware ID",
+                                   ntohl(hdr->hw_id), board->id);
+               inspect_fw_phexexp("Hardware Revision",
+                                  ntohl(hdr->hw_rev), board->hw_rev);
+       } else {
+               inspect_fw_phexpost("Hardware ID",
+                                   ntohl(hdr->hw_id), "unknown");
+               inspect_fw_phex("Hardware Revision",
+                               ntohl(hdr->hw_rev));
+       }
+
+       printf("\n");
+
+       inspect_fw_phexdec("Kernel data offset",
+                          ntohl(hdr->kernel_ofs));
+       inspect_fw_phexdec("Kernel data length",
+                          ntohl(hdr->kernel_len));
+       if (board) {
+               inspect_fw_phexdef("Kernel load address",
+                                  ntohl(hdr->kernel_la),
+                                  layout ? layout->kernel_la : 0xffffffff);
+               inspect_fw_phexdef("Kernel entry point",
+                                  ntohl(hdr->kernel_ep),
+                                  layout ? layout->kernel_ep : 0xffffffff);
+               inspect_fw_phexdecdef("Rootfs data offset",
+                                     ntohl(hdr->rootfs_ofs),
+                                     layout ? layout->rootfs_ofs : 0xffffffff);
+       } else {
+               inspect_fw_phex("Kernel load address",
+                               ntohl(hdr->kernel_la));
+               inspect_fw_phex("Kernel entry point",
+                               ntohl(hdr->kernel_ep));
+               inspect_fw_phexdec("Rootfs data offset",
+                                  ntohl(hdr->rootfs_ofs));
+       }
+       inspect_fw_phexdec("Rootfs data length",
+                          ntohl(hdr->rootfs_len));
+       inspect_fw_phexdec("Boot loader data offset",
+                          ntohl(hdr->boot_ofs));
+       inspect_fw_phexdec("Boot loader data length",
+                          ntohl(hdr->boot_len));
+       inspect_fw_phexdec("Total firmware length",
+                          ntohl(hdr->fw_length));
+
+       if (extract) {
+               FILE *fp;
+               char *filename;
+
+               printf("\n");
+
+               filename = malloc(strlen(inspect_info.file_name) + 8);
+               sprintf(filename, "%s-kernel", inspect_info.file_name);
+               printf("Extracting kernel to \"%s\"...\n", filename);
+               fp = fopen(filename, "w");
+               if (fp) {
+                       if (!fwrite(buf + ntohl(hdr->kernel_ofs),
+                                   ntohl(hdr->kernel_len), 1, fp)) {
+                               ERR("error in fwrite(): %s", strerror(errno));
+                       }
+                       fclose(fp);
+               } else {
+                       ERR("error in fopen(): %s", strerror(errno));
+               }
+               free(filename);
+
+               filename = malloc(strlen(inspect_info.file_name) + 8);
+               sprintf(filename, "%s-rootfs", inspect_info.file_name);
+               printf("Extracting rootfs to \"%s\"...\n", filename);
+               fp = fopen(filename, "w");
+               if (fp) {
+                       if (!fwrite(buf + ntohl(hdr->rootfs_ofs),
+                                   ntohl(hdr->rootfs_len), 1, fp)) {
+                               ERR("error in fwrite(): %s", strerror(errno));
+                       }
+                       fclose(fp);
+               } else {
+                       ERR("error in fopen(): %s", strerror(errno));
+               }
+               free(filename);
+       }
+
+ out_free_buf:
+       free(buf);
+ out:
+       return ret;
+}
+
+int main(int argc, char *argv[])
+{
+       int ret = EXIT_FAILURE;
+       int err;
+
+       FILE *outfile;
+
+       progname = basename(argv[0]);
+
+       while ( 1 ) {
+               int c;
+
+               c = getopt(argc, argv, "a:B:H:E:F:L:V:N:W:ci:k:r:R:o:xX:hsjv:");
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'a':
+                       sscanf(optarg, "0x%x", &rootfs_align);
+                       break;
+               case 'B':
+                       board_id = optarg;
+                       break;
+               case 'H':
+                       opt_hw_id = optarg;
+                       break;
+               case 'E':
+                       sscanf(optarg, "0x%x", &kernel_ep);
+                       break;
+               case 'F':
+                       layout_id = optarg;
+                       break;
+               case 'W':
+                       opt_hw_rev = optarg;
+                       break;
+               case 'L':
+                       sscanf(optarg, "0x%x", &kernel_la);
+                       break;
+               case 'V':
+                       version = optarg;
+                       break;
+               case 'v':
+                       fw_ver = optarg;
+                       break;
+               case 'N':
+                       vendor = optarg;
+                       break;
+               case 'c':
+                       combined++;
+                       break;
+               case 'k':
+                       kernel_info.file_name = optarg;
+                       break;
+               case 'r':
+                       rootfs_info.file_name = optarg;
+                       break;
+               case 'R':
+                       sscanf(optarg, "0x%x", &rootfs_ofs);
+                       break;
+               case 'o':
+                       ofname = optarg;
+                       break;
+               case 's':
+                       strip_padding = 1;
+                       break;
+               case 'i':
+                       inspect_info.file_name = optarg;
+                       break;
+               case 'j':
+                       add_jffs2_eof = 1;
+                       break;
+               case 'x':
+                       extract = 1;
+                       break;
+               case 'h':
+                       usage(EXIT_SUCCESS);
+                       break;
+               case 'X':
+                       sscanf(optarg, "0x%x", &reserved_space);
+                       break;
+               default:
+                       usage(EXIT_FAILURE);
+                       break;
+               }
+       }
+
+       ret = check_options();
+       if (ret)
+               goto out;
+
+       if (!inspect_info.file_name)
+               ret = build_fw();
+       else
+               ret = inspect_fw();
+
+ out:
+       return ret;
+}
+
diff --git a/trunk/tools/firmware-utils/src/mktplinkfw2.c b/trunk/tools/firmware-utils/src/mktplinkfw2.c
new file mode 100644 (file)
index 0000000..2e20f15
--- /dev/null
@@ -0,0 +1,977 @@
+/*
+ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This tool was based on:
+ *   TP-Link WR941 V2 firmware checksum fixing tool.
+ *   Copyright (C) 2008,2009 Wang Jian <lark@linux.net.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>     /* for unlink() */
+#include <libgen.h>
+#include <getopt.h>     /* for getopt() */
+#include <stdarg.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <endian.h>
+#include <sys/stat.h>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include "md5.h"
+
+#define ALIGN(x,a) ({ typeof(a) __a = (a); (((x) + __a - 1) & ~(__a - 1)); })
+
+#define MD5SUM_LEN     16
+
+struct file_info {
+       char            *file_name;     /* name of the file */
+       uint32_t        file_size;      /* length of the file */
+};
+
+struct fw_header {
+       uint32_t        version;        /* 0x00: header version */
+       char            fw_version[48]; /* 0x04: fw version string */
+       uint32_t        hw_id;          /* 0x34: hardware id */
+       uint32_t        hw_rev;         /* 0x38: FIXME: hardware revision? */
+       uint32_t        unk1;           /* 0x3c: 0x00000000 */
+       uint8_t         md5sum1[MD5SUM_LEN]; /* 0x40 */
+       uint32_t        unk2;           /* 0x50: 0x00000000 */
+       uint8_t         md5sum2[MD5SUM_LEN]; /* 0x54 */
+       uint32_t        unk3;           /* 0x64: 0xffffffff */
+
+       uint32_t        kernel_la;      /* 0x68: kernel load address */
+       uint32_t        kernel_ep;      /* 0x6c: kernel entry point */
+       uint32_t        fw_length;      /* 0x70: total length of the image */
+       uint32_t        kernel_ofs;     /* 0x74: kernel data offset */
+       uint32_t        kernel_len;     /* 0x78: kernel data length */
+       uint32_t        rootfs_ofs;     /* 0x7c: rootfs data offset */
+       uint32_t        rootfs_len;     /* 0x80: rootfs data length */
+       uint32_t        boot_ofs;       /* 0x84: FIXME: seems to be unused */
+       uint32_t        boot_len;       /* 0x88: FIXME: seems to be unused */
+       uint16_t        unk4;           /* 0x8c: 0x55aa */
+       uint8_t         sver_hi;        /* 0x8e */
+       uint8_t         sver_lo;        /* 0x8f */
+       uint8_t         unk5;           /* 0x90: magic: 0xa5 */
+       uint8_t         ver_hi;         /* 0x91 */
+       uint8_t         ver_mid;        /* 0x92 */
+       uint8_t         ver_lo;         /* 0x93 */
+       uint8_t         pad[364];
+} __attribute__ ((packed));
+
+struct flash_layout {
+       char            *id;
+       uint32_t        fw_max_len;
+       uint32_t        kernel_la;
+       uint32_t        kernel_ep;
+       uint32_t        rootfs_ofs;
+};
+
+struct board_info {
+       char            *id;
+       uint32_t        hw_id;
+       uint32_t        hw_rev;
+       char            *layout_id;
+       uint32_t        hdr_ver;
+       bool            endian_swap;
+};
+
+/*
+ * Globals
+ */
+static char *ofname;
+static char *progname;
+static char *vendor = "TP-LINK Technologies";
+static char *version = "ver. 1.0";
+static char *fw_ver = "0.0.0";
+static char *sver = "1.0";
+static uint32_t hdr_ver = 2;
+
+static char *board_id;
+static struct board_info *board;
+static char *layout_id;
+static struct flash_layout *layout;
+static char *opt_hw_id;
+static uint32_t hw_id;
+static char *opt_hw_rev;
+static uint32_t hw_rev;
+static int fw_ver_lo;
+static int fw_ver_mid;
+static int fw_ver_hi;
+static int sver_lo;
+static int sver_hi;
+static struct file_info kernel_info;
+static uint32_t kernel_la = 0;
+static uint32_t kernel_ep = 0;
+static uint32_t kernel_len = 0;
+static struct file_info rootfs_info;
+static uint32_t rootfs_ofs = 0;
+static uint32_t rootfs_align;
+static struct file_info boot_info;
+static int combined;
+static int strip_padding;
+static int add_jffs2_eof;
+static unsigned char jffs2_eof_mark[4] = {0xde, 0xad, 0xc0, 0xde};
+
+static struct file_info inspect_info;
+static int extract = 0;
+static bool endian_swap = false;
+
+char md5salt_normal[MD5SUM_LEN] = {
+       0xdc, 0xd7, 0x3a, 0xa5, 0xc3, 0x95, 0x98, 0xfb,
+       0xdc, 0xf9, 0xe7, 0xf4, 0x0e, 0xae, 0x47, 0x37,
+};
+
+char md5salt_boot[MD5SUM_LEN] = {
+       0x8c, 0xef, 0x33, 0x5b, 0xd5, 0xc5, 0xce, 0xfa,
+       0xa7, 0x9c, 0x28, 0xda, 0xb2, 0xe9, 0x0f, 0x42,
+};
+
+static struct flash_layout layouts[] = {
+       {
+               .id             = "8Mltq",
+               .fw_max_len     = 0x7a0000,
+               .kernel_la      = 0x80002000,
+               .kernel_ep      = 0x80002000,
+               .rootfs_ofs     = 0x140000,
+       }, {
+               .id             = "8Mmtk",
+               .fw_max_len     = 0x7a0000,
+               .kernel_la      = 0x80000000,
+               .kernel_ep      = 0x80000000,
+               .rootfs_ofs     = 0x140000,
+       }, {
+               /* terminating entry */
+       }
+};
+
+static struct board_info boards[] = {
+       {
+               .id             = "TD-W8970v1",
+               .hw_id          = 0x89700001,
+               .hw_rev         = 1,
+               .layout_id      = "8Mltq",
+       }, {
+               .id             = "ArcherC20i",
+               .hw_id          = 0xc2000001,
+               .hw_rev         = 58,
+               .layout_id      = "8Mmtk",
+               .hdr_ver        = 3,
+               .endian_swap    = true,
+       }, {
+               /* terminating entry */
+       }
+};
+
+/*
+ * Message macros
+ */
+#define ERR(fmt, ...) do { \
+       fflush(0); \
+       fprintf(stderr, "[%s] *** error: " fmt "\n", \
+                       progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERRS(fmt, ...) do { \
+       int save = errno; \
+       fflush(0); \
+       fprintf(stderr, "[%s] *** error: " fmt "\n", \
+                       progname, ## __VA_ARGS__, strerror(save)); \
+} while (0)
+
+#define DBG(fmt, ...) do { \
+       fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
+} while (0)
+
+static struct board_info *find_board(char *id)
+{
+       struct board_info *ret;
+       struct board_info *board;
+
+       ret = NULL;
+       for (board = boards; board->id != NULL; board++){
+               if (strcasecmp(id, board->id) == 0) {
+                       ret = board;
+                       break;
+               }
+       };
+
+       return ret;
+}
+
+static struct board_info *find_board_by_hwid(uint32_t hw_id)
+{
+       struct board_info *board;
+
+       for (board = boards; board->id != NULL; board++) {
+               if (hw_id == board->hw_id)
+                       return board;
+       };
+
+       return NULL;
+}
+
+static struct flash_layout *find_layout(char *id)
+{
+       struct flash_layout *ret;
+       struct flash_layout *l;
+
+       ret = NULL;
+       for (l = layouts; l->id != NULL; l++){
+               if (strcasecmp(id, l->id) == 0) {
+                       ret = l;
+                       break;
+               }
+       };
+
+       return ret;
+}
+
+static void usage(int status)
+{
+       FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+       struct board_info *board;
+
+       fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+       fprintf(stream,
+"\n"
+"Options:\n"
+"  -B <board>      create image for the board specified with <board>\n"
+"  -c              use combined kernel image\n"
+"  -E <ep>         overwrite kernel entry point with <ep> (hexval prefixed with 0x)\n"
+"  -L <la>         overwrite kernel load address with <la> (hexval prefixed with 0x)\n"
+"  -H <hwid>       use hardware id specified with <hwid>\n"
+"  -W <hwrev>      use hardware revision specified with <hwrev>\n"
+"  -F <id>         use flash layout specified with <id>\n"
+"  -k <file>       read kernel image from the file <file>\n"
+"  -r <file>       read rootfs image from the file <file>\n"
+"  -a <align>      align the rootfs start on an <align> bytes boundary\n"
+"  -R <offset>     overwrite rootfs offset with <offset> (hexval prefixed with 0x)\n"
+"  -o <file>       write output to the file <file>\n"
+"  -s              strip padding from the end of the image\n"
+"  -j              add jffs2 end-of-filesystem markers\n"
+"  -V <version>    set image version to <version>\n"
+"  -v <version>    set firmware version to <version>\n"
+"  -y <version>    set secondary version to <version>\n"
+"  -i <file>       inspect given firmware file <file>\n"
+"  -x              extract kernel and rootfs while inspecting (requires -i)\n"
+"  -h              show this screen\n"
+       );
+
+       exit(status);
+}
+
+static int get_md5(char *data, int size, char *md5)
+{
+       MD5_CTX ctx;
+
+       MD5_Init(&ctx);
+       MD5_Update(&ctx, data, size);
+       MD5_Final(md5, &ctx);
+}
+
+static int get_file_stat(struct file_info *fdata)
+{
+       struct stat st;
+       int res;
+
+       if (fdata->file_name == NULL)
+               return 0;
+
+       res = stat(fdata->file_name, &st);
+       if (res){
+               ERRS("stat failed on %s", fdata->file_name);
+               return res;
+       }
+
+       fdata->file_size = st.st_size;
+       return 0;
+}
+
+static int read_to_buf(struct file_info *fdata, char *buf)
+{
+       FILE *f;
+       int ret = EXIT_FAILURE;
+
+       f = fopen(fdata->file_name, "r");
+       if (f == NULL) {
+               ERRS("could not open \"%s\" for reading", fdata->file_name);
+               goto out;
+       }
+
+       errno = 0;
+       fread(buf, fdata->file_size, 1, f);
+       if (errno != 0) {
+               ERRS("unable to read from file \"%s\"", fdata->file_name);
+               goto out_close;
+       }
+
+       ret = EXIT_SUCCESS;
+
+ out_close:
+       fclose(f);
+ out:
+       return ret;
+}
+
+static int check_options(void)
+{
+       int ret;
+
+       if (inspect_info.file_name) {
+               ret = get_file_stat(&inspect_info);
+               if (ret)
+                       return ret;
+
+               return 0;
+       } else if (extract) {
+               ERR("no firmware for inspection specified");
+               return -1;
+       }
+
+       if (board_id == NULL && opt_hw_id == NULL) {
+               ERR("either board or hardware id must be specified");
+               return -1;
+       }
+
+       if (board_id) {
+               board = find_board(board_id);
+               if (board == NULL) {
+                       ERR("unknown/unsupported board id \"%s\"", board_id);
+                       return -1;
+               }
+               if (layout_id == NULL)
+                       layout_id = board->layout_id;
+
+               hw_id = board->hw_id;
+               hw_rev = board->hw_rev;
+               if (board->hdr_ver)
+                       hdr_ver = board->hdr_ver;
+               endian_swap = board->endian_swap;
+       } else {
+               if (layout_id == NULL) {
+                       ERR("flash layout is not specified");
+                       return -1;
+               }
+               hw_id = strtoul(opt_hw_id, NULL, 0);
+
+               if (opt_hw_rev)
+                       hw_rev = strtoul(opt_hw_rev, NULL, 0);
+               else
+                       hw_rev = 1;
+       }
+
+       layout = find_layout(layout_id);
+       if (layout == NULL) {
+               ERR("unknown flash layout \"%s\"", layout_id);
+               return -1;
+       }
+
+       if (!kernel_la)
+               kernel_la = layout->kernel_la;
+       if (!kernel_ep)
+               kernel_ep = layout->kernel_ep;
+       if (!rootfs_ofs)
+               rootfs_ofs = layout->rootfs_ofs;
+
+       if (kernel_info.file_name == NULL) {
+               ERR("no kernel image specified");
+               return -1;
+       }
+
+       ret = get_file_stat(&kernel_info);
+       if (ret)
+               return ret;
+
+       kernel_len = kernel_info.file_size;
+
+       if (combined) {
+               if (kernel_info.file_size >
+                   layout->fw_max_len - sizeof(struct fw_header)) {
+                       ERR("kernel image is too big");
+                       return -1;
+               }
+       } else {
+               if (rootfs_info.file_name == NULL) {
+                       ERR("no rootfs image specified");
+                       return -1;
+               }
+
+               ret = get_file_stat(&rootfs_info);
+               if (ret)
+                       return ret;
+
+               if (rootfs_align) {
+                       kernel_len += sizeof(struct fw_header);
+                       kernel_len = ALIGN(kernel_len, rootfs_align);
+                       kernel_len -= sizeof(struct fw_header);
+
+                       DBG("kernel length aligned to %u", kernel_len);
+
+                       if (kernel_len + rootfs_info.file_size >
+                           layout->fw_max_len - sizeof(struct fw_header)) {
+                               ERR("images are too big");
+                               return -1;
+                       }
+               } else {
+                       if (kernel_info.file_size >
+                           rootfs_ofs - sizeof(struct fw_header)) {
+                               ERR("kernel image is too big");
+                               return -1;
+                       }
+
+                       if (rootfs_info.file_size >
+                           (layout->fw_max_len - rootfs_ofs)) {
+                               ERR("rootfs image is too big");
+                               return -1;
+                       }
+               }
+       }
+
+       if (ofname == NULL) {
+               ERR("no output file specified");
+               return -1;
+       }
+
+       ret = sscanf(fw_ver, "%d.%d.%d", &fw_ver_hi, &fw_ver_mid, &fw_ver_lo);
+       if (ret != 3) {
+               ERR("invalid firmware version '%s'", fw_ver);
+               return -1;
+       }
+
+       ret = sscanf(sver, "%d.%d", &sver_hi, &sver_lo);
+       if (ret != 2) {
+               ERR("invalid secondary version '%s'", sver);
+               return -1;
+       }
+
+       return 0;
+}
+
+static void fill_header(char *buf, int len)
+{
+       struct fw_header *hdr = (struct fw_header *)buf;
+       unsigned ver_len;
+
+       memset(hdr, '\xff', sizeof(struct fw_header));
+
+       hdr->version = htonl(bswap_32(hdr_ver));
+       ver_len = strlen(version);
+       if (ver_len > (sizeof(hdr->fw_version) - 1))
+               ver_len = sizeof(hdr->fw_version) - 1;
+
+       memcpy(hdr->fw_version, version, ver_len);
+       hdr->fw_version[ver_len] = 0;
+
+       hdr->hw_id = htonl(hw_id);
+       hdr->hw_rev = htonl(hw_rev);
+
+       if (boot_info.file_size == 0) {
+               memcpy(hdr->md5sum1, md5salt_normal, sizeof(hdr->md5sum1));
+               hdr->boot_ofs = htonl(0);
+               hdr->boot_len = htonl(0);
+       } else {
+               memcpy(hdr->md5sum1, md5salt_boot, sizeof(hdr->md5sum1));
+               hdr->boot_ofs = htonl(rootfs_ofs + rootfs_info.file_size);
+               hdr->boot_len = htonl(rootfs_info.file_size);
+       }
+
+       hdr->kernel_la = htonl(kernel_la);
+       hdr->kernel_ep = htonl(kernel_ep);
+       hdr->fw_length = htonl(layout->fw_max_len);
+       hdr->kernel_ofs = htonl(sizeof(struct fw_header));
+       hdr->kernel_len = htonl(kernel_len);
+       if (!combined) {
+               hdr->rootfs_ofs = htonl(rootfs_ofs);
+               hdr->rootfs_len = htonl(rootfs_info.file_size);
+       }
+
+       hdr->boot_ofs = htonl(0);
+       hdr->boot_len = htonl(boot_info.file_size);
+
+       hdr->unk1 = htonl(0);
+       hdr->unk2 = htonl(0);
+       hdr->unk3 = htonl(0xffffffff);
+       hdr->unk4 = htons(0x55aa);
+       hdr->unk5 = 0xa5;
+
+       hdr->sver_hi = sver_hi;
+       hdr->sver_lo = sver_lo;
+
+       hdr->ver_hi = fw_ver_hi;
+       hdr->ver_mid = fw_ver_mid;
+       hdr->ver_lo = fw_ver_lo;
+
+       if (endian_swap) {
+               hdr->kernel_la = bswap_32(hdr->kernel_la);
+               hdr->kernel_ep = bswap_32(hdr->kernel_ep);
+       }
+
+       get_md5(buf, len, hdr->md5sum1);
+}
+
+static int pad_jffs2(char *buf, int currlen)
+{
+       int len;
+       uint32_t pad_mask;
+
+       len = currlen;
+       pad_mask = (64 * 1024);
+       while ((len < layout->fw_max_len) && (pad_mask != 0)) {
+               uint32_t mask;
+               int i;
+
+               for (i = 10; i < 32; i++) {
+                       mask = 1 << i;
+                       if (pad_mask & mask)
+                               break;
+               }
+
+               len = ALIGN(len, mask);
+
+               for (i = 10; i < 32; i++) {
+                       mask = 1 << i;
+                       if ((len & (mask - 1)) == 0)
+                               pad_mask &= ~mask;
+               }
+
+               for (i = 0; i < sizeof(jffs2_eof_mark); i++)
+                       buf[len + i] = jffs2_eof_mark[i];
+
+               len += sizeof(jffs2_eof_mark);
+       }
+
+       return len;
+}
+
+static int write_fw(char *data, int len)
+{
+       FILE *f;
+       int ret = EXIT_FAILURE;
+
+       f = fopen(ofname, "w");
+       if (f == NULL) {
+               ERRS("could not open \"%s\" for writing", ofname);
+               goto out;
+       }
+
+       errno = 0;
+       fwrite(data, len, 1, f);
+       if (errno) {
+               ERRS("unable to write output file");
+               goto out_flush;
+       }
+
+       DBG("firmware file \"%s\" completed", ofname);
+
+       ret = EXIT_SUCCESS;
+
+ out_flush:
+       fflush(f);
+       fclose(f);
+       if (ret != EXIT_SUCCESS) {
+               unlink(ofname);
+       }
+ out:
+       return ret;
+}
+
+static int build_fw(void)
+{
+       int buflen;
+       char *buf;
+       char *p;
+       int ret = EXIT_FAILURE;
+       int writelen = 0;
+
+       buflen = layout->fw_max_len;
+
+       buf = malloc(buflen);
+       if (!buf) {
+               ERR("no memory for buffer\n");
+               goto out;
+       }
+
+       memset(buf, 0xff, buflen);
+       p = buf + sizeof(struct fw_header);
+       ret = read_to_buf(&kernel_info, p);
+       if (ret)
+               goto out_free_buf;
+
+       writelen = sizeof(struct fw_header) + kernel_len;
+
+       if (!combined) {
+               if (rootfs_align)
+                       p = buf + writelen;
+               else
+                       p = buf + rootfs_ofs;
+
+               ret = read_to_buf(&rootfs_info, p);
+               if (ret)
+                       goto out_free_buf;
+
+               if (rootfs_align)
+                       writelen += rootfs_info.file_size;
+               else
+                       writelen = rootfs_ofs + rootfs_info.file_size;
+
+               if (add_jffs2_eof)
+                       writelen = pad_jffs2(buf, writelen);
+       }
+
+       if (!strip_padding)
+               writelen = buflen;
+
+       fill_header(buf, writelen);
+       ret = write_fw(buf, writelen);
+       if (ret)
+               goto out_free_buf;
+
+       ret = EXIT_SUCCESS;
+
+ out_free_buf:
+       free(buf);
+ out:
+       return ret;
+}
+
+/* Helper functions to inspect_fw() representing different output formats */
+static inline void inspect_fw_pstr(char *label, char *str)
+{
+       printf("%-23s: %s\n", label, str);
+}
+
+static inline void inspect_fw_phex(char *label, uint32_t val)
+{
+       printf("%-23s: 0x%08x\n", label, val);
+}
+
+static inline void inspect_fw_phexpost(char *label,
+                                       uint32_t val, char *post)
+{
+       printf("%-23s: 0x%08x (%s)\n", label, val, post);
+}
+
+static inline void inspect_fw_phexdef(char *label,
+                                      uint32_t val, uint32_t defval)
+{
+       printf("%-23s: 0x%08x                  ", label, val);
+
+       if (val == defval)
+               printf("(== libreCMC default)\n");
+       else
+               printf("(libreCMC default: 0x%08x)\n", defval);
+}
+
+static inline void inspect_fw_phexexp(char *label,
+                                      uint32_t val, uint32_t expval)
+{
+       printf("%-23s: 0x%08x ", label, val);
+
+       if (val == expval)
+               printf("(ok)\n");
+       else
+               printf("(expected: 0x%08x)\n", expval);
+}
+
+static inline void inspect_fw_phexdec(char *label, uint32_t val)
+{
+       printf("%-23s: 0x%08x / %8u bytes\n", label, val, val);
+}
+
+static inline void inspect_fw_phexdecdef(char *label,
+                                         uint32_t val, uint32_t defval)
+{
+       printf("%-23s: 0x%08x / %8u bytes ", label, val, val);
+
+       if (val == defval)
+               printf("(== libreCMC default)\n");
+       else
+               printf("(libreCMC default: 0x%08x)\n", defval);
+}
+
+static inline void inspect_fw_pmd5sum(char *label, uint8_t *val, char *text)
+{
+       int i;
+
+       printf("%-23s:", label);
+       for (i=0; i<MD5SUM_LEN; i++)
+               printf(" %02x", val[i]);
+       printf(" %s\n", text);
+}
+
+static int inspect_fw(void)
+{
+       char *buf;
+       struct fw_header *hdr;
+       uint8_t md5sum[MD5SUM_LEN];
+       struct board_info *board;
+       int ret = EXIT_FAILURE;
+
+       buf = malloc(inspect_info.file_size);
+       if (!buf) {
+               ERR("no memory for buffer!\n");
+               goto out;
+       }
+
+       ret = read_to_buf(&inspect_info, buf);
+       if (ret)
+               goto out_free_buf;
+       hdr = (struct fw_header *)buf;
+
+       inspect_fw_pstr("File name", inspect_info.file_name);
+       inspect_fw_phexdec("File size", inspect_info.file_size);
+
+       switch(bswap_32(ntohl(hdr->version))) {
+       case 2:
+       case 3:
+               break;
+       default:
+               ERR("file does not seem to have V2/V3 header!\n");
+               goto out_free_buf;
+       }
+
+       inspect_fw_phexdec("Version 2 Header size", sizeof(struct fw_header));
+
+       if (ntohl(hdr->unk1) != 0)
+               inspect_fw_phexdec("Unknown value 1", hdr->unk1);
+
+       memcpy(md5sum, hdr->md5sum1, sizeof(md5sum));
+       if (ntohl(hdr->boot_len) == 0)
+               memcpy(hdr->md5sum1, md5salt_normal, sizeof(md5sum));
+       else
+               memcpy(hdr->md5sum1, md5salt_boot, sizeof(md5sum));
+       get_md5(buf, inspect_info.file_size, hdr->md5sum1);
+
+       if (memcmp(md5sum, hdr->md5sum1, sizeof(md5sum))) {
+               inspect_fw_pmd5sum("Header MD5Sum1", md5sum, "(*ERROR*)");
+               inspect_fw_pmd5sum("          --> expected", hdr->md5sum1, "");
+       } else {
+               inspect_fw_pmd5sum("Header MD5Sum1", md5sum, "(ok)");
+       }
+       if (ntohl(hdr->unk2) != 0)
+               inspect_fw_phexdec("Unknown value 2", hdr->unk2);
+       inspect_fw_pmd5sum("Header MD5Sum2", hdr->md5sum2,
+                          "(purpose yet unknown, unchecked here)");
+
+       if (ntohl(hdr->unk3) != 0xffffffff)
+               inspect_fw_phexdec("Unknown value 3", hdr->unk3);
+
+       if (ntohs(hdr->unk4) != 0x55aa)
+               inspect_fw_phexdec("Unknown value 4", hdr->unk4);
+
+       if (hdr->unk5 != 0xa5)
+               inspect_fw_phexdec("Unknown value 5", hdr->unk5);
+
+       printf("\n");
+
+       inspect_fw_pstr("Firmware version", hdr->fw_version);
+
+       board = find_board_by_hwid(ntohl(hdr->hw_id));
+       if (board) {
+               layout = find_layout(board->layout_id);
+               inspect_fw_phexpost("Hardware ID",
+                                   ntohl(hdr->hw_id), board->id);
+               inspect_fw_phexexp("Hardware Revision",
+                                  ntohl(hdr->hw_rev), board->hw_rev);
+       } else {
+               inspect_fw_phexpost("Hardware ID",
+                                   ntohl(hdr->hw_id), "unknown");
+               inspect_fw_phex("Hardware Revision",
+                               ntohl(hdr->hw_rev));
+       }
+
+       printf("%-23s: %d.%d.%d-%d.%d\n", "Software version",
+              hdr->ver_hi, hdr->ver_mid, hdr->ver_lo,
+              hdr->sver_hi, hdr->sver_lo);
+
+       printf("\n");
+
+       inspect_fw_phexdec("Kernel data offset",
+                          ntohl(hdr->kernel_ofs));
+       inspect_fw_phexdec("Kernel data length",
+                          ntohl(hdr->kernel_len));
+       if (board) {
+               inspect_fw_phexdef("Kernel load address",
+                                  ntohl(hdr->kernel_la),
+                                  layout ? layout->kernel_la : 0xffffffff);
+               inspect_fw_phexdef("Kernel entry point",
+                                  ntohl(hdr->kernel_ep),
+                                  layout ? layout->kernel_ep : 0xffffffff);
+               inspect_fw_phexdecdef("Rootfs data offset",
+                                     ntohl(hdr->rootfs_ofs),
+                                     layout ? layout->rootfs_ofs : 0xffffffff);
+       } else {
+               inspect_fw_phex("Kernel load address",
+                               ntohl(hdr->kernel_la));
+               inspect_fw_phex("Kernel entry point",
+                               ntohl(hdr->kernel_ep));
+               inspect_fw_phexdec("Rootfs data offset",
+                                  ntohl(hdr->rootfs_ofs));
+       }
+       inspect_fw_phexdec("Rootfs data length",
+                          ntohl(hdr->rootfs_len));
+       inspect_fw_phexdec("Boot loader data offset",
+                          ntohl(hdr->boot_ofs));
+       inspect_fw_phexdec("Boot loader data length",
+                          ntohl(hdr->boot_len));
+       inspect_fw_phexdec("Total firmware length",
+                          ntohl(hdr->fw_length));
+
+       if (extract) {
+               FILE *fp;
+               char *filename;
+
+               printf("\n");
+
+               filename = malloc(strlen(inspect_info.file_name) + 8);
+               sprintf(filename, "%s-kernel", inspect_info.file_name);
+               printf("Extracting kernel to \"%s\"...\n", filename);
+               fp = fopen(filename, "w");
+               if (fp) {
+                       if (!fwrite(buf + ntohl(hdr->kernel_ofs),
+                                   ntohl(hdr->kernel_len), 1, fp)) {
+                               ERR("error in fwrite(): %s", strerror(errno));
+                       }
+                       fclose(fp);
+               } else {
+                       ERR("error in fopen(): %s", strerror(errno));
+               }
+               free(filename);
+
+               filename = malloc(strlen(inspect_info.file_name) + 8);
+               sprintf(filename, "%s-rootfs", inspect_info.file_name);
+               printf("Extracting rootfs to \"%s\"...\n", filename);
+               fp = fopen(filename, "w");
+               if (fp) {
+                       if (!fwrite(buf + ntohl(hdr->rootfs_ofs),
+                                   ntohl(hdr->rootfs_len), 1, fp)) {
+                               ERR("error in fwrite(): %s", strerror(errno));
+                       }
+                       fclose(fp);
+               } else {
+                       ERR("error in fopen(): %s", strerror(errno));
+               }
+               free(filename);
+       }
+
+ out_free_buf:
+       free(buf);
+ out:
+       return ret;
+}
+
+int main(int argc, char *argv[])
+{
+       int ret = EXIT_FAILURE;
+       int err;
+
+       FILE *outfile;
+
+       progname = basename(argv[0]);
+
+       while ( 1 ) {
+               int c;
+
+               c = getopt(argc, argv, "a:B:H:E:F:L:V:N:W:ci:k:r:R:o:xhsjv:y:T:e");
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'a':
+                       sscanf(optarg, "0x%x", &rootfs_align);
+                       break;
+               case 'B':
+                       board_id = optarg;
+                       break;
+               case 'H':
+                       opt_hw_id = optarg;
+                       break;
+               case 'E':
+                       sscanf(optarg, "0x%x", &kernel_ep);
+                       break;
+               case 'F':
+                       layout_id = optarg;
+                       break;
+               case 'W':
+                       opt_hw_rev = optarg;
+                       break;
+               case 'L':
+                       sscanf(optarg, "0x%x", &kernel_la);
+                       break;
+               case 'V':
+                       version = optarg;
+                       break;
+               case 'v':
+                       fw_ver = optarg;
+                       break;
+               case 'y':
+                       sver = optarg;
+                       break;
+               case 'N':
+                       vendor = optarg;
+                       break;
+               case 'c':
+                       combined++;
+                       break;
+               case 'k':
+                       kernel_info.file_name = optarg;
+                       break;
+               case 'r':
+                       rootfs_info.file_name = optarg;
+                       break;
+               case 'R':
+                       sscanf(optarg, "0x%x", &rootfs_ofs);
+                       break;
+               case 'o':
+                       ofname = optarg;
+                       break;
+               case 's':
+                       strip_padding = 1;
+                       break;
+               case 'i':
+                       inspect_info.file_name = optarg;
+                       break;
+               case 'j':
+                       add_jffs2_eof = 1;
+                       break;
+               case 'x':
+                       extract = 1;
+                       break;
+               case 'T':
+                       hdr_ver = atoi(optarg);
+                       break;
+               case 'e':
+                       endian_swap = true;
+                       break;
+               case 'h':
+                       usage(EXIT_SUCCESS);
+                       break;
+               default:
+                       usage(EXIT_FAILURE);
+                       break;
+               }
+       }
+
+       ret = check_options();
+       if (ret)
+               goto out;
+
+       if (!inspect_info.file_name)
+               ret = build_fw();
+       else
+               ret = inspect_fw();
+
+ out:
+       return ret;
+}
+
diff --git a/trunk/tools/firmware-utils/src/mkwrgimg.c b/trunk/tools/firmware-utils/src/mkwrgimg.c
new file mode 100644 (file)
index 0000000..3915d14
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ *  Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <libgen.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include "md5.h"
+
+#define ERR(fmt, ...) do { \
+       fflush(0); \
+       fprintf(stderr, "[%s] *** error: " fmt "\n", \
+                       progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERRS(fmt, ...) do { \
+       int save = errno; \
+       fflush(0); \
+       fprintf(stderr, "[%s] *** error: " fmt ", %s\n", \
+                       progname, ## __VA_ARGS__, strerror(save)); \
+} while (0)
+
+#define WRG_MAGIC      0x20040220
+
+struct wrg_header {
+       char            signature[32];
+       uint32_t        magic1;
+       uint32_t        magic2;
+       uint32_t        size;
+       uint32_t        offset;
+       char            devname[32];
+       char            digest[16];
+} __attribute__ ((packed));
+
+static char *progname;
+static char *ifname;
+static char *ofname;
+static char *signature;
+static char *dev_name;
+static uint32_t offset;
+static int big_endian;
+
+void usage(int status)
+{
+       FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+
+       fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+       fprintf(stream,
+"\n"
+"Options:\n"
+"  -b              create image in big endian format\n"
+"  -i <file>       read input from the file <file>\n"
+"  -d <name>       set device name to <name>\n"
+"  -o <file>       write output to the file <file>\n"
+"  -O <offset>     set offset to <offset>\n"
+"  -s <sig>        set image signature to <sig>\n"
+"  -h              show this screen\n"
+       );
+
+       exit(status);
+}
+
+static void put_u32(void *data, uint32_t val)
+{
+       unsigned char *p = data;
+
+       if (big_endian) {
+               p[0] = (val >> 24) & 0xff;
+               p[1] = (val >> 16) & 0xff;
+               p[2] = (val >> 8) & 0xff;
+               p[3] = val & 0xff;
+       } else {
+               p[3] = (val >> 24) & 0xff;
+               p[2] = (val >> 16) & 0xff;
+               p[1] = (val >> 8) & 0xff;
+               p[0] = val & 0xff;
+       }
+}
+
+static void get_digest(struct wrg_header *header, char *data, int size)
+{
+       MD5_CTX ctx;
+
+       MD5_Init(&ctx);
+
+       MD5_Update(&ctx, (char *)&header->offset, sizeof(header->offset));
+       MD5_Update(&ctx, (char *)&header->devname, sizeof(header->devname));
+       MD5_Update(&ctx, data, size);
+
+       MD5_Final(header->digest, &ctx);
+}
+
+int main(int argc, char *argv[])
+{
+       struct wrg_header *header;
+       char *buf;
+       struct stat st;
+       int buflen;
+       int err;
+       int res = EXIT_FAILURE;
+
+       FILE *outfile, *infile;
+
+       progname = basename(argv[0]);
+
+       while ( 1 ) {
+               int c;
+
+               c = getopt(argc, argv, "bd:i:o:s:O:h");
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'b':
+                       big_endian = 1;
+                       break;
+               case 'd':
+                       dev_name = optarg;
+                       break;
+               case 'i':
+                       ifname = optarg;
+                       break;
+               case 'o':
+                       ofname = optarg;
+                       break;
+               case 's':
+                       signature = optarg;
+                       break;
+               case 'O':
+                       offset = strtoul(optarg, NULL, 0);
+                       break;
+               case 'h':
+                       usage(EXIT_SUCCESS);
+                       break;
+
+               default:
+                       usage(EXIT_FAILURE);
+                       break;
+               }
+       }
+
+       if (signature == NULL) {
+               ERR("no signature specified");
+               goto err;
+       }
+
+       if (ifname == NULL) {
+               ERR("no input file specified");
+               goto err;
+       }
+
+       if (ofname == NULL) {
+               ERR("no output file specified");
+               goto err;
+       }
+
+       if (dev_name == NULL) {
+               ERR("no device name specified");
+               goto err;
+       }
+
+       err = stat(ifname, &st);
+       if (err){
+               ERRS("stat failed on %s", ifname);
+               goto err;
+       }
+
+       buflen = st.st_size + sizeof(struct wrg_header);
+       buf = malloc(buflen);
+       if (!buf) {
+               ERR("no memory for buffer\n");
+               goto err;
+       }
+
+       infile = fopen(ifname, "r");
+       if (infile == NULL) {
+               ERRS("could not open \"%s\" for reading", ifname);
+               goto err_free;
+       }
+
+       errno = 0;
+       fread(buf + sizeof(struct wrg_header), st.st_size, 1, infile);
+       if (errno != 0) {
+               ERRS("unable to read from file %s", ifname);
+               goto close_in;
+       }
+
+       header = (struct wrg_header *) buf;
+       memset(header, '\0', sizeof(struct wrg_header));
+
+       strncpy(header->signature, signature, sizeof(header->signature));
+       strncpy(header->devname, dev_name, sizeof(header->signature));
+       put_u32(&header->magic1, WRG_MAGIC);
+       put_u32(&header->magic2, WRG_MAGIC);
+       put_u32(&header->size, st.st_size);
+       put_u32(&header->offset, offset);
+
+       get_digest(header, buf + sizeof(struct wrg_header), st.st_size);
+
+       outfile = fopen(ofname, "w");
+       if (outfile == NULL) {
+               ERRS("could not open \"%s\" for writing", ofname);
+               goto close_in;
+       }
+
+       errno = 0;
+       fwrite(buf, buflen, 1, outfile);
+       if (errno) {
+               ERRS("unable to write to file %s", ofname);
+               goto close_out;
+       }
+
+       fflush(outfile);
+
+       res = EXIT_SUCCESS;
+
+close_out:
+       fclose(outfile);
+       if (res != EXIT_SUCCESS)
+               unlink(ofname);
+close_in:
+       fclose(infile);
+err_free:
+       free(buf);
+err:
+       return res;
+}
diff --git a/trunk/tools/firmware-utils/src/mkzcfw.c b/trunk/tools/firmware-utils/src/mkzcfw.c
new file mode 100644 (file)
index 0000000..7674e70
--- /dev/null
@@ -0,0 +1,408 @@
+/*
+ * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>     /* for unlink() */
+#include <libgen.h>
+#include <getopt.h>     /* for getopt() */
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include "cyg_crc.h"
+
+#if (__BYTE_ORDER == __BIG_ENDIAN)
+#  define HOST_TO_BE32(x)      (x)
+#  define BE32_TO_HOST(x)      (x)
+#  define HOST_TO_LE32(x)      bswap_32(x)
+#  define LE32_TO_HOST(x)      bswap_32(x)
+#else
+#  define HOST_TO_BE32(x)      bswap_32(x)
+#  define BE32_TO_HOST(x)      bswap_32(x)
+#  define HOST_TO_LE32(x)      (x)
+#  define LE32_TO_HOST(x)      (x)
+#endif
+
+#define MAGIC_FIRMWARE 0x6d726966      /* 'firm' */
+#define MAGIC_KERNEL   0x676d694b      /* 'Kimg' */
+#define MAGIC_ROOTFS   0x676d6952      /* 'Rimg' */
+
+struct file_info {
+       char            *file_name;     /* name of the file */
+       uint32_t        file_size;      /* length of the file */
+};
+
+struct fw_header {
+       uint32_t        magic;
+       uint32_t        length;
+       uint32_t        unk1;
+       uint32_t        unk2;
+} __attribute__ ((packed));
+
+struct fw_tail {
+       uint32_t        hw_id;
+       uint32_t        crc;
+} __attribute__ ((packed));
+
+struct board_info {
+       char            *id;
+       uint32_t        hw_id;
+       uint32_t        kernel_len;
+       uint32_t        rootfs_len;
+};
+
+/*
+ * Globals
+ */
+static char *ofname;
+static char *progname;
+
+static char *board_id;
+static struct board_info *board;
+static struct file_info kernel_info;
+static struct file_info rootfs_info;
+
+
+static struct board_info boards[] = {
+       {
+               .id             = "ZCN-1523H-2-8",
+               .hw_id          = 0x66661523,
+               .kernel_len     = 0x170000,
+               .rootfs_len     = 0x610000,
+       }, {
+               .id             = "ZCN-1523H-5-16",
+               .hw_id          = 0x6615235A,
+               .kernel_len     = 0x170000,
+               .rootfs_len     = 0x610000,
+       }, {
+               /* terminating entry */
+       }
+};
+
+/*
+ * Message macros
+ */
+#define ERR(fmt, ...) do { \
+       fflush(0); \
+       fprintf(stderr, "[%s] *** error: " fmt "\n", \
+                       progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERRS(fmt, ...) do { \
+       int save = errno; \
+       fflush(0); \
+       fprintf(stderr, "[%s] *** error: " fmt "\n", \
+                       progname, ## __VA_ARGS__, strerror(save)); \
+} while (0)
+
+#define DBG(fmt, ...) do { \
+       fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
+} while (0)
+
+static struct board_info *find_board(char *id)
+{
+       struct board_info *ret;
+       struct board_info *board;
+
+       ret = NULL;
+       for (board = boards; board->id != NULL; board++){
+               if (strcasecmp(id, board->id) == 0) {
+                       ret = board;
+                       break;
+               }
+       };
+
+       return ret;
+}
+
+static void usage(int status)
+{
+       FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+       struct board_info *board;
+
+       fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+       fprintf(stream,
+"\n"
+"Options:\n"
+"  -B <board>      create image for the board specified with <board>\n"
+"  -k <file>       read kernel image from the file <file>\n"
+"  -r <file>       read rootfs image from the file <file>\n"
+"  -o <file>       write output to the file <file>\n"
+"  -h              show this screen\n"
+       );
+
+       exit(status);
+}
+
+static int get_file_stat(struct file_info *fdata)
+{
+       struct stat st;
+       int res;
+
+       if (fdata->file_name == NULL)
+               return 0;
+
+       res = stat(fdata->file_name, &st);
+       if (res){
+               ERRS("stat failed on %s", fdata->file_name);
+               return res;
+       }
+
+       fdata->file_size = st.st_size;
+       return 0;
+}
+
+static int read_to_buf(struct file_info *fdata, char *buf)
+{
+       FILE *f;
+       int ret = EXIT_FAILURE;
+
+       f = fopen(fdata->file_name, "r");
+       if (f == NULL) {
+               ERRS("could not open \"%s\" for reading", fdata->file_name);
+               goto out;
+       }
+
+       errno = 0;
+       fread(buf, fdata->file_size, 1, f);
+       if (errno != 0) {
+               ERRS("unable to read from file \"%s\"", fdata->file_name);
+               goto out_close;
+       }
+
+       ret = EXIT_SUCCESS;
+
+ out_close:
+       fclose(f);
+ out:
+       return ret;
+}
+
+static int check_options(void)
+{
+       int ret;
+
+       if (board_id == NULL) {
+               ERR("no board specified");
+               return -1;
+       }
+
+       board = find_board(board_id);
+       if (board == NULL) {
+               ERR("unknown/unsupported board id \"%s\"", board_id);
+               return -1;
+       }
+
+       if (kernel_info.file_name == NULL) {
+               ERR("no kernel image specified");
+               return -1;
+       }
+
+       ret = get_file_stat(&kernel_info);
+       if (ret)
+               return ret;
+
+       if (kernel_info.file_size > board->kernel_len) {
+               ERR("kernel image is too big");
+               return -1;
+       }
+
+       if (rootfs_info.file_name == NULL) {
+               ERR("no rootfs image specified");
+               return -1;
+       }
+
+       ret = get_file_stat(&rootfs_info);
+       if (ret)
+               return ret;
+
+       if (rootfs_info.file_size > board->rootfs_len) {
+               ERR("rootfs image is too big");
+               return -1;
+       }
+
+       if (ofname == NULL) {
+               ERR("no output file specified");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int write_fw(char *data, int len)
+{
+       FILE *f;
+       int ret = EXIT_FAILURE;
+
+       f = fopen(ofname, "w");
+       if (f == NULL) {
+               ERRS("could not open \"%s\" for writing", ofname);
+               goto out;
+       }
+
+       errno = 0;
+       fwrite(data, len, 1, f);
+       if (errno) {
+               ERRS("unable to write output file");
+               goto out_flush;
+       }
+
+       DBG("firmware file \"%s\" completed", ofname);
+
+       ret = EXIT_SUCCESS;
+
+ out_flush:
+       fflush(f);
+       fclose(f);
+       if (ret != EXIT_SUCCESS) {
+               unlink(ofname);
+       }
+ out:
+       return ret;
+}
+
+static int build_fw(void)
+{
+       int buflen;
+       char *buf;
+       char *p;
+       int ret = EXIT_FAILURE;
+       int writelen = 0;
+       uint32_t crc;
+       struct fw_header *hdr;
+       struct fw_tail *tail;
+
+       buflen = 3 * sizeof(struct fw_header) +
+                kernel_info.file_size + rootfs_info.file_size +
+                3 * sizeof(struct fw_tail);
+
+       buf = malloc(buflen);
+       if (!buf) {
+               ERR("no memory for buffer\n");
+               goto out;
+       }
+
+       p = buf;
+       memset(p, 0, buflen);
+
+       /* fill firmware header */
+       hdr = (struct fw_header *) p;
+       hdr->magic = HOST_TO_LE32(MAGIC_FIRMWARE);
+       hdr->length = HOST_TO_LE32(buflen - sizeof(struct fw_header));
+       p += sizeof(struct fw_header);
+
+       /* fill kernel block header */
+       hdr = (struct fw_header *) p;
+       hdr->magic = HOST_TO_LE32(MAGIC_KERNEL);
+       hdr->length = HOST_TO_LE32(kernel_info.file_size +
+                                  sizeof(struct fw_tail));
+       p += sizeof(struct fw_header);
+
+       /* read kernel data */
+       ret = read_to_buf(&kernel_info, p);
+       if (ret)
+               goto out_free_buf;
+
+       /* fill firmware tail */
+       tail = (struct fw_tail *) (p + kernel_info.file_size);
+       tail->hw_id = HOST_TO_BE32(board->hw_id);
+       tail->crc = HOST_TO_BE32(cyg_crc32(p, kernel_info.file_size +
+                                          sizeof(struct fw_tail) - 4));
+
+       p += kernel_info.file_size + sizeof(struct fw_tail);
+
+       /* fill rootfs block header */
+       hdr = (struct fw_header *) p;
+       hdr->magic = HOST_TO_LE32(MAGIC_ROOTFS);
+       hdr->length = HOST_TO_LE32(rootfs_info.file_size +
+                                  sizeof(struct fw_tail));
+       p += sizeof(struct fw_header);
+
+       /* read rootfs data */
+       ret = read_to_buf(&rootfs_info, p);
+       if (ret)
+               goto out_free_buf;
+
+       /* fill firmware tail */
+       tail = (struct fw_tail *) (p + rootfs_info.file_size);
+       tail->hw_id = HOST_TO_BE32(board->hw_id);
+       tail->crc = HOST_TO_BE32(cyg_crc32(p, rootfs_info.file_size +
+                                          sizeof(struct fw_tail) - 4));
+
+       p += rootfs_info.file_size + sizeof(struct fw_tail);
+
+       /* fill firmware tail */
+       tail = (struct fw_tail *) p;
+       tail->hw_id = HOST_TO_BE32(board->hw_id);
+       tail->crc = HOST_TO_BE32(cyg_crc32(buf + sizeof(struct fw_header),
+                                buflen - sizeof(struct fw_header) - 4));
+
+       ret = write_fw(buf, buflen);
+       if (ret)
+               goto out_free_buf;
+
+       ret = EXIT_SUCCESS;
+
+ out_free_buf:
+       free(buf);
+ out:
+       return ret;
+}
+
+int main(int argc, char *argv[])
+{
+       int ret = EXIT_FAILURE;
+       int err;
+
+       FILE *outfile;
+
+       progname = basename(argv[0]);
+
+       while ( 1 ) {
+               int c;
+
+               c = getopt(argc, argv, "B:k:r:o:h");
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'B':
+                       board_id = optarg;
+                       break;
+               case 'k':
+                       kernel_info.file_name = optarg;
+                       break;
+               case 'r':
+                       rootfs_info.file_name = optarg;
+                       break;
+               case 'o':
+                       ofname = optarg;
+                       break;
+               case 'h':
+                       usage(EXIT_SUCCESS);
+                       break;
+               default:
+                       usage(EXIT_FAILURE);
+                       break;
+               }
+       }
+
+       ret = check_options();
+       if (ret)
+               goto out;
+
+       ret = build_fw();
+
+ out:
+       return ret;
+}
+
diff --git a/trunk/tools/firmware-utils/src/mkzynfw.c b/trunk/tools/firmware-utils/src/mkzynfw.c
new file mode 100644 (file)
index 0000000..58be075
--- /dev/null
@@ -0,0 +1,1130 @@
+/*
+ *
+ *  Copyright (C) 2007-2008 OpenWrt.org
+ *  Copyright (C) 2007-2008 Gabor Juhos <juhosg at librecmc.org>
+ *
+ *  This code was based on the information of the ZyXEL's firmware
+ *  image format written by Kolja Waschk, can be found at:
+ *  http://www.ixo.de/info/zyxel_uclinux
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>    /* for unlink() */
+#include <libgen.h>
+#include <getopt.h>    /* for getopt() */
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <endian.h>    /* for __BYTE_ORDER */
+#if defined(__CYGWIN__)
+#  include <byteswap.h>
+#endif
+
+#include "zynos.h"
+
+#if (__BYTE_ORDER == __LITTLE_ENDIAN)
+#  define HOST_TO_LE16(x)      (x)
+#  define HOST_TO_LE32(x)      (x)
+#  define LE16_TO_HOST(x)      (x)
+#  define LE32_TO_HOST(x)      (x)
+#  define HOST_TO_BE16(x)      bswap_16(x)
+#  define HOST_TO_BE32(x)      bswap_32(x)
+#  define BE16_TO_HOST(x)      bswap_16(x)
+#  define BE32_TO_HOST(x)      bswap_32(x)
+#else
+#  define HOST_TO_BE16(x)      (x)
+#  define HOST_TO_BE32(x)      (x)
+#  define BE16_TO_HOST(x)      (x)
+#  define BE32_TO_HOST(x)      (x)
+#  define HOST_TO_LE16(x)      bswap_16(x)
+#  define HOST_TO_LE32(x)      bswap_32(x)
+#  define LE16_TO_HOST(x)      bswap_16(x)
+#  define LE32_TO_HOST(x)      bswap_32(x)
+#endif
+
+#define ALIGN(x,y)     (((x)+((y)-1)) & ~((y)-1))
+
+#define MAX_NUM_BLOCKS 8
+#define MAX_ARG_COUNT  32
+#define MAX_ARG_LEN    1024
+#define FILE_BUF_LEN   (16*1024)
+
+
+struct csum_state{
+       int             odd;
+       uint32_t        sum;
+       uint32_t        tmp;
+};
+
+struct fw_block {
+       uint32_t        align;          /* alignment of this block */
+       char            *file_name;     /* name of the file */
+       uint32_t        file_size;      /* length of the file */
+       char            *mmap_name;     /* name in the MMAP table */
+       int             type;           /* block type */
+       uint32_t        padlen;
+       uint8_t         padc;
+};
+
+#define BLOCK_TYPE_BOOTEXT     0
+#define BLOCK_TYPE_RAW         1
+
+struct fw_mmap {
+       uint32_t        addr;
+       uint32_t        size;
+       uint32_t        user_addr;
+       uint32_t        user_size;
+};
+#define MMAP_DATA_SIZE 1024
+#define MMAP_ALIGN     16
+
+struct board_info {
+       char *name;             /* model name */
+       char *desc;             /* description */
+       uint16_t vendor;        /* vendor id */
+       uint16_t model;         /* model id */
+       uint32_t flash_base;    /* flash base address */
+       uint32_t flash_size;    /* board flash size */
+       uint32_t code_start;    /* code start address */
+       uint32_t romio_offs;    /* offset of the firmware within the flash */
+       uint32_t bootext_size;  /* maximum size of bootext block */
+};
+
+/*
+ * Globals
+ */
+char *progname;
+char *ofname = NULL;
+int verblevel = 0;
+
+struct board_info *board = NULL;
+
+struct fw_block blocks[MAX_NUM_BLOCKS];
+struct fw_block *bootext_block = NULL;
+int num_blocks = 0;
+
+#define ADM5120_FLASH_BASE     0xBFC00000
+#define ADM5120_CODE_START     0x80008000
+
+/* TODO: check values for AR7 */
+#define AR7_FLASH_BASE         0xB0000000
+#define AR7_CODE_START         0x94008000
+
+#define ATHEROS_FLASH_BASE     0xBFC00000
+#define ATHEROS_CODE_START     0x80e00000
+
+#define AR71XX_FLASH_BASE      0xBFC00000
+#define AR71XX_CODE_START      0x81E00000
+
+#define BOARD(n, d, v, m, fb, fs, cs, fo) {            \
+       .name = (n), .desc=(d),                         \
+       .vendor = (v), .model = (m),                    \
+       .flash_base = (fb), .flash_size = (fs)<<20,     \
+       .code_start = (cs), .romio_offs = (fo),         \
+       .bootext_size = BOOTEXT_DEF_SIZE                \
+       }
+
+#define ADMBOARD1(n, d, m, fs) BOARD(n, d, ZYNOS_VENDOR_ID_ZYXEL, m, \
+       ADM5120_FLASH_BASE, fs, ADM5120_CODE_START, 0x8000)
+
+#define ADMBOARD2(n, d, m, fs) BOARD(n, d, ZYNOS_VENDOR_ID_ZYXEL, m, \
+       ADM5120_FLASH_BASE, fs, ADM5120_CODE_START, 0x10000)
+
+#define AR7BOARD1(n, d, m, fs) BOARD(n, d, ZYNOS_VENDOR_ID_ZYXEL, m, \
+       AR7_FLASH_BASE, fs, AR7_CODE_START, 0x8000)
+
+#define ATHEROSBOARD1(n, d, m, fs) BOARD(n, d, ZYNOS_VENDOR_ID_ZYXEL, m, \
+       ATHEROS_FLASH_BASE, fs, ATHEROS_CODE_START, 0x30000)
+
+#define AR71XXBOARD1(n, d, m, fs) {            \
+       .name = (n), .desc=(d),                         \
+       .vendor = (ZYNOS_VENDOR_ID_ZYXEL), .model = (m),                        \
+       .flash_base = (AR71XX_FLASH_BASE), .flash_size = (fs)<<20,      \
+       .code_start = (AR71XX_CODE_START), .romio_offs = (0x40000),             \
+       .bootext_size = 0x30000         \
+       }
+
+
+static struct board_info boards[] = {
+       /*
+        * Infineon/ADMtek ADM5120 based boards
+        */
+       ADMBOARD2("ES-2024A",   "ZyXEL ES-2024A", ZYNOS_MODEL_ES_2024A, 4),
+       ADMBOARD2("ES-2024PWR", "ZyXEL ES-2024PWR", ZYNOS_MODEL_ES_2024PWR, 4),
+       ADMBOARD2("ES-2108",    "ZyXEL ES-2108", ZYNOS_MODEL_ES_2108, 4),
+       ADMBOARD2("ES-2108-F",  "ZyXEL ES-2108-F", ZYNOS_MODEL_ES_2108_F, 4),
+       ADMBOARD2("ES-2108-G",  "ZyXEL ES-2108-G", ZYNOS_MODEL_ES_2108_G, 4),
+       ADMBOARD2("ES-2108-LC", "ZyXEL ES-2108-LC", ZYNOS_MODEL_ES_2108_LC, 4),
+       ADMBOARD2("ES-2108PWR", "ZyXEL ES-2108PWR", ZYNOS_MODEL_ES_2108PWR, 4),
+       ADMBOARD1("HS-100",     "ZyXEL HomeSafe 100", ZYNOS_MODEL_HS_100, 2),
+       ADMBOARD1("HS-100W",    "ZyXEL HomeSafe 100W", ZYNOS_MODEL_HS_100W, 2),
+       ADMBOARD1("P-334",      "ZyXEL Prestige 334", ZYNOS_MODEL_P_334, 2),
+       ADMBOARD1("P-334U",     "ZyXEL Prestige 334U", ZYNOS_MODEL_P_334U, 4),
+       ADMBOARD1("P-334W",     "ZyXEL Prestige 334W", ZYNOS_MODEL_P_334W, 2),
+       ADMBOARD1("P-334WH",    "ZyXEL Prestige 334WH", ZYNOS_MODEL_P_334WH, 4),
+       ADMBOARD1("P-334WHD",   "ZyXEL Prestige 334WHD", ZYNOS_MODEL_P_334WHD, 4),
+       ADMBOARD1("P-334WT",    "ZyXEL Prestige 334WT", ZYNOS_MODEL_P_334WT, 4),
+       ADMBOARD1("P-335",      "ZyXEL Prestige 335", ZYNOS_MODEL_P_335, 4),
+       ADMBOARD1("P-335Plus",  "ZyXEL Prestige 335Plus", ZYNOS_MODEL_P_335PLUS, 4),
+       ADMBOARD1("P-335U",     "ZyXEL Prestige 335U", ZYNOS_MODEL_P_335U, 4),
+       ADMBOARD1("P-335WT",    "ZyXEL Prestige 335WT", ZYNOS_MODEL_P_335WT, 4),
+
+       {
+               .name           = "P-2602HW-D1A",
+               .desc           = "ZyXEL P-2602HW-D1A",
+               .vendor         = ZYNOS_VENDOR_ID_ZYXEL,
+               .model          = ZYNOS_MODEL_P_2602HW_D1A,
+               .flash_base     = AR7_FLASH_BASE,
+               .flash_size     = 4*1024*1024,
+               .code_start     = 0x94008000,
+               .romio_offs     = 0x20000,
+               .bootext_size   = BOOTEXT_DEF_SIZE,
+       },
+
+#if 0
+       /*
+        * Texas Instruments AR7 based boards
+        */
+       AR7BOARD1("P-660H-61",  "ZyXEL P-660H-61", ZYNOS_MODEL_P_660H_61, 2),
+       AR7BOARD1("P-660H-63",  "ZyXEL P-660H-63", ZYNOS_MODEL_P_660H_63, 2),
+       AR7BOARD1("P-660H-D1",  "ZyXEL P-660H-D1", ZYNOS_MODEL_P_660H_D1, 2),
+       AR7BOARD1("P-660H-D3",  "ZyXEL P-660H-D3", ZYNOS_MODEL_P_660H_D3, 2),
+       AR7BOARD1("P-660HW-61", "ZyXEL P-660HW-61", ZYNOS_MODEL_P_660HW_61, 2),
+       AR7BOARD1("P-660HW-63", "ZyXEL P-660HW-63", ZYNOS_MODEL_P_660HW_63, 2),
+       AR7BOARD1("P-660HW-67", "ZyXEL P-660HW-67", ZYNOS_MODEL_P_660HW_67, 2),
+       AR7BOARD1("P-660HW-D1", "ZyXEL P-660HW-D1", ZYNOS_MODEL_P_660HW_D1, 2),
+       AR7BOARD1("P-660HW-D3", "ZyXEL P-660HW-D3", ZYNOS_MODEL_P_660HW_D3, 2),
+       AR7BOARD1("P-660R-61",  "ZyXEL P-660R-61", ZYNOS_MODEL_P_660R_61, 2),
+       AR7BOARD1("P-660R-61C", "ZyXEL P-660R-61C", ZYNOS_MODEL_P_660R_61C, 2),
+       AR7BOARD1("P-660R-63",  "ZyXEL P-660R-63", ZYNOS_MODEL_P_660R_63, 2),
+       AR7BOARD1("P-660R-63C", "ZyXEL P-660R-63C", ZYNOS_MODEL_P_660R_63C, 2),
+       AR7BOARD1("P-660R-67",  "ZyXEL P-660R-67", ZYNOS_MODEL_P_660R_67, 2),
+       AR7BOARD1("P-660R-D1",  "ZyXEL P-660R-D1", ZYNOS_MODEL_P_660R_D1, 2),
+       AR7BOARD1("P-660R-D3",  "ZyXEL P-660R-D3", ZYNOS_MODEL_P_660R_D3, 2),
+#endif
+       {
+               .name           = "O2SURF",
+               .desc           = "O2 DSL Surf & Phone",
+               .vendor         = ZYNOS_VENDOR_ID_O2,
+               .model          = ZYNOS_MODEL_O2SURF,
+               .flash_base     = AR7_FLASH_BASE,
+               .flash_size     = 8*1024*1024,
+               .code_start     = 0x94014000,
+               .romio_offs     = 0x40000,
+               .bootext_size   = BOOTEXT_DEF_SIZE,
+       },
+
+       /*
+:x
+        */
+       ATHEROSBOARD1("NBG-318S", "ZyXEL NBG-318S", ZYNOS_MODEL_NBG_318S, 4),
+
+       /*
+        * Atheros ar71xx based boards
+        */
+       AR71XXBOARD1("NBG-460N", "ZyXEL NBG-460N", ZYNOS_MODEL_NBG_460N, 4),
+
+       {.name = NULL}
+};
+
+/*
+ * Message macros
+ */
+#define ERR(fmt, ...) do { \
+       fflush(0); \
+       fprintf(stderr, "[%s] *** error: " fmt "\n", \
+                       progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERRS(fmt, ...) do { \
+       int save = errno; \
+       fflush(0); \
+       fprintf(stderr, "[%s] *** error: " fmt ", %s\n", \
+                       progname, ## __VA_ARGS__, strerror(save)); \
+} while (0)
+
+#define WARN(fmt, ...) do { \
+       fprintf(stderr, "[%s] *** warning: " fmt "\n", \
+                       progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define DBG(lev, fmt, ...) do { \
+       if (verblevel < lev) \
+               break;\
+       fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERR_FATAL              -1
+#define ERR_INVALID_IMAGE      -2
+
+/*
+ * Helper routines
+ */
+void
+usage(int status)
+{
+       FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+       struct board_info *board;
+
+       fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+       fprintf(stream,
+"\n"
+"Options:\n"
+"  -B <board>      create image for the board specified with <board>.\n"
+"                  valid <board> values:\n"
+       );
+       for (board = boards; board->name != NULL; board++){
+               fprintf(stream,
+"                    %-12s= %s\n",
+                board->name, board->desc);
+       };
+       fprintf(stream,
+"  -b <file>[:<align>]\n"
+"                  add boot extension block to the image\n"
+"  -r <file>[:<align>]\n"
+"                  add raw block to the image\n"
+"  -o <file>       write output to the file <file>\n"
+"  -h              show this screen\n"
+       );
+
+       exit(status);
+}
+
+
+/*
+ * argument parsing
+ */
+int
+str2u32(char *arg, uint32_t *val)
+{
+       char *err = NULL;
+       uint32_t t;
+
+       errno=0;
+       t = strtoul(arg, &err, 0);
+       if (errno || (err==arg) || ((err != NULL) && *err)) {
+               return -1;
+       }
+
+       *val = t;
+       return 0;
+}
+
+
+int
+str2u16(char *arg, uint16_t *val)
+{
+       char *err = NULL;
+       uint32_t t;
+
+       errno=0;
+       t = strtoul(arg, &err, 0);
+       if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x10000)) {
+               return -1;
+       }
+
+       *val = t & 0xFFFF;
+       return 0;
+}
+
+int
+str2u8(char *arg, uint8_t *val)
+{
+       char *err = NULL;
+       uint32_t t;
+
+       errno=0;
+       t = strtoul(arg, &err, 0);
+       if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x100)) {
+               return -1;
+       }
+
+       *val = t & 0xFF;
+       return 0;
+}
+
+int
+str2sig(char *arg, uint32_t *sig)
+{
+       if (strlen(arg) != 4)
+               return -1;
+
+       *sig = arg[0] | (arg[1] << 8) | (arg[2] << 16) | (arg[3] << 24);
+
+       return 0;
+}
+
+
+int
+parse_arg(char *arg, char *buf, char *argv[])
+{
+       int res = 0;
+       size_t argl;
+       char *tok;
+       char **ap = &buf;
+       int i;
+
+       memset(argv, 0, MAX_ARG_COUNT * sizeof(void *));
+
+       if ((arg == NULL)) {
+               /* no arguments */
+               return 0;
+       }
+
+       argl = strlen(arg);
+       if (argl == 0) {
+               /* no arguments */
+               return 0;
+       }
+
+       if (argl >= MAX_ARG_LEN) {
+               /* argument is too long */
+               argl = MAX_ARG_LEN-1;
+       }
+
+       memcpy(buf, arg, argl);
+       buf[argl] = '\0';
+
+       for (i = 0; i < MAX_ARG_COUNT; i++) {
+               tok = strsep(ap, ":");
+               if (tok == NULL) {
+                       break;
+               }
+#if 0
+               else if (tok[0] == '\0') {
+                       break;
+               }
+#endif
+               argv[i] = tok;
+               res++;
+       }
+
+       return res;
+}
+
+
+int
+required_arg(char c, char *arg)
+{
+       if (arg == NULL || *arg != '-')
+               return 0;
+
+       ERR("option -%c requires an argument\n", c);
+       return -1;
+}
+
+
+int
+is_empty_arg(char *arg)
+{
+       int ret = 1;
+       if (arg != NULL) {
+               if (*arg) ret = 0;
+       };
+       return ret;
+}
+
+
+void
+csum_init(struct csum_state *css)
+{
+       css->odd = 0;
+       css->sum = 0;
+       css->tmp = 0;
+}
+
+
+void
+csum_update(uint8_t *p, uint32_t len, struct csum_state *css)
+{
+       if (len == 0)
+               return;
+
+       if (css->odd) {
+               css->sum += (css->tmp << 8) + p[0];
+               if (css->sum > 0xFFFF) {
+                       css->sum += 1;
+                       css->sum &= 0xFFFF;
+               }
+               css->odd = 0;
+               len--;
+               p++;
+       }
+
+       for ( ; len > 1; len -= 2, p +=2 ) {
+               css->sum  += (p[0] << 8) + p[1];
+               if (css->sum > 0xFFFF) {
+                       css->sum += 1;
+                       css->sum &= 0xFFFF;
+               }
+       }
+
+       if (len == 1){
+               css->tmp = p[0];
+               css->odd = 1;
+       }
+}
+
+
+uint16_t
+csum_get(struct csum_state *css)
+{
+       char pad = 0;
+
+       csum_update(&pad, 1, css);
+       return css->sum;
+}
+
+uint16_t
+csum_buf(uint8_t *p, uint32_t len)
+{
+       struct csum_state css;
+
+       csum_init(&css);
+       csum_update(p, len, &css);
+       return csum_get(&css);
+
+}
+
+/*
+ * routines to write data to the output file
+ */
+int
+write_out_data(FILE *outfile, uint8_t *data, size_t len,
+               struct csum_state *css)
+{
+       errno = 0;
+
+       fwrite(data, len, 1, outfile);
+       if (errno) {
+               ERR("unable to write output file");
+               return -1;
+       }
+
+       if (css) {
+               csum_update(data, len, css);
+       }
+
+       return 0;
+}
+
+
+int
+write_out_padding(FILE *outfile, size_t len, uint8_t padc,
+                struct csum_state *css)
+{
+       uint8_t buf[512];
+       size_t buflen = sizeof(buf);
+
+       memset(buf, padc, buflen);
+       while (len > 0) {
+               if (len < buflen)
+                       buflen = len;
+
+               if (write_out_data(outfile, buf, buflen, css))
+                       return -1;
+
+               len -= buflen;
+       }
+
+       return 0;
+}
+
+
+int
+write_out_data_align(FILE *outfile, uint8_t *data, size_t len, size_t align,
+               struct csum_state *css)
+{
+       size_t padlen;
+       int res;
+
+       res = write_out_data(outfile, data, len, css);
+       if (res)
+               return res;
+
+       padlen = ALIGN(len,align) - len;
+       res = write_out_padding(outfile, padlen, 0xFF, css);
+
+       return res;
+}
+
+
+int
+write_out_header(FILE *outfile, struct zyn_rombin_hdr *hdr)
+{
+       struct zyn_rombin_hdr t;
+
+       errno = 0;
+       if (fseek(outfile, 0, SEEK_SET) != 0) {
+               ERRS("fseek failed on output file");
+               return -1;
+       }
+
+       /* setup temporary header fields */
+       memset(&t, 0, sizeof(t));
+       t.addr = HOST_TO_BE32(hdr->addr);
+       memcpy(&t.sig, ROMBIN_SIGNATURE, ROMBIN_SIG_LEN);
+       t.type = hdr->type;
+       t.flags = hdr->flags;
+       t.osize = HOST_TO_BE32(hdr->osize);
+       t.csize = HOST_TO_BE32(hdr->csize);
+       t.ocsum = HOST_TO_BE16(hdr->ocsum);
+       t.ccsum = HOST_TO_BE16(hdr->ccsum);
+       t.mmap_addr = HOST_TO_BE32(hdr->mmap_addr);
+
+       DBG(2, "hdr.addr      = 0x%08x", hdr->addr);
+       DBG(2, "hdr.type      = 0x%02x", hdr->type);
+       DBG(2, "hdr.osize     = 0x%08x", hdr->osize);
+       DBG(2, "hdr.csize     = 0x%08x", hdr->csize);
+       DBG(2, "hdr.flags     = 0x%02x", hdr->flags);
+       DBG(2, "hdr.ocsum     = 0x%04x", hdr->ocsum);
+       DBG(2, "hdr.ccsum     = 0x%04x", hdr->ccsum);
+       DBG(2, "hdr.mmap_addr = 0x%08x", hdr->mmap_addr);
+
+       return write_out_data(outfile, (uint8_t *)&t, sizeof(t), NULL);
+}
+
+
+int
+write_out_mmap(FILE *outfile, struct fw_mmap *mmap, struct csum_state *css)
+{
+       struct zyn_mmt_hdr *mh;
+       uint8_t buf[MMAP_DATA_SIZE];
+       uint32_t user_size;
+       char *data;
+       int res;
+
+       memset(buf, 0, sizeof(buf));
+
+       mh = (struct zyn_mmt_hdr *)buf;
+
+       /* TODO: needs to recreate the memory map too? */
+       mh->count=0;
+
+       /* Build user data section */
+       data = buf+sizeof(*mh);
+       data += sprintf(data, "Vendor 1 %d", board->vendor);
+       *data++ = '\0';
+       data += sprintf(data, "Model 1 %d", BE16_TO_HOST(board->model));
+       *data++ = '\0';
+       /* TODO: make hardware version configurable? */
+       data += sprintf(data, "HwVerRange 2 %d %d", 0, 0);
+       *data++ = '\0';
+
+       user_size = (uint8_t *)data - buf;
+       mh->user_start= HOST_TO_BE32(mmap->addr+sizeof(*mh));
+       mh->user_end= HOST_TO_BE32(mmap->addr+user_size);
+       mh->csum = HOST_TO_BE16(csum_buf(buf+sizeof(*mh), user_size));
+
+       res = write_out_data(outfile, buf, sizeof(buf), css);
+
+       return res;
+}
+
+
+int
+block_stat_file(struct fw_block *block)
+{
+       struct stat st;
+       int res;
+
+       if (block->file_name == NULL)
+               return 0;
+
+       res = stat(block->file_name, &st);
+       if (res){
+               ERRS("stat failed on %s", block->file_name);
+               return res;
+       }
+
+       block->file_size = st.st_size;
+       return 0;
+}
+
+
+int
+read_magic(uint16_t *magic)
+{
+       FILE *f;
+       int res;
+
+       errno = 0;
+       f = fopen(bootext_block->file_name,"r");
+       if (errno) {
+               ERRS("unable to open file: %s", bootext_block->file_name);
+               return -1;
+       }
+
+       errno = 0;
+       fread(magic, 2, 1, f);
+       if (errno != 0) {
+               ERRS("unable to read from file: %s", bootext_block->file_name);
+               res = -1;
+               goto err;
+       }
+
+       res = 0;
+
+err:
+       fclose(f);
+       return res;
+}
+
+
+int
+write_out_file(FILE *outfile, char *name, size_t len, struct csum_state *css)
+{
+       char buf[FILE_BUF_LEN];
+       size_t buflen = sizeof(buf);
+       FILE *f;
+       int res;
+
+       DBG(2, "writing out file, name=%s, len=%d",
+               name, len);
+
+       errno = 0;
+       f = fopen(name,"r");
+       if (errno) {
+               ERRS("unable to open file: %s", name);
+               return -1;
+       }
+
+       while (len > 0) {
+               if (len < buflen)
+                       buflen = len;
+
+               /* read data from source file */
+               errno = 0;
+               fread(buf, buflen, 1, f);
+               if (errno != 0) {
+                       ERRS("unable to read from file: %s",name);
+                       res = -1;
+                       break;
+               }
+
+               res = write_out_data(outfile, buf, buflen, css);
+               if (res)
+                       break;
+
+               len -= buflen;
+       }
+
+       fclose(f);
+       return res;
+}
+
+
+int
+write_out_block(FILE *outfile, struct fw_block *block, struct csum_state *css)
+{
+       int res;
+
+       if (block == NULL)
+               return 0;
+
+       if (block->file_name == NULL)
+               return 0;
+
+       if (block->file_size == 0)
+               return 0;
+
+       res = write_out_file(outfile, block->file_name,
+                       block->file_size, css);
+       return res;
+}
+
+
+int
+write_out_image(FILE *outfile)
+{
+       struct fw_block *block;
+       struct fw_mmap mmap;
+       struct zyn_rombin_hdr hdr;
+       struct csum_state css;
+       int i, res;
+       uint32_t offset;
+       uint32_t padlen;
+       uint16_t csum;
+       uint16_t t;
+
+       /* setup header fields */
+       memset(&hdr, 0, sizeof(hdr));
+       hdr.addr = board->code_start;
+       hdr.type = OBJECT_TYPE_BOOTEXT;
+       hdr.flags = ROMBIN_FLAG_OCSUM;
+
+       offset = board->romio_offs;
+
+       res = write_out_header(outfile, &hdr);
+       if (res)
+               return res;
+
+       offset += sizeof(hdr);
+
+       csum_init(&css);
+       res = write_out_block(outfile, bootext_block, &css);
+       if (res)
+               return res;
+
+       offset += bootext_block->file_size;
+       if (offset > (board->romio_offs + board->bootext_size)) {
+               ERR("bootext file '%s' is too big", bootext_block->file_name);
+               return -1;
+       }
+
+       padlen = ALIGN(offset, MMAP_ALIGN) - offset;
+       res = write_out_padding(outfile, padlen, 0xFF, &css);
+       if (res)
+               return res;
+
+       offset += padlen;
+
+       mmap.addr = board->flash_base + offset;
+       res = write_out_mmap(outfile, &mmap, &css);
+       if (res)
+               return res;
+
+       offset += MMAP_DATA_SIZE;
+
+       if ((offset - board->romio_offs) < board->bootext_size) {
+               padlen = board->romio_offs + board->bootext_size - offset;
+               res = write_out_padding(outfile, padlen, 0xFF, &css);
+               if (res)
+                       return res;
+               offset += padlen;
+
+               DBG(2, "bootext end at %08x", offset);
+       }
+
+       for (i = 0; i < num_blocks; i++) {
+               block = &blocks[i];
+
+               if (block->type == BLOCK_TYPE_BOOTEXT)
+                       continue;
+
+               padlen = ALIGN(offset, block->align) - offset;
+               res = write_out_padding(outfile, padlen, 0xFF, &css);
+               if (res)
+                       return res;
+               offset += padlen;
+
+               res = write_out_block(outfile, block, &css);
+               if (res)
+                       return res;
+               offset += block->file_size;
+       }
+
+       padlen = ALIGN(offset, 4) - offset;
+       res = write_out_padding(outfile, padlen, 0xFF, &css);
+       if (res)
+               return res;
+       offset += padlen;
+
+       csum = csum_get(&css);
+       hdr.mmap_addr = mmap.addr;
+       hdr.osize = 2;
+
+       res = read_magic(&hdr.ocsum);
+       if (res)
+               return res;
+       hdr.ocsum = BE16_TO_HOST(hdr.ocsum);
+
+       if (csum <= hdr.ocsum)
+               t = hdr.ocsum - csum;
+       else
+               t = hdr.ocsum - csum - 1;
+
+       DBG(2, "ocsum=%04x, csum=%04x, fix=%04x", hdr.ocsum, csum, t);
+
+       t = HOST_TO_BE16(t);
+       res = write_out_data(outfile, (uint8_t *)&t, 2, NULL);
+       if (res)
+               return res;
+
+
+       res = write_out_header(outfile, &hdr);
+
+       return res;
+}
+
+
+struct board_info *
+find_board(char *name)
+{
+       struct board_info *ret;
+       struct board_info *board;
+
+       ret = NULL;
+       for (board = boards; board->name != NULL; board++){
+               if (strcasecmp(name, board->name) == 0) {
+                       ret = board;
+                       break;
+               }
+       };
+
+       return ret;
+}
+
+
+int
+parse_opt_board(char ch, char *arg)
+{
+
+       DBG(1,"parsing board option: -%c %s", ch, arg);
+
+       if (board != NULL) {
+               ERR("only one board option allowed");
+               return -1;
+       }
+
+       if (required_arg(ch, arg))
+               return -1;
+
+       board = find_board(arg);
+       if (board == NULL){
+               ERR("invalid/unknown board specified: %s", arg);
+               return -1;
+       }
+
+       return 0;
+}
+
+
+int
+parse_opt_ofname(char ch, char *arg)
+{
+
+       if (ofname != NULL) {
+               ERR("only one output file allowed");
+               return -1;
+       }
+
+       if (required_arg(ch, arg))
+               return -1;
+
+       ofname = arg;
+
+       return 0;
+}
+
+
+int
+parse_opt_block(char ch, char *arg)
+{
+       char buf[MAX_ARG_LEN];
+       char *argv[MAX_ARG_COUNT];
+       int argc;
+       char *p;
+       struct fw_block *block;
+       int i;
+
+       if ( num_blocks >= MAX_NUM_BLOCKS ) {
+               ERR("too many blocks specified");
+               return -1;
+       }
+
+       block = &blocks[num_blocks++];
+
+       /* setup default field values */
+       block->padc = 0xFF;
+
+       switch(ch) {
+       case 'b':
+               if (bootext_block) {
+                       ERR("only one boot extension block allowed");
+                       break;
+               }
+               block->type = BLOCK_TYPE_BOOTEXT;
+               bootext_block = block;
+               break;
+       case 'r':
+               block->type = BLOCK_TYPE_RAW;
+               break;
+       }
+
+       argc = parse_arg(arg, buf, argv);
+
+       i = 0;
+       p = argv[i++];
+       if (is_empty_arg(p)) {
+               ERR("no file specified in %s", arg);
+               return -1;
+       } else {
+               block->file_name = strdup(p);
+               if (block->file_name == NULL) {
+                       ERR("not enough memory");
+                       return -1;
+               }
+       }
+
+       if (block->type == BLOCK_TYPE_BOOTEXT)
+               return 0;
+
+       p = argv[i++];
+       if (!is_empty_arg(p)) {
+               if (str2u32(p, &block->align) != 0) {
+                       ERR("invalid block align in %s", arg);
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+
+int
+calc_block_offsets(int type, uint32_t *offset)
+{
+       struct fw_block *block;
+       uint32_t next_offs;
+       uint32_t avail;
+       int i, res;
+
+       DBG(1,"calculating block offsets, starting with %lu",
+               *offset);
+
+       res = 0;
+       for (i = 0; i < num_blocks; i++) {
+               block = &blocks[i];
+
+               if (block->type != type)
+                       continue;
+
+               next_offs = ALIGN(*offset, block->align);
+               avail = board->flash_size - next_offs;
+               if (block->file_size > avail) {
+                       ERR("file %s is too big, offset = %u, size=%u,"
+                               " avail = %u, align = %u", block->file_name,
+                               (unsigned)next_offs,
+                               (unsigned)block->file_size,
+                               (unsigned)avail,
+                               (unsigned)block->align);
+                       res = -1;
+                       break;
+               }
+
+               block->padlen = next_offs - *offset;
+               *offset += block->file_size;
+       }
+
+       return res;
+}
+
+int
+process_blocks(void)
+{
+       struct fw_block *block;
+       uint32_t offset;
+       int i;
+       int res;
+
+       /* collecting file stats */
+       for (i = 0; i < num_blocks; i++) {
+               block = &blocks[i];
+               res = block_stat_file(block);
+               if (res)
+                       return res;
+       }
+
+       offset = board->romio_offs + bootext_block->file_size;
+       res = calc_block_offsets(BLOCK_TYPE_RAW, &offset);
+
+       return res;
+}
+
+
+int
+main(int argc, char *argv[])
+{
+       int optinvalid = 0;   /* flag for invalid option */
+       int c;
+       int res = EXIT_FAILURE;
+
+       FILE *outfile;
+
+       progname=basename(argv[0]);
+
+       opterr = 0;  /* could not print standard getopt error messages */
+       while ( 1 ) {
+               optinvalid = 0;
+
+               c = getopt(argc, argv, "b:B:ho:r:v");
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'b':
+               case 'r':
+                       optinvalid = parse_opt_block(c,optarg);
+                       break;
+               case 'B':
+                       optinvalid = parse_opt_board(c,optarg);
+                       break;
+               case 'o':
+                       optinvalid = parse_opt_ofname(c,optarg);
+                       break;
+               case 'v':
+                       verblevel++;
+                       break;
+               case 'h':
+                       usage(EXIT_SUCCESS);
+                       break;
+               default:
+                       optinvalid = 1;
+                       break;
+               }
+               if (optinvalid != 0 ) {
+                       ERR("invalid option: -%c", optopt);
+                       goto out;
+               }
+       }
+
+       if (board == NULL) {
+               ERR("no board specified");
+               goto out;
+       }
+
+       if (ofname == NULL) {
+               ERR("no output file specified");
+               goto out;
+       }
+
+       if (optind < argc) {
+               ERR("invalid option: %s", argv[optind]);
+               goto out;
+       }
+
+       if (process_blocks() != 0) {
+               goto out;
+       }
+
+       outfile = fopen(ofname, "w");
+       if (outfile == NULL) {
+               ERRS("could not open \"%s\" for writing", ofname);
+               goto out;
+       }
+
+       if (write_out_image(outfile) != 0)
+               goto out_flush;
+
+       DBG(1,"Image file %s completed.", ofname);
+
+       res = EXIT_SUCCESS;
+
+out_flush:
+       fflush(outfile);
+       fclose(outfile);
+       if (res != EXIT_SUCCESS) {
+               unlink(ofname);
+       }
+out:
+       return res;
+}
diff --git a/trunk/tools/firmware-utils/src/motorola-bin.c b/trunk/tools/firmware-utils/src/motorola-bin.c
new file mode 100644 (file)
index 0000000..33e9937
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * motorola-bin.c
+ *
+ * Copyright (C) 2005-2006 Mike Baker,
+ *                         Imre Kaloz <kaloz@openwrt.org>
+ *                         D. Hugh Redelmeier
+ *                         OpenWrt.org
+ *
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Motorola's firmware flashing code requires an extra header.
+ * The header is eight bytes (see struct motorola below).
+ * This program will take a firmware file and create a new one
+ * with this header:
+ *     motorola-bin --wr850g WR850G_V403.stripped.trx WR850G_V403.trx
+ *
+ * Note: Motorola's firmware is distributed with this header.
+ * If you need to flash Motorola firmware on a router running libreCMC,
+ * you will to remove this header.  Use the --strip flag:
+ *     motorola-bin --strip WR850G_V403.trx WR850G_V403.stripped.trx
+ */
+
+/*
+ * February 1, 2006
+ *
+ * Add support for for creating WA840G and WE800G images
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <inttypes.h>
+
+#define BPB 8 /* bits/byte */
+
+static uint32_t crc32[1<<BPB];
+
+static void init_crc32()
+{
+       const uint32_t poly = ntohl(0x2083b8ed);
+       int n;
+
+       for (n = 0; n < 1<<BPB; n++) {
+               uint32_t crc = n;
+               int bit;
+
+               for (bit = 0; bit < BPB; bit++)
+                       crc = (crc & 1) ? (poly ^ (crc >> 1)) : (crc >> 1);
+               crc32[n] = crc;
+       }
+}
+
+static uint32_t crc32buf(unsigned char *buf, size_t len)
+{
+       uint32_t crc = 0xFFFFFFFF;
+
+       for (; len; len--, buf++)
+               crc = crc32[(uint8_t)crc ^ *buf] ^ (crc >> BPB);
+       return crc;
+}
+
+struct motorola {
+       uint32_t crc;   // crc32 of the remainder
+       uint32_t flags; // unknown, 105770*
+};
+
+static const struct model {
+       char digit;     /* a digit signifying model (historical) */
+       const char *name;
+       uint32_t flags;
+} models[] = {
+       { '1', "WR850G", 0x10577050LU },
+       { '2', "WA840G", 0x10577040LU },
+       { '3', "WE800G", 0x10577000LU },
+       { '\0', NULL, 0 }
+};
+
+static void usage(const char *) __attribute__ (( __noreturn__ ));
+
+static void usage(const char *mess)
+{
+       const struct model *m;
+
+       fprintf(stderr, "Error: %s\n", mess);
+       fprintf(stderr, "Usage: motorola-bin -device|--strip infile outfile\n");
+       fprintf(stderr, "Known devices: ");
+
+       for (m = models; m->digit != '\0'; m++)
+               fprintf(stderr, " %c - %s", m->digit, m->name);
+
+       fprintf(stderr, "\n");
+       exit(1);
+}
+
+int main(int argc, char **argv)
+{
+       off_t len;      // of original firmware
+       int fd;
+       void *trx;      // pointer to original firmware (mmmapped)
+       struct motorola *firmware;      // pionter to prefix + copy of original firmware
+       uint32_t flags;
+
+       // verify parameters
+
+       if (argc != 4)
+               usage("wrong number of arguments");
+
+       // mmap trx file
+       if ((fd = open(argv[2], O_RDONLY))  < 0
+       || (len = lseek(fd, 0, SEEK_END)) < 0
+       || (trx = mmap(0, len, PROT_READ, MAP_SHARED, fd, 0)) == (void *) (-1)
+       || close(fd) < 0)
+       {
+               fprintf(stderr, "Error loading file %s: %s\n", argv[2], strerror(errno));
+               exit(1);
+       }
+
+       init_crc32();
+
+       if (strcmp(argv[1], "--strip") == 0)
+       {
+               const char *ugh = NULL;
+
+               if (len < sizeof(struct motorola)) {
+                       ugh = "input file too short";
+               } else {
+                       const struct model *m;
+
+                       firmware = trx;
+                       if (htonl(crc32buf(trx + offsetof(struct motorola, flags), len - offsetof(struct motorola, flags))) != firmware->crc)
+                               ugh = "Invalid CRC";
+                       for (m = models; ; m++) {
+                               if (m->digit == '\0') {
+                                       if (ugh == NULL)
+                                               ugh = "unrecognized flags field";
+                                       break;
+                               }
+                               if (firmware->flags == htonl(m->flags)) {
+                                       fprintf(stderr, "Firmware for Motorola %s\n", m->name);
+                                       break;
+                               }
+                       }
+               }
+
+               if (ugh != NULL) {
+                       fprintf(stderr, "%s\n", ugh);
+                       exit(3);
+               } else {
+                       // all is well, write the file without the prefix
+                       if ((fd = open(argv[3], O_CREAT|O_WRONLY|O_TRUNC,0644)) < 0
+                       || write(fd, trx + sizeof(struct motorola), len - sizeof(struct motorola)) !=  len - sizeof(struct motorola)
+                       || close(fd) < 0)
+                       {
+                               fprintf(stderr, "Error storing file %s: %s\n", argv[3], strerror(errno));
+                               exit(2);
+                       }
+               }
+               
+       } else {
+               // setup the firmware flags magic number
+               const struct model *m;
+               const char *df = argv[1];
+
+               if (*df != '-')
+                       usage("first argument must start with -");
+               if (*++df == '-')
+                       ++df;   /* allow but don't require second - */
+
+               for (m = models; ; m++) {
+                       if (m->digit == '\0')
+                               usage("unrecognized device specified");
+                       if ((df[0] == m->digit && df[1] == '\0') || strcasecmp(df, m->name) == 0) {
+                               flags = m->flags;
+                               break;
+                       }
+               }
+
+
+               // create a firmware image in memory
+               // and copy the trx to it
+               firmware = malloc(sizeof(struct motorola) + len);
+               memcpy(&firmware[1], trx, len);
+
+               // setup the motorola headers
+               firmware->flags = htonl(flags);
+
+               // CRC of flags + firmware
+               firmware->crc = htonl(crc32buf((unsigned char *)&firmware->flags, sizeof(firmware->flags) + len));
+
+               // write the firmware
+               if ((fd = open(argv[3], O_CREAT|O_WRONLY|O_TRUNC,0644)) < 0
+               || write(fd, firmware, sizeof(struct motorola) + len) != sizeof(struct motorola) + len
+               || close(fd) < 0)
+               {
+                       fprintf(stderr, "Error storing file %s: %s\n", argv[3], strerror(errno));
+                       exit(2);
+               }
+
+               free(firmware);
+       }
+
+       munmap(trx,len);
+
+       return 0;
+}
diff --git a/trunk/tools/firmware-utils/src/myloader.h b/trunk/tools/firmware-utils/src/myloader.h
new file mode 100644 (file)
index 0000000..7be1d49
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ *  Copyright (C) 2006-2008 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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.
+ *
+ */
+
+#ifndef _MYLOADER_H_
+#define _MYLOADER_H_
+
+/*
+ * Firmware file format:
+ *
+ *     <header>
+ *     [<block descriptor 0>]
+ *     ...
+ *     [<block descriptor n>]
+ *     <null block descriptor>
+ *     [<block data 0>]
+ *     ...
+ *     [<block data n>]
+ *
+ *
+ */
+
+/* Myloader specific magic numbers */
+#define MYLO_MAGIC_FIRMWARE    0x4C594D00
+#define MYLO_MAGIC_20021103    0x20021103
+#define MYLO_MAGIC_20021107    0x20021107
+
+#define MYLO_MAGIC_SYS_PARAMS  MYLO_MAGIC_20021107
+#define MYLO_MAGIC_PARTITIONS  MYLO_MAGIC_20021103
+#define MYLO_MAGIC_BOARD_PARAMS        MYLO_MAGIC_20021103
+
+/*
+ * Addresses of the data structures provided by MyLoader
+ */
+#define MYLO_MIPS_SYS_PARAMS   0x80000800      /* System Parameters */
+#define MYLO_MIPS_BOARD_PARAMS 0x80000A00      /* Board Parameters */
+#define MYLO_MIPS_PARTITIONS   0x80000C00      /* Partition Table */
+#define MYLO_MIPS_BOOT_PARAMS  0x80000E00      /* Boot Parameters */
+
+/* Vendor ID's (seems to be same as the PCI vendor ID's) */
+#define VENID_COMPEX           0x11F6
+
+/* Devices based on the ADM5120 */
+#define DEVID_COMPEX_NP27G     0x0078
+#define DEVID_COMPEX_NP28G     0x044C
+#define DEVID_COMPEX_NP28GHS   0x044E
+#define DEVID_COMPEX_WP54Gv1C  0x0514
+#define DEVID_COMPEX_WP54G     0x0515
+#define DEVID_COMPEX_WP54AG    0x0546
+#define DEVID_COMPEX_WPP54AG   0x0550
+#define DEVID_COMPEX_WPP54G    0x0555
+
+/* Devices based on the Atheros AR2317 */
+#define DEVID_COMPEX_NP25G     0x05e6
+#define DEVID_COMPEX_WPE53G    0x05dc
+
+/* Devices based on the Atheros AR71xx */
+#define DEVID_COMPEX_WP543     0x0640
+#define DEVID_COMPEX_WPE72     0x0672
+
+/* Devices based on the IXP422 */
+#define DEVID_COMPEX_WP18      0x047E
+#define DEVID_COMPEX_NP18A     0x0489
+
+/* Other devices */
+#define DEVID_COMPEX_NP26G8M   0x03E8
+#define DEVID_COMPEX_NP26G16M  0x03E9
+
+struct mylo_fw_header {
+       uint32_t        magic;  /* must be MYLO_MAGIC_FIRMWARE */
+       uint32_t        crc;    /* CRC of the whole firmware */
+       uint32_t        res0;   /* unknown/unused */
+       uint32_t        res1;   /* unknown/unused */
+       uint16_t        vid;    /* vendor ID */
+       uint16_t        did;    /* device ID */
+       uint16_t        svid;   /* sub vendor ID */
+       uint16_t        sdid;   /* sub device ID */
+       uint32_t        rev;    /* device revision */
+       uint32_t        fwhi;   /* FIXME: firmware version high? */
+       uint32_t        fwlo;   /* FIXME: firmware version low? */
+       uint32_t        flags;  /* firmware flags */
+};
+
+#define FW_FLAG_BOARD_PARAMS_WP        0x01 /* board parameters are write protected */
+#define FW_FLAG_BOOT_SECTOR_WE 0x02 /* enable of write boot sectors (below 64K) */
+
+struct mylo_fw_blockdesc {
+       uint32_t        type;   /* block type */
+       uint32_t        addr;   /* relative address to flash start */
+       uint32_t        dlen;   /* size of block data in bytes */
+       uint32_t        blen;   /* total size of block in bytes */
+};
+
+#define FW_DESC_TYPE_UNUSED    0
+#define FW_DESC_TYPE_USED      1
+
+struct mylo_partition {
+       uint16_t        flags;  /* partition flags */
+       uint16_t        type;   /* type of the partition */
+       uint32_t        addr;   /* relative address of the partition from the
+                                  flash start */
+       uint32_t        size;   /* size of the partition in bytes */
+       uint32_t        param;  /* if this is the active partition, the
+                                  MyLoader load code to this address */
+};
+
+#define PARTITION_FLAG_ACTIVE  0x8000 /* this is the active partition,
+                                       * MyLoader loads firmware from here */
+#define PARTITION_FLAG_ISRAM   0x2000 /* FIXME: this is a RAM partition? */
+#define PARTIIION_FLAG_RAMLOAD 0x1000 /* FIXME: load this partition into the RAM? */
+#define PARTITION_FLAG_PRELOAD 0x0800 /* the partition data preloaded to RAM
+                                       * before decompression */
+#define PARTITION_FLAG_LZMA    0x0100 /* the partition data compressed with LZMA */
+#define PARTITION_FLAG_HAVEHDR  0x0002 /* the partition data have a header */
+
+#define PARTITION_TYPE_FREE    0
+#define PARTITION_TYPE_USED    1
+
+#define MYLO_MAX_PARTITIONS    8       /* maximum number of partitions in the
+                                          partition table */
+
+struct mylo_partition_table {
+       uint32_t        magic;  /* must be MYLO_MAGIC_PARTITIONS */
+       uint32_t        res0;   /* unknown/unused */
+       uint32_t        res1;   /* unknown/unused */
+       uint32_t        res2;   /* unknown/unused */
+       struct mylo_partition partitions[MYLO_MAX_PARTITIONS];
+};
+
+struct mylo_partition_header {
+       uint32_t        len;    /* length of the partition data */
+       uint32_t        crc;    /* CRC value of the partition data */
+};
+
+struct mylo_system_params {
+       uint32_t        magic;  /* must be MYLO_MAGIC_SYS_PARAMS */
+       uint32_t        res0;
+       uint32_t        res1;
+       uint32_t        mylo_ver;
+       uint16_t        vid;    /* Vendor ID */
+       uint16_t        did;    /* Device ID */
+       uint16_t        svid;   /* Sub Vendor ID */
+       uint16_t        sdid;   /* Sub Device ID */
+       uint32_t        rev;    /* device revision */
+       uint32_t        fwhi;
+       uint32_t        fwlo;
+       uint32_t        tftp_addr;
+       uint32_t        prog_start;
+       uint32_t        flash_size;     /* Size of boot FLASH in bytes */
+       uint32_t        dram_size;      /* Size of onboard RAM in bytes */
+};
+
+
+struct mylo_eth_addr {
+       uint8_t mac[6];
+       uint8_t csum[2];
+};
+
+#define MYLO_ETHADDR_COUNT     8       /* maximum number of ethernet address
+                                          in the board parameters */
+
+struct mylo_board_params {
+       uint32_t        magic;  /* must be MYLO_MAGIC_BOARD_PARAMS */
+       uint32_t        res0;
+       uint32_t        res1;
+       uint32_t        res2;
+       struct mylo_eth_addr addr[MYLO_ETHADDR_COUNT];
+};
+
+#endif /* _MYLOADER_H_*/
diff --git a/trunk/tools/firmware-utils/src/nand_ecc.c b/trunk/tools/firmware-utils/src/nand_ecc.c
new file mode 100644 (file)
index 0000000..b1e9305
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * calculate ecc code for nand flash
+ *
+ * Copyright (C) 2008 yajin <yajin@vm-kernel.org>
+ * Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
+ *
+ * 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 or
+ * (at your option) version 3 of the License.
+ *
+ * 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
+ */
+
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#define DEF_NAND_PAGE_SIZE   2048
+#define DEF_NAND_OOB_SIZE     64
+#define DEF_NAND_ECC_OFFSET   0x28
+
+static int page_size = DEF_NAND_PAGE_SIZE;
+static int oob_size = DEF_NAND_OOB_SIZE;
+static int ecc_offset = DEF_NAND_ECC_OFFSET;
+
+/*
+ * Pre-calculated 256-way 1 byte column parity
+ */
+static const uint8_t nand_ecc_precalc_table[] = {
+       0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
+       0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
+       0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
+       0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
+       0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
+       0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
+       0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
+       0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
+       0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
+       0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
+       0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
+       0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
+       0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
+       0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
+       0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
+       0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00
+};
+
+/**
+ * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256-byte block
+ * @dat:       raw data
+ * @ecc_code:  buffer for ECC
+ */
+int nand_calculate_ecc(const uint8_t *dat,
+                      uint8_t *ecc_code)
+{
+       uint8_t idx, reg1, reg2, reg3, tmp1, tmp2;
+       int i;
+
+       /* Initialize variables */
+       reg1 = reg2 = reg3 = 0;
+
+       /* Build up column parity */
+       for(i = 0; i < 256; i++) {
+               /* Get CP0 - CP5 from table */
+               idx = nand_ecc_precalc_table[*dat++];
+               reg1 ^= (idx & 0x3f);
+
+               /* All bit XOR = 1 ? */
+               if (idx & 0x40) {
+                       reg3 ^= (uint8_t) i;
+                       reg2 ^= ~((uint8_t) i);
+               }
+       }
+
+       /* Create non-inverted ECC code from line parity */
+       tmp1  = (reg3 & 0x80) >> 0; /* B7 -> B7 */
+       tmp1 |= (reg2 & 0x80) >> 1; /* B7 -> B6 */
+       tmp1 |= (reg3 & 0x40) >> 1; /* B6 -> B5 */
+       tmp1 |= (reg2 & 0x40) >> 2; /* B6 -> B4 */
+       tmp1 |= (reg3 & 0x20) >> 2; /* B5 -> B3 */
+       tmp1 |= (reg2 & 0x20) >> 3; /* B5 -> B2 */
+       tmp1 |= (reg3 & 0x10) >> 3; /* B4 -> B1 */
+       tmp1 |= (reg2 & 0x10) >> 4; /* B4 -> B0 */
+
+       tmp2  = (reg3 & 0x08) << 4; /* B3 -> B7 */
+       tmp2 |= (reg2 & 0x08) << 3; /* B3 -> B6 */
+       tmp2 |= (reg3 & 0x04) << 3; /* B2 -> B5 */
+       tmp2 |= (reg2 & 0x04) << 2; /* B2 -> B4 */
+       tmp2 |= (reg3 & 0x02) << 2; /* B1 -> B3 */
+       tmp2 |= (reg2 & 0x02) << 1; /* B1 -> B2 */
+       tmp2 |= (reg3 & 0x01) << 1; /* B0 -> B1 */
+       tmp2 |= (reg2 & 0x01) << 0; /* B7 -> B0 */
+
+       /* Calculate final ECC code */
+#ifdef CONFIG_MTD_NAND_ECC_SMC
+       ecc_code[0] = ~tmp2;
+       ecc_code[1] = ~tmp1;
+#else
+       ecc_code[0] = ~tmp1;
+       ecc_code[1] = ~tmp2;
+#endif
+       ecc_code[2] = ((~reg1) << 2) | 0x03;
+
+       return 0;
+}
+
+/*
+ *  usage: bb-nandflash-ecc    start_address  size
+ */
+void usage(const char *prog)
+{
+       fprintf(stderr, "Usage: %s [options] <input> <output>\n"
+               "Options:\n"
+               "    -p <pagesize>      NAND page size (default: %d)\n"
+               "    -o <oobsize>       NAND OOB size (default: %d)\n"
+               "    -e <offset>        NAND ECC offset (default: %d)\n"
+               "\n", prog, DEF_NAND_PAGE_SIZE, DEF_NAND_OOB_SIZE,
+               DEF_NAND_ECC_OFFSET);
+       exit(1);
+}
+
+/*start_address/size does not include oob
+  */
+int main(int argc, char **argv)
+{
+       uint8_t *page_data = NULL;
+       uint8_t *ecc_data;
+       int infd = -1, outfd = -1;
+       int ret = 1;
+       ssize_t bytes;
+       int ch;
+
+       while ((ch = getopt(argc, argv, "e:o:p:")) != -1) {
+               switch(ch) {
+               case 'p':
+                       page_size = strtoul(optarg, NULL, 0);
+                       break;
+               case 'o':
+                       oob_size = strtoul(optarg, NULL, 0);
+                       break;
+               case 'e':
+                       ecc_offset = strtoul(optarg, NULL, 0);
+                       break;
+               default:
+                       usage(argv[0]);
+               }
+       }
+       argc -= optind;
+       if (argc < 2)
+               usage(argv[0]);
+
+       argv += optind;
+
+       infd = open(argv[0], O_RDONLY, 0);
+       if (infd < 0) {
+               perror("open input file");
+               goto out;
+       }
+
+       outfd = open(argv[1], O_WRONLY|O_CREAT|O_TRUNC, 0644);
+       if (outfd < 0) {
+               perror("open output file");
+               goto out;
+       }
+
+       page_data = malloc(page_size + oob_size);
+
+       while ((bytes = read(infd, page_data, page_size)) == page_size) {
+               int j;
+
+               ecc_data = page_data + page_size + ecc_offset;
+               for (j = 0; j < page_size / 256; j++)
+               {
+                       nand_calculate_ecc(page_data + j * 256, ecc_data);
+                       ecc_data += 3;
+               }
+               write(outfd, page_data, page_size + oob_size);
+       }
+
+       ret = 0;
+out:
+       if (infd >= 0)
+               close(infd);
+       if (outfd >= 0)
+               close(outfd);
+       if (page_data)
+               free(page_data);
+       return ret;
+}
+
diff --git a/trunk/tools/firmware-utils/src/osbridge-crc.c b/trunk/tools/firmware-utils/src/osbridge-crc.c
new file mode 100644 (file)
index 0000000..f2e3920
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ *  Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>     /* for unlink() */
+#include <libgen.h>
+#include <getopt.h>     /* for getopt() */
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#if (__BYTE_ORDER == __LITTLE_ENDIAN)
+#  define HOST_TO_LE16(x)      (x)
+#  define HOST_TO_LE32(x)      (x)
+#  define LE16_TO_HOST(x)      (x)
+#  define LE32_TO_HOST(x)      (x)
+#else
+#  define HOST_TO_LE16(x)      bswap_16(x)
+#  define HOST_TO_LE32(x)      bswap_32(x)
+#  define LE16_TO_HOST(x)      bswap_16(x)
+#  define LE32_TO_HOST(x)      bswap_32(x)
+#endif
+
+uint32_t crc32buf(char *buf, size_t len);
+
+/*
+ * Globals
+ */
+static char *ifname;
+static char *progname;
+static char *ofname;
+
+/*
+ * Message macros
+ */
+#define ERR(fmt, ...) do { \
+       fflush(0); \
+       fprintf(stderr, "[%s] *** error: " fmt "\n", \
+                       progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERRS(fmt, ...) do { \
+       int save = errno; \
+       fflush(0); \
+       fprintf(stderr, "[%s] *** error: " fmt "\n", \
+                       progname, ## __VA_ARGS__, strerror(save)); \
+} while (0)
+
+void usage(int status)
+{
+       FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+       struct board_info *board;
+
+       fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+       fprintf(stream,
+"\n"
+"Options:\n"
+"  -i <file>       read input from the file <file>\n"
+"  -o <file>       write output to the file <file>\n"
+"  -h              show this screen\n"
+       );
+
+       exit(status);
+}
+
+int main(int argc, char *argv[])
+{
+       int res = EXIT_FAILURE;
+       int buflen;
+       int err;
+       struct stat st;
+       char *buf;
+       uint32_t *hdr;
+       uint32_t crc;
+
+       FILE *outfile, *infile;
+
+       progname = basename(argv[0]);
+
+       while ( 1 ) {
+               int c;
+
+               c = getopt(argc, argv, "i:o:h");
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'i':
+                       ifname = optarg;
+                       break;
+               case 'o':
+                       ofname = optarg;
+                       break;
+               case 'h':
+                       usage(EXIT_SUCCESS);
+                       break;
+               default:
+                       usage(EXIT_FAILURE);
+                       break;
+               }
+       }
+
+       if (ifname == NULL) {
+               ERR("no input file specified");
+               goto err;
+       }
+
+       if (ofname == NULL) {
+               ERR("no output file specified");
+               goto err;
+       }
+
+       err = stat(ifname, &st);
+       if (err){
+               ERRS("stat failed on %s", ifname);
+               goto err;
+       }
+
+       buflen = st.st_size;
+       buf = malloc(buflen);
+       if (!buf) {
+               ERR("no memory for buffer\n");
+               goto err;
+       }
+
+       infile = fopen(ifname, "r");
+       if (infile == NULL) {
+               ERRS("could not open \"%s\" for reading", ifname);
+               goto err_free;
+       }
+
+       errno = 0;
+       fread(buf, buflen, 1, infile);
+       if (errno != 0) {
+               ERRS("unable to read from file %s", ifname);
+               goto err_close_in;
+       }
+
+       crc = crc32buf(buf, buflen);
+       hdr = (uint32_t *)buf;
+       *hdr = HOST_TO_LE32(crc);
+
+       outfile = fopen(ofname, "w");
+       if (outfile == NULL) {
+               ERRS("could not open \"%s\" for writing", ofname);
+               goto err_close_in;
+       }
+
+       errno = 0;
+       fwrite(buf, buflen, 1, outfile);
+       if (errno) {
+               ERRS("unable to write to file %s", ofname);
+               goto err_close_out;
+       }
+
+       res = EXIT_SUCCESS;
+
+ out_flush:
+       fflush(outfile);
+
+ err_close_out:
+       fclose(outfile);
+       if (res != EXIT_SUCCESS) {
+               unlink(ofname);
+       }
+
+ err_close_in:
+       fclose(infile);
+
+ err_free:
+       free(buf);
+
+ err:
+       return res;
+}
+
+/**********************************************************************/
+/* The following was grabbed and tweaked from the old snippets collection
+ * of public domain C code. */
+
+/**********************************************************************\
+|* Demonstration program to compute the 32-bit CRC used as the frame  *|
+|* check sequence in ADCCP (ANSI X3.66, also known as FIPS PUB 71     *|
+|* and FED-STD-1003, the U.S. versions of CCITT's X.25 link-level     *|
+|* protocol).  The 32-bit FCS was added via the Federal Register,     *|
+|* 1 June 1982, p.23798.  I presume but don't know for certain that   *|
+|* this polynomial is or will be included in CCITT V.41, which        *|
+|* defines the 16-bit CRC (often called CRC-CCITT) polynomial.  FIPS  *|
+|* PUB 78 says that the 32-bit FCS reduces otherwise undetected       *|
+|* errors by a factor of 10^-5 over 16-bit FCS.                       *|
+\**********************************************************************/
+
+/* Copyright (C) 1986 Gary S. Brown.  You may use this program, or
+   code or tables extracted from it, as desired without restriction.*/
+
+/* First, the polynomial itself and its table of feedback terms.  The  */
+/* polynomial is                                                       */
+/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */
+/* Note that we take it "backwards" and put the highest-order term in  */
+/* the lowest-order bit.  The X^32 term is "implied"; the LSB is the   */
+/* X^31 term, etc.  The X^0 term (usually shown as "+1") results in    */
+/* the MSB being 1.                                                    */
+
+/* Note that the usual hardware shift register implementation, which   */
+/* is what we're using (we're merely optimizing it by doing eight-bit  */
+/* chunks at a time) shifts bits into the lowest-order term.  In our   */
+/* implementation, that means shifting towards the right.  Why do we   */
+/* do it this way?  Because the calculated CRC must be transmitted in  */
+/* order from highest-order term to lowest-order term.  UARTs transmit */
+/* characters in order from LSB to MSB.  By storing the CRC this way,  */
+/* we hand it to the UART in the order low-byte to high-byte; the UART */
+/* sends each low-bit to hight-bit; and the result is transmission bit */
+/* by bit from highest- to lowest-order term without requiring any bit */
+/* shuffling on our part.  Reception works similarly.                  */
+
+/* The feedback terms table consists of 256, 32-bit entries.  Notes:   */
+/*                                                                     */
+/*  1. The table can be generated at runtime if desired; code to do so */
+/*     is shown later.  It might not be obvious, but the feedback      */
+/*     terms simply represent the results of eight shift/xor opera-    */
+/*     tions for all combinations of data and CRC register values.     */
+/*                                                                     */
+/*  2. The CRC accumulation logic is the same for all CRC polynomials, */
+/*     be they sixteen or thirty-two bits wide.  You simply choose the */
+/*     appropriate table.  Alternatively, because the table can be     */
+/*     generated at runtime, you can start by generating the table for */
+/*     the polynomial in question and use exactly the same "updcrc",   */
+/*     if your application needn't simultaneously handle two CRC       */
+/*     polynomials.  (Note, however, that XMODEM is strange.)          */
+/*                                                                     */
+/*  3. For 16-bit CRCs, the table entries need be only 16 bits wide;   */
+/*     of course, 32-bit entries work OK if the high 16 bits are zero. */
+/*                                                                     */
+/*  4. The values must be right-shifted by eight bits by the "updcrc"  */
+/*     logic; the shift must be unsigned (bring in zeroes).  On some   */
+/*     hardware you could probably optimize the shift in assembler by  */
+/*     using byte-swap instructions.                                   */
+
+static const uint32_t crc_32_tab[] = { /* CRC polynomial 0xedb88320 */
+0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+#define UPDC32(octet,crc) (crc_32_tab[((crc) ^ (octet)) & 0xff] ^ ((crc) >> 8))
+
+uint32_t crc32buf(char *buf, size_t len)
+{
+      uint32_t crc;
+
+      crc = 0xFFFFFFFF;
+
+      for ( ; len; --len, ++buf)
+      {
+            crc = UPDC32(*buf, crc);
+      }
+
+      return crc ^ 0xFFFFFFFF;
+}
+
diff --git a/trunk/tools/firmware-utils/src/pc1crypt.c b/trunk/tools/firmware-utils/src/pc1crypt.c
new file mode 100644 (file)
index 0000000..9c2eb83
--- /dev/null
@@ -0,0 +1,361 @@
+/*
+ *  Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ *
+ *  This code was based on:
+ *     PC1 Cipher Algorithm ( Pukall Cipher 1 )
+ *     By Alexander PUKALL 1991
+ *     free code no restriction to use
+ *     please include the name of the Author in the final software
+ *     the Key is 128 bits
+ *     http://membres.lycos.fr/pc1/
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>     /* for unlink() */
+#include <libgen.h>
+#include <getopt.h>     /* for getopt() */
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+struct pc1_ctx {
+       unsigned short  ax;
+       unsigned short  bx;
+       unsigned short  cx;
+       unsigned short  dx;
+       unsigned short  si;
+       unsigned short  tmp;
+       unsigned short  x1a2;
+       unsigned short  x1a0[8];
+       unsigned short  res;
+       unsigned short  i;
+       unsigned short  inter;
+       unsigned short  cfc;
+       unsigned short  cfd;
+       unsigned short  compte;
+       unsigned char   cle[17];
+       short           c;
+};
+
+static void pc1_finish(struct pc1_ctx *pc1)
+{
+       /* erase all variables */
+       memset(pc1, 0, sizeof(struct pc1_ctx));
+}
+
+static void pc1_code(struct pc1_ctx *pc1)
+{
+       pc1->dx = pc1->x1a2 + pc1->i;
+       pc1->ax = pc1->x1a0[pc1->i];
+       pc1->cx = 0x015a;
+       pc1->bx = 0x4e35;
+
+       pc1->tmp = pc1->ax;
+       pc1->ax = pc1->si;
+       pc1->si = pc1->tmp;
+
+       pc1->tmp = pc1->ax;
+       pc1->ax = pc1->dx;
+       pc1->dx = pc1->tmp;
+
+       if (pc1->ax != 0) {
+               pc1->ax = pc1->ax * pc1->bx;
+       }
+
+       pc1->tmp = pc1->ax;
+       pc1->ax = pc1->cx;
+       pc1->cx = pc1->tmp;
+
+       if (pc1->ax != 0) {
+               pc1->ax = pc1->ax * pc1->si;
+               pc1->cx = pc1->ax + pc1->cx;
+       }
+
+       pc1->tmp = pc1->ax;
+       pc1->ax = pc1->si;
+       pc1->si = pc1->tmp;
+       pc1->ax = pc1->ax * pc1->bx;
+       pc1->dx = pc1->cx + pc1->dx;
+
+       pc1->ax = pc1->ax + 1;
+
+       pc1->x1a2 = pc1->dx;
+       pc1->x1a0[pc1->i] = pc1->ax;
+
+       pc1->res = pc1->ax ^ pc1->dx;
+       pc1->i = pc1->i + 1;
+}
+
+static void pc1_assemble(struct pc1_ctx *pc1)
+{
+       pc1->x1a0[0] = (pc1->cle[0] * 256) + pc1->cle[1];
+
+       pc1_code(pc1);
+       pc1->inter = pc1->res;
+
+       pc1->x1a0[1] = pc1->x1a0[0] ^ ((pc1->cle[2]*256) + pc1->cle[3]);
+       pc1_code(pc1);
+       pc1->inter = pc1->inter ^ pc1->res;
+
+       pc1->x1a0[2] = pc1->x1a0[1] ^ ((pc1->cle[4]*256) + pc1->cle[5]);
+       pc1_code(pc1);
+       pc1->inter = pc1->inter ^ pc1->res;
+
+       pc1->x1a0[3] = pc1->x1a0[2] ^ ((pc1->cle[6]*256) + pc1->cle[7]);
+       pc1_code(pc1);
+       pc1->inter = pc1->inter ^ pc1->res;
+
+       pc1->x1a0[4] = pc1->x1a0[3] ^ ((pc1->cle[8]*256) + pc1->cle[9]);
+       pc1_code(pc1);
+       pc1->inter = pc1->inter ^ pc1->res;
+
+       pc1->x1a0[5] = pc1->x1a0[4] ^ ((pc1->cle[10]*256) + pc1->cle[11]);
+       pc1_code(pc1);
+       pc1->inter = pc1->inter ^ pc1->res;
+
+       pc1->x1a0[6] = pc1->x1a0[5] ^ ((pc1->cle[12]*256) + pc1->cle[13]);
+       pc1_code(pc1);
+       pc1->inter = pc1->inter ^ pc1->res;
+
+       pc1->x1a0[7] = pc1->x1a0[6] ^ ((pc1->cle[14]*256) + pc1->cle[15]);
+       pc1_code(pc1);
+       pc1->inter = pc1->inter ^ pc1->res;
+
+       pc1->i = 0;
+}
+
+static unsigned char pc1_decrypt(struct pc1_ctx *pc1, short c)
+{
+       pc1_assemble(pc1);
+       pc1->cfc = pc1->inter >> 8;
+       pc1->cfd = pc1->inter & 255; /* cfc^cfd = random byte */
+
+       c = c ^ (pc1->cfc ^ pc1->cfd);
+       for (pc1->compte = 0; pc1->compte <= 15; pc1->compte++) {
+               /* we mix the plaintext byte with the key */
+               pc1->cle[pc1->compte] = pc1->cle[pc1->compte] ^ c;
+       }
+
+       return c;
+}
+
+static unsigned char pc1_encrypt(struct pc1_ctx *pc1, short c)
+{
+       pc1_assemble(pc1);
+       pc1->cfc = pc1->inter >> 8;
+       pc1->cfd = pc1->inter & 255; /* cfc^cfd = random byte */
+
+       for (pc1->compte = 0; pc1->compte <= 15; pc1->compte++) {
+               /* we mix the plaintext byte with the key */
+               pc1->cle[pc1->compte] = pc1->cle[pc1->compte] ^ c;
+       }
+       c = c ^ (pc1->cfc ^ pc1->cfd);
+
+       return c;
+}
+
+static void pc1_init(struct pc1_ctx *pc1)
+{
+       memset(pc1, 0, sizeof(struct pc1_ctx));
+
+       /* ('Remsaalps!123456') is the key used, you can change it */
+       strcpy(pc1->cle, "Remsaalps!123456");
+}
+
+static void pc1_decrypt_buf(struct pc1_ctx *pc1, unsigned char *buf,
+                           unsigned len)
+{
+       unsigned i;
+
+       for (i = 0; i < len; i++)
+               buf[i] = pc1_decrypt(pc1, buf[i]);
+}
+
+static void pc1_encrypt_buf(struct pc1_ctx *pc1, unsigned char *buf,
+                           unsigned len)
+{
+       unsigned i;
+
+       for (i = 0; i < len; i++)
+               buf[i] = pc1_encrypt(pc1, buf[i]);
+}
+
+/*
+ * Globals
+ */
+static char *ifname;
+static char *progname;
+static char *ofname;
+static int decrypt;
+
+/*
+ * Message macros
+ */
+#define ERR(fmt, ...) do { \
+       fflush(0); \
+       fprintf(stderr, "[%s] *** error: " fmt "\n", \
+                       progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERRS(fmt, ...) do { \
+       int save = errno; \
+       fflush(0); \
+       fprintf(stderr, "[%s] *** error: " fmt "\n", \
+                       progname, ## __VA_ARGS__, strerror(save)); \
+} while (0)
+
+void usage(int status)
+{
+       FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+       struct board_info *board;
+
+       fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+       fprintf(stream,
+"\n"
+"Options:\n"
+"  -d              decrypt instead of encrypt"
+"  -i <file>       read input from the file <file>\n"
+"  -o <file>       write output to the file <file>\n"
+"  -h              show this screen\n"
+       );
+
+       exit(status);
+}
+
+#define BUFSIZE                (64 * 1024)
+
+int main(int argc, char *argv[])
+{
+       struct pc1_ctx pc1;
+       int res = EXIT_FAILURE;
+       int err;
+       struct stat st;
+       char *buf;
+       unsigned total;
+
+       FILE *outfile, *infile;
+
+       progname = basename(argv[0]);
+
+       while ( 1 ) {
+               int c;
+
+               c = getopt(argc, argv, "di:o:h");
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'd':
+                       decrypt = 1;
+                       break;
+               case 'i':
+                       ifname = optarg;
+                       break;
+               case 'o':
+                       ofname = optarg;
+                       break;
+               case 'h':
+                       usage(EXIT_SUCCESS);
+                       break;
+               default:
+                       usage(EXIT_FAILURE);
+                       break;
+               }
+       }
+
+       if (ifname == NULL) {
+               ERR("no input file specified");
+               goto err;
+       }
+
+       if (ofname == NULL) {
+               ERR("no output file specified");
+               goto err;
+       }
+
+       err = stat(ifname, &st);
+       if (err){
+               ERRS("stat failed on %s", ifname);
+               goto err;
+       }
+
+       total = st.st_size;
+       buf = malloc(BUFSIZE);
+       if (!buf) {
+               ERR("no memory for buffer\n");
+               goto err;
+       }
+
+       infile = fopen(ifname, "r");
+       if (infile == NULL) {
+               ERRS("could not open \"%s\" for reading", ifname);
+               goto err_free;
+       }
+
+       outfile = fopen(ofname, "w");
+       if (outfile == NULL) {
+               ERRS("could not open \"%s\" for writing", ofname);
+               goto err_close_in;
+       }
+
+       pc1_init(&pc1);
+       while (total > 0) {
+               unsigned datalen;
+
+               if (total > BUFSIZE)
+                       datalen = BUFSIZE;
+               else
+                       datalen = total;
+
+               errno = 0;
+               fread(buf, datalen, 1, infile);
+               if (errno != 0) {
+                       ERRS("unable to read from file %s", ifname);
+                       goto err_close_out;
+               }
+
+               if (decrypt)
+                       pc1_decrypt_buf(&pc1, buf, datalen);
+               else
+                       pc1_encrypt_buf(&pc1, buf, datalen);
+
+               errno = 0;
+               fwrite(buf, datalen, 1, outfile);
+               if (errno) {
+                       ERRS("unable to write to file %s", ofname);
+                       goto err_close_out;
+               }
+
+               total -= datalen;
+       }
+       pc1_finish(&pc1);
+
+       res = EXIT_SUCCESS;
+
+ out_flush:
+       fflush(outfile);
+
+ err_close_out:
+       fclose(outfile);
+       if (res != EXIT_SUCCESS) {
+               unlink(ofname);
+       }
+
+ err_close_in:
+       fclose(infile);
+
+ err_free:
+       free(buf);
+
+ err:
+       return res;
+}
+
diff --git a/trunk/tools/firmware-utils/src/ptgen.c b/trunk/tools/firmware-utils/src/ptgen.c
new file mode 100644 (file)
index 0000000..6379ed7
--- /dev/null
@@ -0,0 +1,245 @@
+/* 
+ * ptgen - partition table generator
+ * Copyright (C) 2006 by Felix Fietkau <nbd@openwrt.org>
+ *
+ * uses parts of afdisk
+ * Copyright (C) 2002 by David Roetzel <david@roetzel.de>
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdint.h>
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define cpu_to_le16(x) bswap_16(x)
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+#define cpu_to_le16(x) (x)
+#else
+#error unknown endianness!
+#endif
+
+/* Partition table entry */
+struct pte { 
+       unsigned char active;
+       unsigned char chs_start[3];
+       unsigned char type;
+       unsigned char chs_end[3];
+       unsigned int start;
+       unsigned int length;
+};
+
+struct partinfo {
+       unsigned long size;
+       int type;
+};
+
+int verbose = 0;
+int active = 1;
+int heads = -1;
+int sectors = -1;
+int kb_align = 0;
+struct partinfo parts[4];
+char *filename = NULL;
+
+
+/* 
+ * parse the size argument, which is either
+ * a simple number (K assumed) or
+ * K, M or G
+ *
+ * returns the size in KByte
+ */
+static long to_kbytes(const char *string) {
+       int exp = 0;
+       long result;
+       char *end;
+
+       result = strtoul(string, &end, 0);
+       switch (tolower(*end)) {
+                       case 'k' :
+                       case '\0' : exp = 0; break;
+                       case 'm' : exp = 1; break;
+                       case 'g' : exp = 2; break;
+                       default: return 0;
+       }
+
+       if (*end)
+               end++;
+
+       if (*end) {
+               fprintf(stderr, "garbage after end of number\n");
+               return 0;
+       }
+
+       /* result: number + 1024^(exp) */
+       return result * ((2 << ((10 * exp) - 1)) ?: 1);
+}
+
+/* convert the sector number into a CHS value for the partition table */
+static void to_chs(long sect, unsigned char chs[3]) {
+       int c,h,s;
+       
+       s = (sect % sectors) + 1;
+       sect = sect / sectors;
+       h = sect % heads;
+       sect = sect / heads;
+       c = sect;
+
+       chs[0] = h;
+       chs[1] = s | ((c >> 2) & 0xC0);
+       chs[2] = c & 0xFF;
+
+       return;
+}
+
+/* round the sector number up to the next cylinder */
+static inline unsigned long round_to_cyl(long sect) {
+       int cyl_size = heads * sectors;
+
+       return sect + cyl_size - (sect % cyl_size); 
+}
+
+/* round the sector number up to the kb_align boundary */
+static inline unsigned long round_to_kb(long sect) {
+        return ((sect - 1) / kb_align + 1) * kb_align;
+}
+
+/* check the partition sizes and write the partition table */
+static int gen_ptable(uint32_t signature, int nr)
+{
+       struct pte pte[4];
+       unsigned long sect = 0; 
+       int i, fd, ret = -1, start, len;
+
+       memset(pte, 0, sizeof(struct pte) * 4);
+       for (i = 0; i < nr; i++) {
+               if (!parts[i].size) {
+                       fprintf(stderr, "Invalid size in partition %d!\n", i);
+                       return -1;
+               }
+               pte[i].active = ((i + 1) == active) ? 0x80 : 0;
+               pte[i].type = parts[i].type;
+               start = sect + sectors;
+               if (kb_align != 0)
+                       start = round_to_kb(start);
+               pte[i].start = cpu_to_le16(start);
+               sect = start + parts[i].size * 2;
+               if (kb_align == 0)
+                       sect = round_to_cyl(sect);
+               pte[i].length = cpu_to_le16(len = sect - start);
+               to_chs(start, pte[i].chs_start);
+               to_chs(start + len - 1, pte[i].chs_end);
+               if (verbose)
+                       fprintf(stderr, "Partition %d: start=%ld, end=%ld, size=%ld\n", i, (long) start * 512, ((long) start + (long) len) * 512, (long) len * 512);
+               printf("%ld\n", ((long) start * 512));
+               printf("%ld\n", ((long) len * 512));
+       }
+
+       if ((fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) {
+               fprintf(stderr, "Can't open output file '%s'\n",filename);
+               return -1;
+       }
+
+       lseek(fd, 440, SEEK_SET);
+       if (write(fd, &signature, sizeof(signature)) != sizeof(signature)) {
+               fprintf(stderr, "write failed.\n");
+               goto fail;
+       }
+
+       lseek(fd, 446, SEEK_SET);
+       if (write(fd, pte, sizeof(struct pte) * 4) != sizeof(struct pte) * 4) {
+               fprintf(stderr, "write failed.\n");
+               goto fail;
+       }
+       lseek(fd, 510, SEEK_SET);
+       if (write(fd, "\x55\xaa", 2) != 2) {
+               fprintf(stderr, "write failed.\n");
+               goto fail;
+       }
+       
+       ret = 0;
+fail:
+       close(fd);
+       return ret;
+}
+
+static void usage(char *prog)
+{
+       fprintf(stderr, "Usage: %s [-v] -h <heads> -s <sectors> -o <outputfile> [-a 0..4] [-l <align kB>] [[-t <type>] -p <size>...] \n", prog);
+       exit(1);
+}
+
+int main (int argc, char **argv)
+{
+       char type = 0x83;
+       int ch;
+       int part = 0;
+       uint32_t signature = 0x5452574F; /* 'OWRT' */
+
+       while ((ch = getopt(argc, argv, "h:s:p:a:t:o:vl:S:")) != -1) {
+               switch (ch) {
+               case 'o':
+                       filename = optarg;
+                       break;
+               case 'v':
+                       verbose++;
+                       break;
+               case 'h':
+                       heads = (int) strtoul(optarg, NULL, 0);
+                       break;
+               case 's':
+                       sectors = (int) strtoul(optarg, NULL, 0);
+                       break;
+               case 'p':
+                       if (part > 3) {
+                               fprintf(stderr, "Too many partitions\n");
+                               exit(1);
+                       }
+                       parts[part].size = to_kbytes(optarg);
+                       parts[part++].type = type;
+                       break;
+               case 't':
+                       type = (char) strtoul(optarg, NULL, 16);
+                       break;
+               case 'a':
+                       active = (int) strtoul(optarg, NULL, 0);
+                       if ((active < 0) || (active > 4))
+                               active = 0;
+                       break;
+               case 'l':
+                       kb_align = (int) strtoul(optarg, NULL, 0) * 2;
+                       break;
+               case 'S':
+                       signature = strtoul(optarg, NULL, 0);
+                       break;
+               case '?':
+               default:
+                       usage(argv[0]);
+               }
+       }
+       argc -= optind;
+       if (argc || (heads <= 0) || (sectors <= 0) || !filename) 
+               usage(argv[0]);
+
+       return gen_ptable(signature, part);
+}
diff --git a/trunk/tools/firmware-utils/src/seama.c b/trunk/tools/firmware-utils/src/seama.c
new file mode 100644 (file)
index 0000000..944ed3a
--- /dev/null
@@ -0,0 +1,529 @@
+/* vi: set sw=4 ts=4: */
+/*
+ *     Copyright (C) 2008, Alpha Networks, Inc.
+ *     Created by David Hsieh <david_hsieh@alphanetworks.com>
+ *     All right reserved.
+ *
+ *     (SEA)ttle i(MA)ge is the image which used in project seattle.
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1.      Redistributions of source code must retain the above
+ *             copyright notice, this list of conditions and the following
+ *             disclaimer.
+ *
+ *     2.      Redistributions in binary form must reproduce the above
+ *             copyright notice, this list of conditions and the following
+ *             disclaimer in the documentation and/or other materials
+ *             provided with the distribution.
+ *
+ *     3.      The name of the author may not be used to endorse or promote
+ *             products derived from this software without specific prior
+ *             written permission.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
+ *     EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ *     THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ *     PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR
+ *     BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ *     EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ *     TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ *     ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ *     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ *     IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ *     THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include <arpa/inet.h>
+
+#include "md5.h"
+#include "seama.h"
+
+#define PROGNAME                       "seama"
+#define VERSION                                "0.20"
+#define MAX_SEAMA_META_SIZE    1024
+#define MAX_META                       128
+#define MAX_IMAGE                      128
+
+extern int optind;
+extern char * optarg;
+
+static int             o_verbose = 0;          /* verbose mode. */
+static char *  o_dump = NULL;          /* Seama file to dump. */
+static char *  o_seal = NULL;          /* Seal the input images when file name exist. */
+static char *  o_extract = NULL;       /* Extract the seama file. */
+static char *  o_images[MAX_IMAGE];/* The image files to pack or seal */
+static int             o_isize = 0;            /* number of images */
+static char *  o_meta[MAX_META];       /* meta data array */
+static int             o_msize = 0;            /* size of meta array */
+
+static void verbose(const char * format, ...)
+{
+       va_list marker;
+       if (o_verbose)
+       {
+               va_start(marker, format);
+               vfprintf(stdout, format, marker);
+               va_end(marker);
+       }
+}
+
+static void cleanup_exit(int exit_code)
+{
+       verbose("%s: exit with code %d\n", PROGNAME, exit_code);
+       exit(exit_code);
+}
+
+static void show_usage(int exit_code)
+{
+       printf( PROGNAME " version " VERSION "\n"
+                       "usage: " PROGNAME " [OPTIONS]\n"
+                       "  -h                 show this help message.\n"
+                       "  -v                 verbose mode.\n"
+                       "  -m {META data}     META data.\n"
+                       "  -d {file}          dump the info of the seama file.\n"
+                       "  -i {input file}    image file name.\n"
+                       "  -s {file}          Seal the images to the seama file.\n"
+                       "  -x {seama file}    Extract the seama file.\n"
+                       "\n"
+                       "  SEAMA can pack the input file (with -i) into a seama file.\n"
+                       "  ex: seama -i target.file\n"
+                       "  SEAMA can also seal multiple seama files into a single seama file.\n"
+                       "  ex: seama -s final.file -i taget1.seama -i target2.seama\n"
+                       "  To extract the raw image from SEAMA, you need to specify the meta.\n"
+                       "  The first image match the specified meta will be extract to\n"
+                       "  the output file which was specified with '-x'.\n"
+                       "  ex: seama -x output -i seama.image -m file=sealpac\n"
+                       );
+       cleanup_exit(exit_code);
+}
+
+static int parse_args(int argc, char * argv[])
+{
+       int opt;
+
+       while ((opt = getopt(argc, argv, "hvd:s:i:m:x:")) > 0)
+       {
+               switch (opt)
+               {
+               default:        show_usage(-1); break;
+               case 'h':       show_usage(0); break;
+               case 'v':       o_verbose++; break;
+               case 'd':       o_dump = optarg; break;
+               case 's':       o_seal = optarg; break;
+               case 'x':       o_extract = optarg; break;
+               case 'i':
+                       if (o_isize < MAX_IMAGE) o_images[o_isize++] = optarg;
+                       else printf("Exceed the maximum acceptable image files.!\n");
+                       break;
+               case 'm':
+                       if (o_msize < MAX_META) o_meta[o_msize++] = optarg;
+                       else printf("Exceed the maximum acceptable META data.!\n");
+                       break;
+               }
+       }
+       return 0;
+}
+
+/*******************************************************************/
+
+static size_t calculate_digest(FILE * fh, size_t size, uint8_t * digest)
+{
+       MD5_CTX ctx;
+       size_t bytes_left, bytes_read, i;
+       uint8_t buf[MAX_SEAMA_META_SIZE];
+
+       bytes_left = size ? size : sizeof(buf);
+       bytes_read = 0;
+
+       MD5_Init(&ctx);
+       while (!feof(fh) && !ferror(fh) && bytes_left > 0)
+       {
+               i = bytes_left < sizeof(buf) ? bytes_left : sizeof(buf);
+               i = fread(buf, sizeof(char), i, fh);
+               if (i > 0)
+               {
+                       MD5_Update(&ctx, buf, i);
+                       bytes_read += i;
+               }
+               if (size) bytes_left -= i;
+       }
+       MD5_Final(digest, &ctx);
+       return bytes_read;
+}
+
+#define READ_BUFF_SIZE 8*1024
+static size_t copy_file(FILE * to, FILE * from)
+{
+       size_t i, fsize = 0;
+       uint8_t buf[READ_BUFF_SIZE];
+
+       while (!feof(from) && !ferror(from))
+       {
+               i = fread(buf, sizeof(uint8_t), READ_BUFF_SIZE, from);
+               if (i > 0)
+               {
+                       fsize += i;
+                       fwrite(buf, sizeof(uint8_t), i, to);
+               }
+       }
+       return fsize;
+}
+
+static int verify_seama(const char * fname, int msg)
+{
+       FILE * fh = NULL;
+       struct stat st;
+       seamahdr_t shdr;
+       uint8_t checksum[16];
+       uint8_t digest[16];
+       uint8_t buf[MAX_SEAMA_META_SIZE];
+       size_t msize, isize, i;
+       int ret = -1;
+
+#define ERRBREAK(fmt, args...) { if (msg) printf(fmt, ##args); break; }
+
+       do
+       {
+               if (stat(fname, &st) < 0)                               ERRBREAK("Unable to get the info of '%s'\n",fname);
+               if ((fh = fopen(fname, "r+"))==NULL)    ERRBREAK("Unable to open '%s' for reading!\n",fname);
+
+               /* Dump SEAMA header */
+               if (msg) printf("FILE - %s (%d bytes)\n", fname, (int)st.st_size);
+
+               /* SEAMA */
+               while (!feof(fh) && !ferror(fh))
+               {
+                       /* read header */
+                       if (fread(&shdr, sizeof(shdr), 1, fh) != 1) break;
+
+                       /* Check the magic number */
+                       if (shdr.magic != htonl(SEAMA_MAGIC)) ERRBREAK("Invalid SEAMA magic. Probably no more SEAMA!\n");
+
+                       /* Get the size */
+                       isize = ntohl(shdr.size);
+                       msize = ntohs(shdr.metasize);
+
+                       /* The checksum exist only if size is greater than zero. */
+                       if (isize > 0)
+                       {
+                               if (fread(checksum, sizeof(checksum), 1, fh) != 1)
+                                       ERRBREAK("Error reading checksum !\n");
+                       }
+
+                       /* Check the META size. */
+                       if (msize > sizeof(buf)) ERRBREAK("META data in SEAMA header is too large!\n");
+
+                       /* Read META data. */
+                       if (fread(buf, sizeof(char), msize, fh) != msize)
+                               ERRBREAK("Unable to read SEAMA META data!\n");
+
+                       /* dump header */
+                       if (msg)
+                       {
+                               printf("SEAMA ==========================================\n");
+                               printf("  magic      : %08x\n", ntohl(shdr.magic));
+                               printf("  meta size  : %d bytes\n", msize);
+                               for (i=0; i<msize; i+=(strlen((const char *)&buf[i])+1))
+                                       printf("  meta data  : %s\n", &buf[i]);
+                               printf("  image size : %d bytes\n", isize);
+                       }
+
+                       /* verify checksum */
+                       if (isize > 0)
+                       {
+                               if (msg)
+                               {
+                                       printf("  checksum   : ");
+                                       for (i=0; i<16; i++) printf("%02X", checksum[i]);
+                                       printf("\n");
+                               }
+
+                               /* Calculate the checksum */
+                               calculate_digest(fh, isize, digest);
+                               if (msg)
+                               {
+                                       printf("  digest     : ");
+                                       for (i=0; i<16; i++) printf("%02X", digest[i]);
+                                       printf("\n");
+                               }
+
+                               if (memcmp(checksum, digest, 16)!=0) ERRBREAK("!!ERROR!! checksum error !!\n");
+                               ret = 0;
+                       }
+               }
+               if (msg) printf("================================================\n");
+       } while (0);
+       if (fh) fclose(fh);
+       return ret;
+}
+
+static size_t write_seama_header(FILE * fh, char * meta[], size_t msize, size_t size)
+{
+       seamahdr_t shdr;
+       size_t i;
+       uint16_t metasize = 0;
+
+       /* Calculate the META size */
+       for (i=0; i<msize; i++) metasize += (strlen(meta[i]) + 1);
+       //+++ let meta data end on 4 alignment by siyou. 2010/3/1 03:58pm
+       metasize = ((metasize+3)/4)*4;
+       verbose("SEAMA META : %d bytes\n", metasize);
+
+       /* Fill up the header, all the data endian should be network byte order. */
+       shdr.magic              = htonl(SEAMA_MAGIC);
+       shdr.reserved   = 0;
+       shdr.metasize   = htons(metasize);
+       shdr.size               = htonl(size);
+
+       /* Write the header */
+       return fwrite(&shdr, sizeof(seamahdr_t), 1, fh);
+}
+
+static size_t write_checksum(FILE * fh, uint8_t * checksum)
+{
+       return fwrite(checksum, sizeof(uint8_t), 16, fh);
+}
+
+static size_t write_meta_data(FILE * fh, char * meta[], size_t size)
+{
+       size_t i,j;
+       size_t ret = 0;
+
+       for (i=0; i<size; i++)
+       {
+               verbose("SEAMA META data : %s\n", meta[i]);
+               j = fwrite(meta[i], sizeof(char), strlen(meta[i])+1, fh);
+               if (j != strlen(meta[i])+1) return 0;
+               ret += j;
+       }
+       //+++ let meta data end on 4 alignment by siyou. 2010/3/1 03:58pm
+       j = ((ret+3)/4)*4;
+       for ( ; ret < j; ret++)
+               fwrite("", sizeof(char), 1, fh);
+
+       return ret;
+}
+
+/*******************************************************************/
+
+static void dump_seama(const char * fname)
+{
+       verify_seama(fname, 1);
+}
+
+static void seal_files(const char * file)
+{
+       FILE * fh;
+       FILE * ifh;
+       size_t i;
+
+       /* Each image should be seama. */
+       for (i = 0; i < o_isize; i++)
+       {
+               if (verify_seama(o_images[i], 0) < 0)
+               {
+                       printf("'%s' is not a seama file !\n",o_images[i]);
+                       return;
+               }
+       }
+
+       /* Open file for write */
+       fh = fopen(file, "w+");
+       if (fh)
+       {
+               /* Write the header. */
+               write_seama_header(fh, o_meta, o_msize, 0);
+               write_meta_data(fh, o_meta, o_msize);
+
+               /* Write image files */
+               for (i=0; i<o_isize; i++)
+               {
+                       ifh = fopen(o_images[i], "r+");
+                       if (ifh)
+                       {
+                               copy_file(fh, ifh);
+                               fclose(ifh);
+                       }
+               }
+
+               fclose(fh);
+       }
+}
+
+static void pack_files(void)
+{
+       FILE * fh;
+       FILE * ifh;
+       size_t i, fsize;
+       char filename[512];
+       uint8_t digest[16];
+
+       for (i=0; i<o_isize; i++)
+       {
+               /* Open the input file. */
+               ifh = fopen(o_images[i], "r+");
+               if (ifh)
+               {
+                       fsize = calculate_digest(ifh, 0, digest);
+                       verbose("file size (%s) : %d\n", o_images[i], fsize);
+                       rewind(ifh);
+
+                       /* Open the output file. */
+                       sprintf(filename, "%s.seama", o_images[i]);
+                       fh = fopen(filename, "w+");
+                       if (fh)
+                       {
+                               write_seama_header(fh, o_meta, o_msize, fsize);
+                               write_checksum(fh, digest);
+                               write_meta_data(fh, o_meta, o_msize);
+                               copy_file(fh, ifh);
+                               fclose(fh);
+                       }
+                       fclose(ifh);
+               }
+               else
+               {
+                       printf("Unable to open image file '%s'\n",o_images[i]);
+               }
+       }
+}
+
+/**************************************************************************/
+
+static int match_meta(const char * meta, size_t size)
+{
+       size_t i, j;
+       int match;
+
+       for (i = 0; i < o_msize; i++)
+       {
+               for (match = 0, j = 0; j < size; j += (strlen(&meta[j])+1))
+                       if (strcmp(&meta[j], o_meta[i])==0) { match++; break; }
+               if (!match) return 0;
+       }
+       return 1;
+}
+
+
+static void extract_file(const char * output)
+{
+       FILE * ifh = NULL;
+       FILE * ofh = NULL;
+       size_t msize, isize, i, m;
+       seamahdr_t shdr;
+       uint8_t buf[MAX_SEAMA_META_SIZE];
+       int done = 0;
+
+       /* We need meta for searching the target image. */
+       if (o_msize == 0)
+       {
+               printf("SEAMA: need meta for searching image.\n");
+               return;
+       }
+
+       /* Walk through each input file */
+       for (i = 0; i < o_isize; i++)
+       {
+               /* verify the input file */
+               if (verify_seama(o_images[i], 0) < 0)
+               {
+                       printf("SEAMA: '%s' is not a seama file !\n", o_images[i]);
+                       continue;
+               }
+               /* open the input file */
+               ifh  = fopen(o_images[i], "r");
+               if (!ifh) continue;
+               /* read file */
+               while (!feof(ifh) && !ferror(ifh))
+               {
+                       /* read header */
+                       fread(&shdr, sizeof(shdr), 1, ifh);
+                       if (shdr.magic != htonl(SEAMA_MAGIC)) break;
+                       /* Get the size */
+                       isize = ntohl(shdr.size);
+                       msize = ntohs(shdr.metasize);
+                       if (isize == 0)
+                       {
+                               while (msize > 0)
+                               {
+                                       m = fread(buf, sizeof(char), (msize < MAX_SEAMA_META_SIZE) ? msize : MAX_SEAMA_META_SIZE, ifh);
+                                       if (m <= 0) break;
+                                       msize -= m;
+                               }
+                               continue;
+                       }
+                       /* read checksum */
+                       fread(buf, sizeof(char), 16, ifh);
+                       if (msize > 0)
+                       {
+                               /* read META */
+                               fread(buf, sizeof(char), msize, ifh);
+                               if (match_meta((const char *)buf, msize))
+                               {
+                                       printf("SEAMA: found image @ '%s', image size: %d\n", o_images[i], isize);
+                                       /* open output file */
+                                       ofh = fopen(output, "w");
+                                       if (!ofh) printf("SEAMA: unable to open '%s' for writting.\n",output);
+                                       else
+                                       {
+                                               while (isize > 0)
+                                               {
+                                                       m = fread(buf, sizeof(char), (isize < MAX_SEAMA_META_SIZE) ? isize : MAX_SEAMA_META_SIZE, ifh);
+                                                       if (m <= 0) break;
+                                                       fwrite(buf, sizeof(char), m, ofh);
+                                                       isize -= m;
+                                               }
+                                               fclose(ofh);
+                                       }
+                                       done++;
+                                       break;
+                               }
+                       }
+                       while (isize > 0)
+                       {
+                               m = fread(buf, sizeof(char), (isize < MAX_SEAMA_META_SIZE) ? isize : MAX_SEAMA_META_SIZE, ifh);
+                               if (m <= 0) break;
+                               isize -= m;
+                       }
+               }
+               /* close the file. */
+               fclose(ifh);
+               if (done) break;
+       }
+       return;
+}
+
+/*******************************************************************/
+#ifdef RGBIN_BOX
+int seama_main(int argc, char * argv[], char * env[])
+#else
+int main(int argc, char * argv[], char * env[])
+#endif
+{
+       verbose("SEAMA version " VERSION "\n");
+
+       /* parse the arguments */
+       if (parse_args(argc, argv) < 0) show_usage(9);
+
+       /* Do the works */
+       if              (o_dump)        dump_seama(o_dump);
+       else if (o_seal)        seal_files(o_seal);
+       else if (o_extract)     extract_file(o_extract);
+       else                            pack_files();
+
+       cleanup_exit(0);
+       return 0;
+}
diff --git a/trunk/tools/firmware-utils/src/seama.h b/trunk/tools/firmware-utils/src/seama.h
new file mode 100644 (file)
index 0000000..02683b6
--- /dev/null
@@ -0,0 +1,108 @@
+/* vi: set sw=4 ts=4: */
+/*
+ *     (SEA)ttle i(MA)ge is the image which used in project seattle.
+ *
+ *     Created by David Hsieh <david_hsieh@alphanetworks.com>
+ *     Copyright (C) 2008-2009 Alpha Networks, Inc.
+ *
+ *     This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU Lesser General Public
+ *     License as published by the Free Software Foundation; either'
+ *     version 2.1 of the License, or (at your option) any later version.
+ *
+ *     The GNU C Library 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
+ *     Lesser General Public License for more details.
+ *
+ *     You should have received a copy of the GNU Lesser General Public
+ *     License along with the GNU C Library; if not, write to the Free
+ *     Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *     02111-1307 USA.
+ */
+
+#ifndef __SEAMA_HEADER_FILE__
+#define __SEAMA_HEADER_FILE__
+
+#include <stdint.h>
+
+#define SEAMA_MAGIC            0x5EA3A417
+
+/*
+ *     SEAMA looks like the following map.
+ *     All the data of the header should be in network byte order.
+ *
+ *  +-------------+-------------+------------
+ *     | SEAMA magic               |     ^
+ *  +-------------+-------------+     |
+ *     | reserved    | meta size   |     |
+ *  +-------------+-------------+   header
+ *     | image size (0 bytes)      |     |
+ *  +-------------+-------------+     |
+ *     ~ Meta data                 ~     v
+ *  +-------------+-------------+------------
+ *     | SEAMA magic               |   ^     ^
+ *  +-------------+-------------+   |     |
+ *     | reserved    | meta size   |   |     |
+ *  +-------------+-------------+   |     |
+ *     | image size                |   |     |
+ *  +-------------+-------------+ header  |
+ *     |                           |   |     |
+ *     | 16 bytes of MD5 digest    |   |     |
+ *     |                           |   |     |
+ *     |                           |   |     |
+ *  +-------------+-------------+   |     |
+ *     ~ Meta data                 ~   v     |
+ *  +-------------+-------------+-------  |
+ *     |                           |         |
+ *     | Image of the 1st entity   |         |
+ *     ~                           ~ 1st entity
+ *     |                           |         |
+ *     |                           |         v
+ *  +-------------+-------------+-------------
+ *     | SEAMA magic               |   ^     ^
+ *  +-------------+-------------+   |     |
+ *     | reserved    | meta size   |   |     |
+ *  +-------------+-------------+   |     |
+ *     | image size                |   |     |
+ *  +-------------+-------------+ header  |
+ *     |                           |   |     |
+ *     | 16 bytes of MD5 digest    |   |     |
+ *     |                           |   |     |
+ *     |                           |   |     |
+ *  +-------------+-------------+   |     |
+ *     ~ Meta data                 ~   v     |
+ *  +-------------+-------------+-------  |
+ *     |                           |         |
+ *     | Image of the 2nd entity   |         |
+ *     ~                           ~ 2nd entity
+ *     |                           |         |
+ *     |                           |         v
+ *  +-------------+-------------+-------------
+ */
+
+
+/*
+ *     SEAMA header
+ *
+ *     |<-------- 32 bits -------->|
+ *  +-------------+-------------+
+ *     | SEAMA magic               |
+ *  +-------------+-------------+
+ *     | reserved    | meta size   |
+ *  +-------------+-------------+
+ *     | image size                |
+ *  +-------------+-------------+
+ */
+/* seama header */
+typedef struct seama_hdr       seamahdr_t;
+struct seama_hdr
+{
+       uint32_t        magic;                  /* should always be SEAMA_MAGIC. */
+       uint16_t        reserved;               /* reserved for  */
+       uint16_t        metasize;               /* size of the META data */
+       uint32_t        size;                   /* size of the image */
+} __attribute__ ((packed));
+
+
+#endif
diff --git a/trunk/tools/firmware-utils/src/sha1.c b/trunk/tools/firmware-utils/src/sha1.c
new file mode 100644 (file)
index 0000000..3ab1332
--- /dev/null
@@ -0,0 +1,443 @@
+/*
+ *  FIPS-180-1 compliant SHA-1 implementation
+ *
+ *  Copyright (C) 2003-2006  Christophe Devine
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License, version 2.1 as published by the Free Software Foundation.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA  02110-1301  USA
+ */
+/*
+ *  The SHA-1 standard was published by NIST in 1993.
+ *
+ *  http://www.itl.nist.gov/fipspubs/fip180-1.htm
+ */
+
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+
+#include <string.h>
+#include <stdio.h>
+
+#include "sha1.h"
+
+/* 
+ * 32-bit integer manipulation macros (big endian)
+ */
+#ifndef GET_UINT32_BE
+#define GET_UINT32_BE(n,b,i)                    \
+{                                               \
+    (n) = ( (ulong) (b)[(i)    ] << 24 )        \
+        | ( (ulong) (b)[(i) + 1] << 16 )        \
+        | ( (ulong) (b)[(i) + 2] <<  8 )        \
+        | ( (ulong) (b)[(i) + 3]       );       \
+}
+#endif
+#ifndef PUT_UINT32_BE
+#define PUT_UINT32_BE(n,b,i)                    \
+{                                               \
+    (b)[(i)    ] = (uchar) ( (n) >> 24 );       \
+    (b)[(i) + 1] = (uchar) ( (n) >> 16 );       \
+    (b)[(i) + 2] = (uchar) ( (n) >>  8 );       \
+    (b)[(i) + 3] = (uchar) ( (n)       );       \
+}
+#endif
+
+/*
+ * Core SHA-1 functions
+ */
+void sha1_starts( sha1_context *ctx )
+{
+    ctx->total[0] = 0;
+    ctx->total[1] = 0;
+
+    ctx->state[0] = 0x67452301;
+    ctx->state[1] = 0xEFCDAB89;
+    ctx->state[2] = 0x98BADCFE;
+    ctx->state[3] = 0x10325476;
+    ctx->state[4] = 0xC3D2E1F0;
+}
+
+void sha1_process( sha1_context *ctx, uchar data[64] )
+{
+    ulong temp, W[16], A, B, C, D, E;
+
+    GET_UINT32_BE( W[0],  data,  0 );
+    GET_UINT32_BE( W[1],  data,  4 );
+    GET_UINT32_BE( W[2],  data,  8 );
+    GET_UINT32_BE( W[3],  data, 12 );
+    GET_UINT32_BE( W[4],  data, 16 );
+    GET_UINT32_BE( W[5],  data, 20 );
+    GET_UINT32_BE( W[6],  data, 24 );
+    GET_UINT32_BE( W[7],  data, 28 );
+    GET_UINT32_BE( W[8],  data, 32 );
+    GET_UINT32_BE( W[9],  data, 36 );
+    GET_UINT32_BE( W[10], data, 40 );
+    GET_UINT32_BE( W[11], data, 44 );
+    GET_UINT32_BE( W[12], data, 48 );
+    GET_UINT32_BE( W[13], data, 52 );
+    GET_UINT32_BE( W[14], data, 56 );
+    GET_UINT32_BE( W[15], data, 60 );
+
+#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
+
+#define R(t)                                            \
+(                                                       \
+    temp = W[(t -  3) & 0x0F] ^ W[(t - 8) & 0x0F] ^     \
+           W[(t - 14) & 0x0F] ^ W[ t      & 0x0F],      \
+    ( W[t & 0x0F] = S(temp,1) )                         \
+)
+
+#define P(a,b,c,d,e,x)                                  \
+{                                                       \
+    e += S(a,5) + F(b,c,d) + K + x; b = S(b,30);        \
+}
+
+    A = ctx->state[0];
+    B = ctx->state[1];
+    C = ctx->state[2];
+    D = ctx->state[3];
+    E = ctx->state[4];
+
+#define F(x,y,z) (z ^ (x & (y ^ z)))
+#define K 0x5A827999
+
+    P( A, B, C, D, E, W[0]  );
+    P( E, A, B, C, D, W[1]  );
+    P( D, E, A, B, C, W[2]  );
+    P( C, D, E, A, B, W[3]  );
+    P( B, C, D, E, A, W[4]  );
+    P( A, B, C, D, E, W[5]  );
+    P( E, A, B, C, D, W[6]  );
+    P( D, E, A, B, C, W[7]  );
+    P( C, D, E, A, B, W[8]  );
+    P( B, C, D, E, A, W[9]  );
+    P( A, B, C, D, E, W[10] );
+    P( E, A, B, C, D, W[11] );
+    P( D, E, A, B, C, W[12] );
+    P( C, D, E, A, B, W[13] );
+    P( B, C, D, E, A, W[14] );
+    P( A, B, C, D, E, W[15] );
+    P( E, A, B, C, D, R(16) );
+    P( D, E, A, B, C, R(17) );
+    P( C, D, E, A, B, R(18) );
+    P( B, C, D, E, A, R(19) );
+
+#undef K
+#undef F
+
+#define F(x,y,z) (x ^ y ^ z)
+#define K 0x6ED9EBA1
+
+    P( A, B, C, D, E, R(20) );
+    P( E, A, B, C, D, R(21) );
+    P( D, E, A, B, C, R(22) );
+    P( C, D, E, A, B, R(23) );
+    P( B, C, D, E, A, R(24) );
+    P( A, B, C, D, E, R(25) );
+    P( E, A, B, C, D, R(26) );
+    P( D, E, A, B, C, R(27) );
+    P( C, D, E, A, B, R(28) );
+    P( B, C, D, E, A, R(29) );
+    P( A, B, C, D, E, R(30) );
+    P( E, A, B, C, D, R(31) );
+    P( D, E, A, B, C, R(32) );
+    P( C, D, E, A, B, R(33) );
+    P( B, C, D, E, A, R(34) );
+    P( A, B, C, D, E, R(35) );
+    P( E, A, B, C, D, R(36) );
+    P( D, E, A, B, C, R(37) );
+    P( C, D, E, A, B, R(38) );
+    P( B, C, D, E, A, R(39) );
+
+#undef K
+#undef F
+
+#define F(x,y,z) ((x & y) | (z & (x | y)))
+#define K 0x8F1BBCDC
+
+    P( A, B, C, D, E, R(40) );
+    P( E, A, B, C, D, R(41) );
+    P( D, E, A, B, C, R(42) );
+    P( C, D, E, A, B, R(43) );
+    P( B, C, D, E, A, R(44) );
+    P( A, B, C, D, E, R(45) );
+    P( E, A, B, C, D, R(46) );
+    P( D, E, A, B, C, R(47) );
+    P( C, D, E, A, B, R(48) );
+    P( B, C, D, E, A, R(49) );
+    P( A, B, C, D, E, R(50) );
+    P( E, A, B, C, D, R(51) );
+    P( D, E, A, B, C, R(52) );
+    P( C, D, E, A, B, R(53) );
+    P( B, C, D, E, A, R(54) );
+    P( A, B, C, D, E, R(55) );
+    P( E, A, B, C, D, R(56) );
+    P( D, E, A, B, C, R(57) );
+    P( C, D, E, A, B, R(58) );
+    P( B, C, D, E, A, R(59) );
+
+#undef K
+#undef F
+
+#define F(x,y,z) (x ^ y ^ z)
+#define K 0xCA62C1D6
+
+    P( A, B, C, D, E, R(60) );
+    P( E, A, B, C, D, R(61) );
+    P( D, E, A, B, C, R(62) );
+    P( C, D, E, A, B, R(63) );
+    P( B, C, D, E, A, R(64) );
+    P( A, B, C, D, E, R(65) );
+    P( E, A, B, C, D, R(66) );
+    P( D, E, A, B, C, R(67) );
+    P( C, D, E, A, B, R(68) );
+    P( B, C, D, E, A, R(69) );
+    P( A, B, C, D, E, R(70) );
+    P( E, A, B, C, D, R(71) );
+    P( D, E, A, B, C, R(72) );
+    P( C, D, E, A, B, R(73) );
+    P( B, C, D, E, A, R(74) );
+    P( A, B, C, D, E, R(75) );
+    P( E, A, B, C, D, R(76) );
+    P( D, E, A, B, C, R(77) );
+    P( C, D, E, A, B, R(78) );
+    P( B, C, D, E, A, R(79) );
+
+#undef K
+#undef F
+
+    ctx->state[0] += A;
+    ctx->state[1] += B;
+    ctx->state[2] += C;
+    ctx->state[3] += D;
+    ctx->state[4] += E;
+}
+
+void sha1_update( sha1_context *ctx, uchar *input, uint length )
+{
+    ulong left, fill;
+
+    if( ! length ) return;
+
+    left = ctx->total[0] & 0x3F;
+    fill = 64 - left;
+
+    ctx->total[0] += length;
+    ctx->total[0] &= 0xFFFFFFFF;
+
+    if( ctx->total[0] < length )
+        ctx->total[1]++;
+
+    if( left && length >= fill )
+    {
+        memcpy( (void *) (ctx->buffer + left),
+                (void *) input, fill );
+        sha1_process( ctx, ctx->buffer );
+        length -= fill;
+        input  += fill;
+        left = 0;
+    }
+
+    while( length >= 64 )
+    {
+        sha1_process( ctx, input );
+        length -= 64;
+        input  += 64;
+    }
+
+    if( length )
+    {
+        memcpy( (void *) (ctx->buffer + left),
+                (void *) input, length );
+    }
+}
+
+static uchar sha1_padding[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
+};
+
+void sha1_finish( sha1_context *ctx, uchar digest[20] )
+{
+    ulong last, padn;
+    ulong high, low;
+    uchar msglen[8];
+
+    high = ( ctx->total[0] >> 29 )
+         | ( ctx->total[1] <<  3 );
+    low  = ( ctx->total[0] <<  3 );
+
+    PUT_UINT32_BE( high, msglen, 0 );
+    PUT_UINT32_BE( low,  msglen, 4 );
+
+    last = ctx->total[0] & 0x3F;
+    padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
+
+    sha1_update( ctx, sha1_padding, padn );
+    sha1_update( ctx, msglen, 8 );
+
+    PUT_UINT32_BE( ctx->state[0], digest,  0 );
+    PUT_UINT32_BE( ctx->state[1], digest,  4 );
+    PUT_UINT32_BE( ctx->state[2], digest,  8 );
+    PUT_UINT32_BE( ctx->state[3], digest, 12 );
+    PUT_UINT32_BE( ctx->state[4], digest, 16 );
+}
+
+/*
+ * Output SHA-1(file contents), returns 0 if successful.
+ */
+int sha1_file( char *filename, uchar digest[20] )
+{
+    FILE *f;
+    size_t n;
+    sha1_context ctx;
+    uchar buf[1024];
+
+    if( ( f = fopen( filename, "rb" ) ) == NULL )
+        return( 1 );
+
+    sha1_starts( &ctx );
+
+    while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 )
+        sha1_update( &ctx, buf, (uint) n );
+
+    sha1_finish( &ctx, digest );
+
+    fclose( f );
+    return( 0 );
+}
+
+/*
+ * Output SHA-1(buf)
+ */
+void sha1_csum( uchar *buf, uint buflen, uchar digest[20] )
+{
+    sha1_context ctx;
+
+    sha1_starts( &ctx );
+    sha1_update( &ctx, buf, buflen );
+    sha1_finish( &ctx, digest );
+}
+
+/*
+ * Output HMAC-SHA-1(key,buf)
+ */
+void sha1_hmac( uchar *key, uint keylen, uchar *buf, uint buflen,
+                uchar digest[20] )
+{
+    uint i;
+    sha1_context ctx;
+    uchar k_ipad[64];
+    uchar k_opad[64];
+    uchar tmpbuf[20];
+
+    memset( k_ipad, 0x36, 64 );
+    memset( k_opad, 0x5C, 64 );
+
+    for( i = 0; i < keylen; i++ )
+    {
+        if( i >= 64 ) break;
+
+        k_ipad[i] ^= key[i];
+        k_opad[i] ^= key[i];
+    }
+
+    sha1_starts( &ctx );
+    sha1_update( &ctx, k_ipad, 64 );
+    sha1_update( &ctx, buf, buflen );
+    sha1_finish( &ctx, tmpbuf );
+
+    sha1_starts( &ctx );
+    sha1_update( &ctx, k_opad, 64 );
+    sha1_update( &ctx, tmpbuf, 20 );
+    sha1_finish( &ctx, digest );
+
+    memset( k_ipad, 0, 64 );
+    memset( k_opad, 0, 64 );
+    memset( tmpbuf, 0, 20 );
+    memset( &ctx, 0, sizeof( sha1_context ) );
+}
+
+#ifdef SELF_TEST
+/* 
+ * FIPS-180-1 test vectors
+ */
+static char *sha1_test_str[3] = 
+{
+    "abc",
+    "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+    NULL
+};
+
+static uchar sha1_test_sum[3][20] =
+{
+    { 0xA9, 0x99, 0x3E, 0x36, 0x47, 0x06, 0x81, 0x6A, 0xBA, 0x3E,
+      0x25, 0x71, 0x78, 0x50, 0xC2, 0x6C, 0x9C, 0xD0, 0xD8, 0x9D },
+    { 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E, 0xBA, 0xAE,
+      0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5, 0xE5, 0x46, 0x70, 0xF1 },
+    { 0x34, 0xAA, 0x97, 0x3C, 0xD4, 0xC4, 0xDA, 0xA4, 0xF6, 0x1E,
+      0xEB, 0x2B, 0xDB, 0xAD, 0x27, 0x31, 0x65, 0x34, 0x01, 0x6F }
+};
+
+/*
+ * Checkup routine
+ */
+int sha1_self_test( void )
+{
+    int i, j;
+    uchar buf[1000];
+    uchar sha1sum[20];
+    sha1_context ctx;
+
+    for( i = 0; i < 3; i++ )
+    {
+        printf( "  SHA-1 test #%d: ", i + 1 );
+
+        sha1_starts( &ctx );
+
+        if( i < 2 )
+            sha1_update( &ctx, (uchar *) sha1_test_str[i],
+                         strlen( sha1_test_str[i] ) );
+        else
+        {
+            memset( buf, 'a', 1000 );
+            for( j = 0; j < 1000; j++ )
+                sha1_update( &ctx, (uchar *) buf, 1000 );
+        }
+
+        sha1_finish( &ctx, sha1sum );
+
+        if( memcmp( sha1sum, sha1_test_sum[i], 20 ) != 0 )
+        {
+            printf( "failed\n" );
+            return( 1 );
+        }
+
+        printf( "passed\n" );
+    }
+
+    printf( "\n" );
+    return( 0 );
+}
+#else
+int sha1_self_test( void )
+{
+    printf( "SHA-1 self-test not available\n\n" );
+    return( 1 );
+}
+#endif
diff --git a/trunk/tools/firmware-utils/src/sha1.h b/trunk/tools/firmware-utils/src/sha1.h
new file mode 100644 (file)
index 0000000..425267a
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef _SHA1_H
+#define _SHA1_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _STD_TYPES
+#define _STD_TYPES
+
+#define uchar   unsigned char
+#define uint    unsigned int
+#define ulong   unsigned long int
+
+#endif
+
+typedef struct
+{
+    ulong total[2];
+    ulong state[5];
+    uchar buffer[64];
+}
+sha1_context;
+
+/*
+ * Core SHA-1 functions
+ */
+void sha1_starts( sha1_context *ctx );
+void sha1_update( sha1_context *ctx, uchar *input, uint length );
+void sha1_finish( sha1_context *ctx, uchar digest[20] );
+
+/*
+ * Output SHA-1(file contents), returns 0 if successful.
+ */
+int sha1_file( char *filename, uchar digest[20] );
+
+/*
+ * Output SHA-1(buf)
+ */
+void sha1_csum( uchar *buf, uint buflen, uchar digest[20] );
+
+/*
+ * Output HMAC-SHA-1(key,buf)
+ */
+void sha1_hmac( uchar *key, uint keylen, uchar *buf, uint buflen,
+                uchar digest[20] );
+
+/*
+ * Checkup routine
+ */
+int sha1_self_test( void );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* sha1.h */
diff --git a/trunk/tools/firmware-utils/src/spw303v.c b/trunk/tools/firmware-utils/src/spw303v.c
new file mode 100644 (file)
index 0000000..202ffba
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * spw303v.c - partially based on libreCMC's imagetag.c and addpattern.c
+ *
+ * Copyright (C) 2011  Jonas Gorski <jonas.gorski@gmail.com>
+ *
+ * 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
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#define IMAGE_LEN 10                   /* Length of Length Field */
+#define ADDRESS_LEN 12                 /* Length of Address field */
+#define TAGID_LEN  6                   /* Length of tag ID */
+#define TAGINFO_LEN 20                 /* Length of vendor information field in tag */
+#define TAGVER_LEN 4                   /* Length of Tag Version */
+#define TAGLAYOUT_LEN 4                /* Length of FlashLayoutVer */
+
+
+struct spw303v_tag
+{
+    unsigned char tagVersion[4];       // tag version.  Will be 2 here.
+    unsigned char signiture_1[20];                      // text line for company info
+    unsigned char signiture_2[14];                     // additional info (can be version number)
+    unsigned char chipId[6];                                   // chip id
+    unsigned char boardId[16];                         // board id
+    unsigned char bigEndian[2];                        // if = 1 - big, = 0 - little endia of the host
+    unsigned char totalImageLen[IMAGE_LEN];      // the sum of all the following length
+    unsigned char cfeAddress[ADDRESS_LEN];       // if non zero, cfe starting address
+    unsigned char cfeLen[IMAGE_LEN];             // if non zero, cfe size in clear ASCII text.
+    unsigned char rootfsAddress[ADDRESS_LEN];    // if non zero, filesystem starting address
+    unsigned char rootfsLen[IMAGE_LEN];          // if non zero, filesystem size in clear ASCII text.
+    unsigned char kernelAddress[ADDRESS_LEN];    // if non zero, kernel starting address
+    unsigned char kernelLen[IMAGE_LEN];          // if non zero, kernel size in clear ASCII text.
+
+       unsigned char certf1Address[ADDRESS_LEN];
+       unsigned char certf1Len[6];
+       unsigned char certf2Address[ADDRESS_LEN];
+       unsigned char certf2Len[6];
+       unsigned char certf3Address[ADDRESS_LEN];
+       unsigned char certf3Len[6];
+       unsigned char httpsFileSize[4];
+       unsigned char tr64FileSize[4];
+       unsigned char tr69FileSize[4];
+       unsigned char filesmap[4];
+
+    unsigned char imageSequence[4];                            // incrments everytime an image is flashed
+    unsigned char reserved[4];                                     // reserved for later use
+    unsigned char imageCRC[4];                      // 216-219: CRC32 of images
+    unsigned char reserved2[16];                    // 220-235: Unused at present
+    unsigned char headerCRC[4];                     // 236-239: CRC32 of header excluding tagVersion
+    unsigned char reserved3[16];                    // 240-255: Unused at present
+};
+
+static uint32_t crc32tab[256] = {
+       0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
+       0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
+       0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
+       0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
+       0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
+       0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
+       0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
+       0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
+       0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
+       0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
+       0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
+       0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
+       0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
+       0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
+       0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+       0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
+       0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
+       0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
+       0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
+       0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
+       0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+       0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
+       0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
+       0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
+       0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
+       0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
+       0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
+       0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
+       0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
+       0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+       0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
+       0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
+};
+#define IMAGETAG_CRC_START                     0xFFFFFFFF
+
+#define IMAGETAG_MAGIC1_TCOM           "AAAAAAAA Corporatio"
+
+static char fake_data[] = {
+        0x18, 0x21, 0x21, 0x18, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21 ,0x18,
+        0x21, 0x24, 0x21, 0x1b, 0x18, 0x18, 0x24, 0x24, 0x18, 0x21, 0x21, 0x21,
+        0x21, 0x21, 0x21, 0x21, 0x1b, 0x18, 0x18, 0x24, 0x24, 0x21, 0x21, 0x21,
+        0x21, 0x21, 0x21, 0x21, 0x18, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x18,
+        0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x18, 0x21, 0x21,
+        0x21, 0x21, 0x21, 0x21,
+};
+
+
+uint32_t crc32(uint32_t crc, uint8_t *data, size_t len)
+{
+       while (len--)
+               crc = (crc >> 8) ^ crc32tab[(crc ^ *data++) & 0xFF];
+
+       return crc;
+}
+
+void fix_header(void *buf)
+{
+       struct spw303v_tag *tag = buf;
+       uint32_t crc;
+       /* Replace signature with custom t-com one */
+       memset(tag->signiture_1, 0, 20);
+       memcpy(tag->signiture_1, IMAGETAG_MAGIC1_TCOM, strlen(IMAGETAG_MAGIC1_TCOM));
+
+       /* Clear cert fields to remove information_* data */
+       memset(tag->certf1Address, 0, 74);
+
+       /* replace image crc with modified one */
+       crc = ntohl(*((uint32_t *)&tag->imageCRC));
+
+       crc = htonl(crc32(crc, fake_data, 64));
+
+       memcpy(tag->imageCRC, &crc, 4);
+
+       /* Update tag crc */
+       crc = htonl(crc32(IMAGETAG_CRC_START, buf, 236));
+       memcpy(tag->headerCRC, &crc, 4);
+}
+
+
+
+void usage(void) __attribute__ (( __noreturn__ ));
+
+void usage(void)
+{
+       fprintf(stderr, "Usage: spw303v [-i <inputfile>] [-o <outputfile>]\n");
+       exit(EXIT_FAILURE);
+}
+
+
+int main(int argc, char **argv)
+{
+       char buf[1024]; /* keep this at 1k or adjust garbage calc below */
+       FILE *in = stdin;
+       FILE *out = stdout;
+       char *ifn = NULL;
+       char *ofn = NULL;
+       int c;
+       int v0, v1, v2;
+       size_t n;
+       int first_block = 1;
+
+       uint32_t image_crc = IMAGETAG_CRC_START;
+
+       while ((c = getopt(argc, argv, "i:o:h")) != -1) {
+               switch (c) {
+                       case 'i':
+                               ifn = optarg;
+                               break;
+                       case 'o':
+                               ofn = optarg;
+                               break;
+                       case 'h':
+                       default:
+                               usage();
+               }
+       }
+
+       if (optind != argc || optind == 1) {
+               fprintf(stderr, "illegal arg \"%s\"\n", argv[optind]);
+               usage();
+       }
+
+       if (ifn && !(in = fopen(ifn, "r"))) {
+               fprintf(stderr, "can not open \"%s\" for reading\n", ifn);
+               usage();
+       }
+
+       if (ofn && !(out = fopen(ofn, "w"))) {
+               fprintf(stderr, "can not open \"%s\" for writing\n", ofn);
+               usage();
+       }
+
+
+
+       while ((n = fread(buf, 1, sizeof(buf), in)) > 0) {
+               if (n < sizeof(buf)) {
+                       if (ferror(in)) {
+                       FREAD_ERROR:
+                               fprintf(stderr, "fread error\n");
+                               return EXIT_FAILURE;
+                       }
+               }
+
+               if (first_block && n >= 256) {
+                       fix_header(buf);
+                       first_block = 0;
+               }
+
+               image_crc = crc32(image_crc, buf, n);
+
+               if (!fwrite(buf, n, 1, out)) {
+               FWRITE_ERROR:
+                       fprintf(stderr, "fwrite error\n");
+                       return EXIT_FAILURE;
+               }
+       }
+
+       if (ferror(in)) {
+               goto FREAD_ERROR;
+       }
+
+       if (fflush(out)) {
+               goto FWRITE_ERROR;
+       }
+
+       fclose(in);
+       fclose(out);
+
+       return EXIT_SUCCESS;
+}
diff --git a/trunk/tools/firmware-utils/src/srec2bin.c b/trunk/tools/firmware-utils/src/srec2bin.c
new file mode 100644 (file)
index 0000000..1cffbae
--- /dev/null
@@ -0,0 +1,524 @@
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+//Rev 0.1 Original
+// 8 Jan 2001  MJH  Added code to write data to Binary file
+//                  note: outputfile is name.bin, where name is first part
+//                  of input file.  ie tmp.rec -> tmp.bin
+//
+//   srec2bin <input SREC file> <Output Binary File> <If Present, Big Endian>
+//
+//   TAG   
+//        bit32u TAG_BIG     = 0xDEADBE42;
+//        bit32u TAG_LITTLE  = 0xFEEDFA42;
+//
+//  File Structure
+//
+//  TAG    :   32 Bits
+//  [DATA RECORDS]
+//
+//  Data Records Structure
+//
+//  LENGTH  :  32 Bits    <- Length of DATA, excludes ADDRESS and CHECKSUM
+//  ADDRESS :  32 Bits
+//  DATA    :  8 Bits * LENGTH
+//  CHECKSUM:  32 Bits    <-  0 - (Sum of Length --> End of Data)
+//
+//  Note : If Length == 0, Address will be Program Start
+//
+//
+//  
+//
+//
+
+#define MajRevNum 0
+#define MinRevNum 2
+
+
+#define EndianSwitch(x) ((x >> 24) | (x << 24) | ((x << 8) & (0x00FF0000)) | ((x >> 8) & (0x0000FF00)) )
+
+typedef unsigned char bit8u;
+typedef unsigned int bit32u;
+typedef int bit32;
+
+#define FALSE 0
+#define TRUE (!FALSE)
+
+
+bit32u CheckSum;
+int RecStart;
+int debug;
+int verbose;
+
+FILE *OpenOutputFile( char *Name );
+FILE *fOut;
+bit32u RecLength=0;
+
+bit32u AddressCurrent;
+
+bit32u gh(char *cp,int nibs);
+
+int BigEndian;
+
+int inputline;
+
+// char buf[16*1024];
+
+char buffer[2048];
+char *cur_ptr;
+int cur_line=0;
+int cur_len=0;
+
+int s1s2s3_total=0;
+
+bit32u PBVal;
+int    PBValid;
+bit32u PBAdr;
+
+
+void dumpfTell(char *s, bit32u Value)
+{
+    int Length;
+    Length = (int) RecLength;
+    if (debug)
+          printf("[%s  ] ftell()[0x%08lX] Length[0x%4X] Length[%4d] Value[0x%08x]\n",
+                s, ftell(fOut), Length, Length, Value);
+}
+
+void DispHex(bit32u Hex)
+{
+//    printf("%X", Hex);
+}
+
+void WaitDisplay(void)
+{
+   static int Count=0;
+   static int Index=0;
+   char iline[]={"-\\|/"};
+
+   Count++;
+   if ((Count % 32)==0)
+   {
+     if (verbose)
+        printf("%c%c",iline[Index++],8);
+     Index &= 3;
+   }
+}
+
+
+void binOut32 ( bit32u Data )
+{
+// On UNIX machine all 32bit writes need ENDIAN switched
+//    Data = EndianSwitch(Data);
+//    fwrite( &Data, sizeof(bit32u), 1, fOut);
+
+   char sdat[4];
+   int i;
+
+   for(i=0;i<4;i++)
+    sdat[i]=(char)(Data>>(i*8));
+   fwrite( sdat, 1, 4, fOut);
+   dumpfTell("Out32" , Data);
+}
+
+// Only update RecLength on Byte Writes
+// All 32 bit writes will be for Length etc
+
+void binOut8 ( bit8u Data )
+{
+    int n;
+    dumpfTell("B4Data" , (bit32u) (Data & 0xFF) );
+    n = fwrite( &Data, sizeof(bit8u), 1, fOut);
+    if (n != 1)
+        printf("Error in writing %X for Address 0x%8X\n", Data, AddressCurrent);
+    RecLength += 1;
+}
+
+//  Currently ONLY used for outputting Program Start
+
+void binRecStart(bit32u Address)
+{
+    RecLength      = 0;
+    CheckSum       = Address;
+    RecStart       = TRUE;
+
+    if (debug)
+          printf("[RecStart] CheckSum[0x%08X] Length[%4d] Address[0x%08X]\n",
+                CheckSum, RecLength, Address);
+
+
+    dumpfTell("RecLength", RecLength);
+    binOut32( RecLength );
+    dumpfTell("Address", Address);
+    binOut32( Address );
+}
+
+void binRecEnd(void)
+{
+    long RecEnd;
+
+    if (!RecStart)   //  if no record started, do not end it
+    {
+        return;
+    }
+
+    RecStart = FALSE;
+
+
+    RecEnd = ftell(fOut);         // Save Current position
+
+    if (debug)
+          printf("[RecEnd  ] CheckSum[0x%08X] Length[%4d] Length[0x%X] RecEnd[0x%08lX]\n",
+                CheckSum, RecLength, RecLength, RecEnd);
+
+    fseek( fOut, -((long) RecLength), SEEK_CUR);  // move back Start Of Data
+
+    dumpfTell("Data   ", -1);
+
+    fseek( fOut, -4, SEEK_CUR);  // move back Start Of Address
+
+    dumpfTell("Address   ", -1);
+
+    fseek( fOut, -4, SEEK_CUR);  // move back Start Of Length
+
+    dumpfTell("Length   ", -1);
+
+    binOut32( RecLength );
+
+    fseek( fOut, RecEnd, SEEK_SET);  // move to end of Record
+
+    CheckSum += RecLength;
+
+    CheckSum =  ~CheckSum + 1;  // Two's complement
+
+    binOut32( CheckSum );
+
+    if (verbose)
+        printf("[Created Record of %d Bytes with CheckSum [0x%8X]\n", RecLength, CheckSum);
+}
+
+void binRecOutProgramStart(bit32u Address)
+{
+    if (Address != (AddressCurrent+1))
+    {
+        binRecEnd();
+        binRecStart(Address);
+    }
+    AddressCurrent = Address;
+}
+void binRecOutByte(bit32u Address, bit8u Data)
+{
+    //  If Address is one after Current Address, output Byte
+    //  If not, close out last record, update Length, write checksum
+    //  Then Start New Record, updating Current Address
+
+    if (Address != (AddressCurrent+1))
+    {
+        binRecEnd();
+        binRecStart(Address);
+    }
+    AddressCurrent = Address;
+    CheckSum += Data;
+    binOut8( Data );
+}
+
+//=============================================================================
+//       SUPPORT FUNCTIONS
+//=============================================================================
+int readline(FILE *fil,char *buf,int len)
+{
+    int rlen;
+    
+    rlen=0;
+    if (len==0)  return(0);
+    while(1)
+    {
+      if (cur_len==0)
+      {
+        cur_len=fread(buffer, 1, sizeof(buffer), fil);
+        if (cur_len==0)
+        {
+          if (rlen)
+          {
+            *buf=0;
+            return(rlen);
+          }
+          return(-1);
+        }
+        cur_ptr=buffer;
+      }
+      if (cur_len)
+      {
+        if (*cur_ptr=='\n')
+        {
+          *buf=0;
+          cur_ptr++;
+          cur_len--;
+          return(rlen);
+        }
+         else
+         {
+           if ((len>1)&&(*cur_ptr!='\r'))
+           {
+             *buf++=*cur_ptr++;
+             len--;
+           }
+           else
+             cur_ptr++;
+
+           rlen++;
+           cur_len--;
+         }
+      }
+      else
+      {
+        *buf=0;
+        cur_ptr++;
+        cur_len--;
+        return(rlen);
+      }
+    }
+}
+
+
+int SRLerrorout(char *c1,char *c2)
+{
+  printf("\nERROR: %s - '%s'.",c1,c2);
+  return(FALSE);
+}
+
+
+int checksum(char *cp,int count)
+{
+  char *scp;
+  int cksum;
+  int dum;
+
+  scp=cp;
+  while(*scp)
+  {
+    if (!isxdigit(*scp++))
+      return(SRLerrorout("Invalid hex digits",cp));
+  }
+  scp=cp;
+
+  cksum=count;
+
+  while(count)
+  {
+    cksum += gh(scp,2);
+    if (count == 2)
+        dum = ~cksum;
+    scp += 2;
+    count--;
+  }
+  cksum&=0x0ff; 
+  //  printf("\nCk:%02x",cksum);
+  return(cksum==0x0ff);
+}
+
+bit32u gh(char *cp,int nibs)
+{
+  int i;
+  bit32u j;
+
+  j=0;
+
+  for(i=0;i<nibs;i++)
+  {
+    j<<=4;
+    if ((*cp>='a')&&(*cp<='z')) *cp &= 0x5f;
+    if ((*cp>='0')&&(*cp<='9')) 
+      j += (*cp-0x30);
+     else
+      if ((*cp>='A')&&(*cp<='F'))
+        j += (*cp-0x37);
+       else
+        SRLerrorout("Bad Hex char", cp);
+    cp++;
+  }
+  return(j);
+}
+
+
+//=============================================================================
+//       PROCESS SREC LINE
+//=============================================================================
+
+int srecLine(char *pSrecLine)
+{
+    char *scp,ch;
+    int  itmp,count,dat;
+    bit32u adr;
+    static bit32u RecordCounter=0;
+
+    cur_line++;
+    scp=pSrecLine;
+  
+    if (*pSrecLine!='S')
+      return(SRLerrorout("Not an Srecord file",scp));
+    pSrecLine++;
+    if (strlen(pSrecLine)<4)
+      return(SRLerrorout("Srecord too short",scp));
+  
+    ch=*pSrecLine++;
+  
+    count=gh(pSrecLine,2);
+  
+    pSrecLine += 2;
+  
+  //  if(debug)
+  //        printf("count %d, strlen(pSrecLine) = %d, pSrecLine =[%s]\n", count, strlen(pSrecLine), pSrecLine);
+     RecordCounter++;
+     DispHex(RecordCounter);
+  
+    if ((count*2) != strlen(pSrecLine)) return(SRLerrorout("Count field larger than record",scp));
+  
+    if (!checksum(pSrecLine, count)) return(SRLerrorout("Bad Checksum",scp));
+  
+    switch(ch)
+    {
+        case '0': if (count<3) return(SRLerrorout("Invalid Srecord count field",scp));
+                  itmp=gh(pSrecLine,4); pSrecLine+=4; count-=2;
+                  if (itmp) return(SRLerrorout("Srecord 1 address not zero",scp));
+        break;
+        case '1': if (count<3) return(SRLerrorout("Invalid Srecord count field",scp));
+                  return(SRLerrorout("Srecord Not valid for MIPS",scp));
+        break;
+        case '2': if (count<4) return(SRLerrorout("Invalid Srecord count field",scp));
+                  return(SRLerrorout("Srecord Not valid for MIPS",scp));
+        break;
+        case '3': if (count<5) return(SRLerrorout("Invalid Srecord count field",scp));
+                  adr=gh(pSrecLine,8); pSrecLine+=8; count-=4;
+                  count--;
+                  while(count)
+                  {
+                    dat=gh(pSrecLine,2); pSrecLine+=2; count--;
+                    binRecOutByte(adr, (char) (dat & 0xFF));
+                    adr++;
+                  }
+                  s1s2s3_total++;
+        break;
+        case '4': return(SRLerrorout("Invalid Srecord type",scp));
+        break;
+        case '5': if (count<3) return(SRLerrorout("Invalid Srecord count field",scp));
+                  itmp=gh(pSrecLine,4); pSrecLine+=4; count-=2;
+                  if (itmp|=s1s2s3_total) return(SRLerrorout("Incorrect number of S3 Record processed",scp));
+        break;
+        case '6': return(SRLerrorout("Invalid Srecord type",scp));
+        break;
+        case '7': // PROGRAM START
+                  if (count<5) return(SRLerrorout("Invalid Srecord count field",scp));
+                  adr=gh(pSrecLine,8); pSrecLine+=8; count-=4;
+                  if (count!=1) return(SRLerrorout("Invalid Srecord count field",scp));
+                  binRecOutProgramStart(adr);
+        break;
+        case '8': if (count<4) return(SRLerrorout("Invalid Srecord count field",scp));
+                  return(SRLerrorout("Srecord Not valid for MIPS",scp));
+        break;
+        case '9': if (count<3) return(SRLerrorout("Invalid Srecord count field",scp));
+                  return(SRLerrorout("Srecord Not valid for MIPS",scp));
+        break;
+        default:
+        break;
+    }
+    return(TRUE);
+}
+
+//=============================================================================
+//       MAIN LOGIC, READS IN LINE AND OUTPUTS BINARY
+//=============================================================================
+
+int srec2bin(int argc,char *argv[],int verbose)
+{
+    int i,rlen,sts;
+    FILE *fp;
+    char ac;
+    char buff[256];
+    bit32u TAG_BIG     = 0xDEADBE42;
+    bit32u TAG_LITTLE  = 0xFEEDFA42;
+
+    bit32u Tag;
+
+  
+    if(argc < 3)
+    {
+      printf("\nError: <srec2bin <srec input file> <bin output file>\n\n");
+      return(0);
+    }
+  
+    if (argc > 3) BigEndian=TRUE; else BigEndian=FALSE;
+
+    if (BigEndian)
+        Tag = TAG_BIG;
+    else
+        Tag = TAG_LITTLE;
+
+    if (verbose)
+       printf("\nEndian: %s, Tag is 0x%8X\n",(BigEndian)?"BIG":"LITTLE", Tag);
+
+    fp = fopen(argv[1],"rt");
+
+    if (fp==NULL)
+    {
+      printf("\nError: Opening input file, %s.", argv[1]);
+      return(0);
+    }
+  
+    fOut = fopen( argv[2], "wb");
+    
+    if (fOut==NULL)
+    {
+      printf("\nError: Opening Output file, %s.", argv[2]);
+      if(fp) fclose(fp);
+      return(0);
+    }
+    RecStart = FALSE;
+
+    AddressCurrent = 0xFFFFFFFFL;
+
+    // Setup Tag 
+  
+    dumpfTell("Tag", Tag);
+
+    binOut32(Tag);
+
+  
+    inputline=0;
+    sts=TRUE;
+
+    rlen = readline(fp,buff,sizeof buff);
+
+    while( (sts) && (rlen != -1))
+    {
+        if (strlen(buff))
+        {
+            sts &= srecLine(buff);
+            WaitDisplay();
+        }
+       rlen = readline(fp,buff,sizeof buff);
+    }
+
+  
+  //  printf("PC: 0x%08X, Length 0x%08X, Tag 0x%08X\n", ProgramStart, RecLength, TAG_LITTLE);
+  
+    binRecEnd();
+
+    if(fp) fclose(fp);
+    if(fOut) fclose(fOut);
+
+    return(1);
+}
+
+main(int argc, char *argv[])
+{
+    debug = TRUE;
+    debug = FALSE;
+    verbose = FALSE;
+    srec2bin(argc,argv,verbose);
+    return 0;
+}
+
diff --git a/trunk/tools/firmware-utils/src/tplink-safeloader.c b/trunk/tools/firmware-utils/src/tplink-safeloader.c
new file mode 100644 (file)
index 0000000..9c5bb54
--- /dev/null
@@ -0,0 +1,546 @@
+/*
+  Copyright (c) 2014, Matthias Schiffer <mschiffer@universe-factory.net>
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+
+    1. Redistributions of source code must retain the above copyright notice,
+       this list of conditions and the following disclaimer.
+    2. Redistributions in binary form must reproduce the above copyright notice,
+       this list of conditions and the following disclaimer in the documentation
+       and/or other materials provided with the distribution.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+/*
+   tplink-safeloader
+
+   Image generation tool for the TP-LINK SafeLoader as seen on
+   TP-LINK Pharos devices (CPE210/220/510/520)
+*/
+
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <arpa/inet.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "md5.h"
+
+
+#define ALIGN(x,a) ({ typeof(a) __a = (a); (((x) + __a - 1) & ~(__a - 1)); })
+
+
+/** An image partition table entry */
+struct image_partition_entry {
+       const char *name;
+       size_t size;
+       uint8_t *data;
+};
+
+/** A flash partition table entry */
+struct flash_partition_entry {
+       const char *name;
+       uint32_t base;
+       uint32_t size;
+};
+
+
+/** The content of the soft-version structure */
+struct __attribute__((__packed__)) soft_version {
+       uint32_t magic;
+       uint32_t zero;
+       uint8_t pad1;
+       uint8_t version_major;
+       uint8_t version_minor;
+       uint8_t version_patch;
+       uint8_t year_hi;
+       uint8_t year_lo;
+       uint8_t month;
+       uint8_t day;
+       uint32_t rev;
+       uint8_t pad2;
+};
+
+
+static const uint8_t jffs2_eof_mark[4] = {0xde, 0xad, 0xc0, 0xde};
+
+
+/**
+   Salt for the MD5 hash
+
+   Fortunately, TP-LINK seems to use the same salt for most devices which use
+   the new image format.
+*/
+static const uint8_t md5_salt[16] = {
+       0x7a, 0x2b, 0x15, 0xed,
+       0x9b, 0x98, 0x59, 0x6d,
+       0xe5, 0x04, 0xab, 0x44,
+       0xac, 0x2a, 0x9f, 0x4e,
+};
+
+
+/** Vendor information for CPE210/220/510/520 */
+static const unsigned char cpe510_vendor[] = "\x00\x00\x00\x1f""CPE510(TP-LINK|UN|N300-5):1.0\r\n";
+
+
+/**
+    The flash partition table for CPE210/220/510/520;
+    it is the same as the one used by the stock images.
+*/
+static const struct flash_partition_entry cpe510_partitions[] = {
+       {"fs-uboot", 0x00000, 0x20000},
+       {"partition-table", 0x20000, 0x02000},
+       {"default-mac", 0x30000, 0x00020},
+       {"product-info", 0x31100, 0x00100},
+       {"signature", 0x32000, 0x00400},
+       {"os-image", 0x40000, 0x170000},
+       {"soft-version", 0x1b0000, 0x00100},
+       {"support-list", 0x1b1000, 0x00400},
+       {"file-system", 0x1c0000, 0x600000},
+       {"user-config", 0x7c0000, 0x10000},
+       {"default-config", 0x7d0000, 0x10000},
+       {"log", 0x7e0000, 0x10000},
+       {"radio", 0x7f0000, 0x10000},
+       {NULL, 0, 0}
+};
+
+/**
+   The support list for CPE210/220/510/520
+
+   The stock images also contain strings for two more devices: BS510 and BS210.
+   At the moment, there exists no public information about these devices.
+*/
+static const unsigned char cpe510_support_list[] =
+       "\x00\x00\x00\xc8\x00\x00\x00\x00"
+       "SupportList:\r\n"
+       "CPE510(TP-LINK|UN|N300-5):1.0\r\n"
+       "CPE520(TP-LINK|UN|N300-5):1.0\r\n"
+       "CPE210(TP-LINK|UN|N300-2):1.0\r\n"
+       "CPE220(TP-LINK|UN|N300-2):1.0\r\n"
+       "\r\n\xff";
+
+#define error(_ret, _errno, _str, ...)                         \
+       do {                                                    \
+               fprintf(stderr, _str ": %s\n", ## __VA_ARGS__,  \
+                       strerror(_errno));                      \
+               if (_ret)                                       \
+                       exit(_ret);                             \
+       } while (0)
+
+
+/** Allocates a new image partition */
+struct image_partition_entry alloc_image_partition(const char *name, size_t len) {
+       struct image_partition_entry entry = {name, len, malloc(len)};
+       if (!entry.data)
+               error(1, errno, "malloc");
+
+       return entry;
+}
+
+/** Frees an image partition */
+void free_image_partition(struct image_partition_entry entry) {
+       free(entry.data);
+}
+
+/** Generates the partition-table partition */
+struct image_partition_entry make_partition_table(const struct flash_partition_entry *p) {
+       struct image_partition_entry entry = alloc_image_partition("partition-table", 0x800);
+
+       char *s = (char *)entry.data, *end = (char *)(s+entry.size);
+
+       *(s++) = 0x00;
+       *(s++) = 0x04;
+       *(s++) = 0x00;
+       *(s++) = 0x00;
+
+       size_t i;
+       for (i = 0; p[i].name; i++) {
+               size_t len = end-s;
+               size_t w = snprintf(s, len, "partition %s base 0x%05x size 0x%05x\n", p[i].name, p[i].base, p[i].size);
+
+               if (w > len-1)
+                       error(1, 0, "flash partition table overflow?");
+
+               s += w;
+       }
+
+       s++;
+
+       memset(s, 0xff, end-s);
+
+       return entry;
+}
+
+
+/** Generates a binary-coded decimal representation of an integer in the range [0, 99] */
+static inline uint8_t bcd(uint8_t v) {
+       return 0x10 * (v/10) + v%10;
+}
+
+
+/** Generates the soft-version partition */
+struct image_partition_entry make_soft_version(uint32_t rev) {
+       struct image_partition_entry entry = alloc_image_partition("soft-version", sizeof(struct soft_version));
+       struct soft_version *s = (struct soft_version *)entry.data;
+
+       time_t t;
+
+       if (time(&t) == (time_t)(-1))
+               error(1, errno, "time");
+
+       struct tm *tm = localtime(&t);
+
+       s->magic = htonl(0x0000000c);
+       s->zero = 0;
+       s->pad1 = 0xff;
+
+       s->version_major = 0;
+       s->version_minor = 0;
+       s->version_patch = 0;
+
+       s->year_hi = bcd((1900+tm->tm_year)/100);
+       s->year_lo = bcd(tm->tm_year%100);
+       s->month = bcd(tm->tm_mon+1);
+       s->day = bcd(tm->tm_mday);
+       s->rev = htonl(rev);
+
+       s->pad2 = 0xff;
+
+       return entry;
+}
+
+/** Generates the support-list partition */
+struct image_partition_entry make_support_list(const unsigned char *support_list, size_t len) {
+       struct image_partition_entry entry = alloc_image_partition("support-list", len);
+       memcpy(entry.data, support_list, len);
+       return entry;
+}
+
+/** Creates a new image partition with an arbitrary name from a file */
+struct image_partition_entry read_file(const char *part_name, const char *filename, bool add_jffs2_eof) {
+       struct stat statbuf;
+
+       if (stat(filename, &statbuf) < 0)
+               error(1, errno, "unable to stat file `%s'", filename);
+
+       size_t len = statbuf.st_size;
+
+       if (add_jffs2_eof)
+               len = ALIGN(len, 0x10000) + sizeof(jffs2_eof_mark);
+
+       struct image_partition_entry entry = alloc_image_partition(part_name, len);
+
+       FILE *file = fopen(filename, "rb");
+       if (!file)
+               error(1, errno, "unable to open file `%s'", filename);
+
+       if (fread(entry.data, statbuf.st_size, 1, file) != 1)
+               error(1, errno, "unable to read file `%s'", filename);
+
+       if (add_jffs2_eof) {
+               uint8_t *eof = entry.data + statbuf.st_size, *end = entry.data+entry.size;
+
+               memset(eof, 0xff, end - eof - sizeof(jffs2_eof_mark));
+               memcpy(end - sizeof(jffs2_eof_mark), jffs2_eof_mark, sizeof(jffs2_eof_mark));
+       }
+
+       fclose(file);
+
+       return entry;
+}
+
+
+/**
+   Copies a list of image partitions into an image buffer and generates the image partition table while doing so
+
+   Example image partition table:
+
+     fwup-ptn partition-table base 0x00800 size 0x00800
+     fwup-ptn os-image base 0x01000 size 0x113b45
+     fwup-ptn file-system base 0x114b45 size 0x1d0004
+     fwup-ptn support-list base 0x2e4b49 size 0x000d1
+
+   Each line of the partition table is terminated with the bytes 09 0d 0a ("\t\r\n"),
+   the end of the partition table is marked with a zero byte.
+
+   The firmware image must contain at least the partition-table and support-list partitions
+   to be accepted. There aren't any alignment constraints for the image partitions.
+
+   The partition-table partition contains the actual flash layout; partitions
+   from the image partition table are mapped to the corresponding flash partitions during
+   the firmware upgrade. The support-list partition contains a list of devices supported by
+   the firmware image.
+
+   The base offsets in the firmware partition table are relative to the end
+   of the vendor information block, so the partition-table partition will
+   actually start at offset 0x1814 of the image.
+
+   I think partition-table must be the first partition in the firmware image.
+*/
+void put_partitions(uint8_t *buffer, const struct image_partition_entry *parts) {
+       size_t i;
+       char *image_pt = (char *)buffer, *end = image_pt + 0x800;
+
+       size_t base = 0x800;
+       for (i = 0; parts[i].name; i++) {
+               memcpy(buffer + base, parts[i].data, parts[i].size);
+
+               size_t len = end-image_pt;
+               size_t w = snprintf(image_pt, len, "fwup-ptn %s base 0x%05x size 0x%05x\t\r\n", parts[i].name, (unsigned)base, (unsigned)parts[i].size);
+
+               if (w > len-1)
+                       error(1, 0, "image partition table overflow?");
+
+               image_pt += w;
+
+               base += parts[i].size;
+       }
+
+       image_pt++;
+
+       memset(image_pt, 0xff, end-image_pt);
+}
+
+/** Generates and writes the image MD5 checksum */
+void put_md5(uint8_t *md5, uint8_t *buffer, unsigned int len) {
+       MD5_CTX ctx;
+
+       MD5_Init(&ctx);
+       MD5_Update(&ctx, md5_salt, (unsigned int)sizeof(md5_salt));
+       MD5_Update(&ctx, buffer, len);
+       MD5_Final(md5, &ctx);
+}
+
+
+/**
+   Generates the firmware image in factory format
+
+   Image format:
+
+     Bytes (hex)  Usage
+     -----------  -----
+     0000-0003    Image size (4 bytes, big endian)
+     0004-0013    MD5 hash (hash of a 16 byte salt and the image data starting with byte 0x14)
+     0014-1013    Vendor information (4096 bytes, padded with 0xff; there seem to be older
+                  (VxWorks-based) TP-LINK devices which use a smaller vendor information block)
+     1014-1813    Image partition table (2048 bytes, padded with 0xff)
+     1814-xxxx    Firmware partitions
+*/
+void * generate_factory_image(const unsigned char *vendor, size_t vendor_len, const struct image_partition_entry *parts, size_t *len) {
+       *len = 0x1814;
+
+       size_t i;
+       for (i = 0; parts[i].name; i++)
+               *len += parts[i].size;
+
+       uint8_t *image = malloc(*len);
+       if (!image)
+               error(1, errno, "malloc");
+
+       image[0] = *len >> 24;
+       image[1] = *len >> 16;
+       image[2] = *len >> 8;
+       image[3] = *len;
+
+       memcpy(image+0x14, vendor, vendor_len);
+       memset(image+0x14+vendor_len, 0xff, 4096-vendor_len);
+
+       put_partitions(image + 0x1014, parts);
+       put_md5(image+0x04, image+0x14, *len-0x14);
+
+       return image;
+}
+
+/**
+   Generates the firmware image in sysupgrade format
+
+   This makes some assumptions about the provided flash and image partition tables and
+   should be generalized when TP-LINK starts building its safeloader into hardware with
+   different flash layouts.
+*/
+void * generate_sysupgrade_image(const struct flash_partition_entry *flash_parts, const struct image_partition_entry *image_parts, size_t *len) {
+       const struct flash_partition_entry *flash_os_image = &flash_parts[5];
+       const struct flash_partition_entry *flash_soft_version = &flash_parts[6];
+       const struct flash_partition_entry *flash_support_list = &flash_parts[7];
+       const struct flash_partition_entry *flash_file_system = &flash_parts[8];
+
+       const struct image_partition_entry *image_os_image = &image_parts[3];
+       const struct image_partition_entry *image_soft_version = &image_parts[1];
+       const struct image_partition_entry *image_support_list = &image_parts[2];
+       const struct image_partition_entry *image_file_system = &image_parts[4];
+
+       assert(strcmp(flash_os_image->name, "os-image") == 0);
+       assert(strcmp(flash_soft_version->name, "soft-version") == 0);
+       assert(strcmp(flash_support_list->name, "support-list") == 0);
+       assert(strcmp(flash_file_system->name, "file-system") == 0);
+
+       assert(strcmp(image_os_image->name, "os-image") == 0);
+       assert(strcmp(image_soft_version->name, "soft-version") == 0);
+       assert(strcmp(image_support_list->name, "support-list") == 0);
+       assert(strcmp(image_file_system->name, "file-system") == 0);
+
+       if (image_os_image->size > flash_os_image->size)
+               error(1, 0, "kernel image too big (more than %u bytes)", (unsigned)flash_os_image->size);
+       if (image_file_system->size > flash_file_system->size)
+               error(1, 0, "rootfs image too big (more than %u bytes)", (unsigned)flash_file_system->size);
+
+       *len = flash_file_system->base - flash_os_image->base + image_file_system->size;
+
+       uint8_t *image = malloc(*len);
+       if (!image)
+               error(1, errno, "malloc");
+
+       memset(image, 0xff, *len);
+
+       memcpy(image, image_os_image->data, image_os_image->size);
+       memcpy(image + flash_soft_version->base - flash_os_image->base, image_soft_version->data, image_soft_version->size);
+       memcpy(image + flash_support_list->base - flash_os_image->base, image_support_list->data, image_support_list->size);
+       memcpy(image + flash_file_system->base - flash_os_image->base, image_file_system->data, image_file_system->size);
+
+       return image;
+}
+
+
+/** Generates an image for CPE210/220/510/520 and writes it to a file */
+static void do_cpe510(const char *output, const char *kernel_image, const char *rootfs_image, uint32_t rev, bool add_jffs2_eof, bool sysupgrade) {
+       struct image_partition_entry parts[6] = {};
+
+       parts[0] = make_partition_table(cpe510_partitions);
+       parts[1] = make_soft_version(rev);
+       parts[2] = make_support_list(cpe510_support_list, sizeof(cpe510_support_list)-1);
+       parts[3] = read_file("os-image", kernel_image, false);
+       parts[4] = read_file("file-system", rootfs_image, add_jffs2_eof);
+
+       size_t len;
+       void *image;
+       if (sysupgrade)
+               image = generate_sysupgrade_image(cpe510_partitions, parts, &len);
+       else
+               image = generate_factory_image(cpe510_vendor, sizeof(cpe510_vendor)-1, parts, &len);
+
+       FILE *file = fopen(output, "wb");
+       if (!file)
+               error(1, errno, "unable to open output file");
+
+       if (fwrite(image, len, 1, file) != 1)
+               error(1, 0, "unable to write output file");
+
+       fclose(file);
+
+       free(image);
+
+       size_t i;
+       for (i = 0; parts[i].name; i++)
+               free_image_partition(parts[i]);
+}
+
+
+/** Usage output */
+void usage(const char *argv0) {
+       fprintf(stderr,
+               "Usage: %s [OPTIONS...]\n"
+               "\n"
+               "Options:\n"
+               "  -B <board>      create image for the board specified with <board>\n"
+               "  -k <file>       read kernel image from the file <file>\n"
+               "  -r <file>       read rootfs image from the file <file>\n"
+               "  -o <file>       write output to the file <file>\n"
+               "  -V <rev>        sets the revision number to <rev>\n"
+               "  -j              add jffs2 end-of-filesystem markers\n"
+               "  -S              create sysupgrade instead of factory image\n"
+               "  -h              show this help\n",
+               argv0
+       );
+};
+
+
+int main(int argc, char *argv[]) {
+       const char *board = NULL, *kernel_image = NULL, *rootfs_image = NULL, *output = NULL;
+       bool add_jffs2_eof = false, sysupgrade = false;
+       unsigned rev = 0;
+
+       while (true) {
+               int c;
+
+               c = getopt(argc, argv, "B:k:r:o:V:jSh");
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'B':
+                       board = optarg;
+                       break;
+
+               case 'k':
+                       kernel_image = optarg;
+                       break;
+
+               case 'r':
+                       rootfs_image = optarg;
+                       break;
+
+               case 'o':
+                       output = optarg;
+                       break;
+
+               case 'V':
+                       sscanf(optarg, "r%u", &rev);
+                       break;
+
+               case 'j':
+                       add_jffs2_eof = true;
+                       break;
+
+               case 'S':
+                       sysupgrade = true;
+                       break;
+
+               case 'h':
+                       usage(argv[0]);
+                       return 0;
+
+               default:
+                       usage(argv[0]);
+                       return 1;
+               }
+       }
+
+       if (!board)
+               error(1, 0, "no board has been specified");
+       if (!kernel_image)
+               error(1, 0, "no kernel image has been specified");
+       if (!rootfs_image)
+               error(1, 0, "no rootfs image has been specified");
+       if (!output)
+               error(1, 0, "no output filename has been specified");
+
+       if (strcmp(board, "CPE510") == 0)
+               do_cpe510(output, kernel_image, rootfs_image, rev, add_jffs2_eof, sysupgrade);
+       else
+               error(1, 0, "unsupported board %s", board);
+
+       return 0;
+}
diff --git a/trunk/tools/firmware-utils/src/trx.c b/trunk/tools/firmware-utils/src/trx.c
new file mode 100644 (file)
index 0000000..aa1f5be
--- /dev/null
@@ -0,0 +1,418 @@
+/*
+ * Copyright (C) 2004  Manuel Novoa III  <mjn3@codepoet.org>
+ *
+ * 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
+ */
+
+/* July 29, 2004
+ *
+ * This is a hacked replacement for the 'trx' utility used to create
+ * wrt54g .trx firmware files.  It isn't pretty, but it does the job
+ * for me.
+ *
+ * As an extension, you can specify a larger maximum length for the
+ * .trx file using '-m'.  It will be rounded up to be a multiple of 4K.
+ * NOTE: This space will be malloc()'d.
+ *
+ * August 16, 2004
+ *
+ * Sigh... Make it endian-neutral.
+ *
+ * TODO: Support '-b' option to specify offsets for each file.
+ *
+ * February 19, 2005 - mbm
+ *
+ * Add -a (align offset) and -b (absolute offset)
+ *
+ * March 24, 2010 - markus
+ *
+ * extend trx header struct for new version
+ * assume v1 for as default
+ * Add option -2 to allow v2 header
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define STORE32_LE(X)          bswap_32(X)
+#define LOAD32_LE(X)           bswap_32(X)
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+#define STORE32_LE(X)          (X)
+#define LOAD32_LE(X)           (X)
+#else
+#error unkown endianness!
+#endif
+
+uint32_t crc32buf(char *buf, size_t len);
+
+/**********************************************************************/
+/* from trxhdr.h */
+
+#define TRX_MAGIC      0x30524448      /* "HDR0" */
+#define TRX_MAX_LEN    0x720000
+#define TRX_NO_HEADER  1               /* Do not write TRX header */
+
+struct trx_header {
+       uint32_t magic;                 /* "HDR0" */
+       uint32_t len;                   /* Length of file including header */
+       uint32_t crc32;                 /* 32-bit CRC from flag_version to end of file */
+       uint32_t flag_version;  /* 0:15 flags, 16:31 version */
+       uint32_t offsets[4];    /* Offsets of partitions from start of header */
+};
+
+/**********************************************************************/
+
+void usage(void) __attribute__ (( __noreturn__ ));
+
+void usage(void)
+{
+       fprintf(stderr, "Usage:\n");
+       fprintf(stderr, " trx [-2] [-o outfile] [-m maxlen] [-a align] [-b absolute offset] [-x relative offset]\n");
+       fprintf(stderr, "     [-f file] [-f file [-f file [-f file (v2 only)]]]\n");
+       exit(EXIT_FAILURE);
+}
+
+int main(int argc, char **argv)
+{
+       FILE *out = stdout;
+       FILE *in;
+       char *ofn = NULL;
+       char *buf;
+       char *e;
+       int c, i, append = 0;
+       size_t n;
+       ssize_t n2;
+       uint32_t cur_len, fsmark=0;
+       unsigned long maxlen = TRX_MAX_LEN;
+       struct trx_header *p;
+       char trx_version = 1;
+       unsigned char binheader[32];
+
+       fprintf(stderr, "mjn3's trx replacement - v0.81.1\n");
+
+       if (!(buf = malloc(maxlen))) {
+               fprintf(stderr, "malloc failed\n");
+               return EXIT_FAILURE;
+       }
+
+       p = (struct trx_header *) buf;
+
+       p->magic = STORE32_LE(TRX_MAGIC);
+       cur_len = sizeof(struct trx_header) - 4; /* assume v1 header */
+
+       in = NULL;
+       i = 0;
+
+       while ((c = getopt(argc, argv, "-:2o:m:a:x:b:f:A:F:")) != -1) {
+               switch (c) {
+                       case '2':
+                               /* take care that nothing was written to buf so far */
+                               if (cur_len != sizeof(struct trx_header) - 4) {
+                                       fprintf(stderr, "-2 has to be used before any other argument!\n");
+                               }
+                               else {
+                                       trx_version = 2;
+                                       cur_len += 4;
+                               }
+                               break;
+                       case 'F':
+                               fsmark = cur_len;
+                       case 'A':
+                               append = 1;
+                               /* fall through */
+                       case 'f':
+                       case 1:
+                               if (!append)
+                                       p->offsets[i++] = STORE32_LE(cur_len);
+
+                               if (!(in = fopen(optarg, "r"))) {
+                                       fprintf(stderr, "can not open \"%s\" for reading\n", optarg);
+                                       usage();
+                               }
+                               n = fread(buf + cur_len, 1, maxlen - cur_len, in);
+                               if (!feof(in)) {
+                                       fprintf(stderr, "fread failure or file \"%s\" too large\n",optarg);
+                                       fclose(in);
+                                       return EXIT_FAILURE;
+                               }
+                               fclose(in);
+#undef  ROUND
+#define ROUND 4
+                               if (n & (ROUND-1)) {
+                                       memset(buf + cur_len + n, 0, ROUND - (n & (ROUND-1)));
+                                       n += ROUND - (n & (ROUND-1));
+                               }
+                               cur_len += n;
+                               append = 0;
+
+                               break;
+                       case 'o':
+                               ofn = optarg;
+                               if (ofn && !(out = fopen(ofn, "w"))) {
+                                       fprintf(stderr, "can not open \"%s\" for writing\n", ofn);
+                                       usage();
+                               }
+
+                               break;
+                       case 'm':
+                               errno = 0;
+                               maxlen = strtoul(optarg, &e, 0);
+                               if (errno || (e == optarg) || *e) {
+                                       fprintf(stderr, "illegal numeric string\n");
+                                       usage();
+                               }
+#undef  ROUND
+#define ROUND 0x1000
+                               if (maxlen & (ROUND-1)) {
+                                       maxlen += (ROUND - (maxlen & (ROUND-1)));
+                               }
+                               if (maxlen < ROUND) {
+                                       fprintf(stderr, "maxlen too small (or wrapped)\n");
+                                       usage();
+                               }
+                               if (maxlen > TRX_MAX_LEN) {
+                                       fprintf(stderr, "WARNING: maxlen exceeds default maximum!  Beware of overwriting nvram!\n");
+                               }
+                               if (!(buf = realloc(buf,maxlen))) {
+                                       fprintf(stderr, "realloc failed");
+                                       return EXIT_FAILURE;
+                               }
+                               p = (struct trx_header *) buf;
+                               break;
+                       case 'a':
+                               errno = 0;
+                               n = strtoul(optarg, &e, 0);
+                               if (errno || (e == optarg) || *e) {
+                                       fprintf(stderr, "illegal numeric string\n");
+                                       usage();
+                               }
+                               if (cur_len & (n-1)) {
+                                       n = n - (cur_len & (n-1));
+                                       memset(buf + cur_len, 0, n);
+                                       cur_len += n;
+                               }
+                               break;
+                       case 'b':
+                               errno = 0;
+                               n = strtoul(optarg, &e, 0);
+                               if (errno || (e == optarg) || *e) {
+                                       fprintf(stderr, "illegal numeric string\n");
+                                       usage();
+                               }
+                               if (n < cur_len) {
+                                       fprintf(stderr, "WARNING: current length exceeds -b %d offset\n",(int) n);
+                               } else {
+                                       memset(buf + cur_len, 0, n - cur_len);
+                                       cur_len = n;
+                               }
+                               break;
+                       case 'x':
+                               errno = 0;
+                               n2 = strtol(optarg, &e, 0);
+                               if (errno || (e == optarg) || *e) {
+                                       fprintf(stderr, "illegal numeric string\n");
+                                       usage();
+                               }
+                               if (n2 < 0) {
+                                       if (-n2 > cur_len) {
+                                               fprintf(stderr, "WARNING: current length smaller then -x %d offset\n",(int) n2);
+                                               cur_len = 0;
+                                       } else
+                                               cur_len += n2;
+                               } else {
+                                       memset(buf + cur_len, 0, n2);
+                                       cur_len += n2;
+                               }
+
+                               break;
+                       default:
+                               usage();
+               }
+       }
+       p->flag_version = STORE32_LE((trx_version << 16));
+
+       if (!in) {
+               fprintf(stderr, "we require atleast one filename\n");
+               usage();
+       }
+
+#undef  ROUND
+#define ROUND 0x1000
+       n = cur_len & (ROUND-1);
+       if (n) {
+               memset(buf + cur_len, 0, ROUND - n);
+               cur_len += ROUND - n;
+       }
+
+       /* for TRXv2 set bin-header Flags to 0xFF for CRC calculation like CFE does */
+       if (trx_version == 2) {
+               if(cur_len - LOAD32_LE(p->offsets[3]) < sizeof(binheader)) {
+                       fprintf(stderr, "TRXv2 binheader too small!\n");
+                       return EXIT_FAILURE;
+               }
+               memcpy(binheader, buf + LOAD32_LE(p->offsets[3]), sizeof(binheader)); /* save header */
+               memset(buf + LOAD32_LE(p->offsets[3]) + 22, 0xFF, 8); /* set stable and try1-3 to 0xFF */
+       }
+
+       p->crc32 = crc32buf((char *) &p->flag_version,
+                                               ((fsmark)?fsmark:cur_len) - offsetof(struct trx_header, flag_version));
+       p->crc32 = STORE32_LE(p->crc32);
+
+       p->len = STORE32_LE((fsmark) ? fsmark : cur_len);
+
+       /* restore TRXv2 bin-header */
+       if (trx_version == 2) {
+               memcpy(buf + LOAD32_LE(p->offsets[3]), binheader, sizeof(binheader));
+       }
+
+       if (!fwrite(buf, cur_len, 1, out) || fflush(out)) {
+               fprintf(stderr, "fwrite failed\n");
+               return EXIT_FAILURE;
+       }
+
+       fclose(out);
+
+       return EXIT_SUCCESS;
+}
+
+/**********************************************************************/
+/* The following was grabbed and tweaked from the old snippets collection
+ * of public domain C code. */
+
+/**********************************************************************\
+|* Demonstration program to compute the 32-bit CRC used as the frame  *|
+|* check sequence in ADCCP (ANSI X3.66, also known as FIPS PUB 71     *|
+|* and FED-STD-1003, the U.S. versions of CCITT's X.25 link-level     *|
+|* protocol).  The 32-bit FCS was added via the Federal Register,     *|
+|* 1 June 1982, p.23798.  I presume but don't know for certain that   *|
+|* this polynomial is or will be included in CCITT V.41, which        *|
+|* defines the 16-bit CRC (often called CRC-CCITT) polynomial.  FIPS  *|
+|* PUB 78 says that the 32-bit FCS reduces otherwise undetected       *|
+|* errors by a factor of 10^-5 over 16-bit FCS.                       *|
+\**********************************************************************/
+
+/* Copyright (C) 1986 Gary S. Brown.  You may use this program, or
+   code or tables extracted from it, as desired without restriction.*/
+
+/* First, the polynomial itself and its table of feedback terms.  The  */
+/* polynomial is                                                       */
+/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */
+/* Note that we take it "backwards" and put the highest-order term in  */
+/* the lowest-order bit.  The X^32 term is "implied"; the LSB is the   */
+/* X^31 term, etc.  The X^0 term (usually shown as "+1") results in    */
+/* the MSB being 1.                                                    */
+
+/* Note that the usual hardware shift register implementation, which   */
+/* is what we're using (we're merely optimizing it by doing eight-bit  */
+/* chunks at a time) shifts bits into the lowest-order term.  In our   */
+/* implementation, that means shifting towards the right.  Why do we   */
+/* do it this way?  Because the calculated CRC must be transmitted in  */
+/* order from highest-order term to lowest-order term.  UARTs transmit */
+/* characters in order from LSB to MSB.  By storing the CRC this way,  */
+/* we hand it to the UART in the order low-byte to high-byte; the UART */
+/* sends each low-bit to hight-bit; and the result is transmission bit */
+/* by bit from highest- to lowest-order term without requiring any bit */
+/* shuffling on our part.  Reception works similarly.                  */
+
+/* The feedback terms table consists of 256, 32-bit entries.  Notes:   */
+/*                                                                     */
+/*  1. The table can be generated at runtime if desired; code to do so */
+/*     is shown later.  It might not be obvious, but the feedback      */
+/*     terms simply represent the results of eight shift/xor opera-    */
+/*     tions for all combinations of data and CRC register values.     */
+/*                                                                     */
+/*  2. The CRC accumulation logic is the same for all CRC polynomials, */
+/*     be they sixteen or thirty-two bits wide.  You simply choose the */
+/*     appropriate table.  Alternatively, because the table can be     */
+/*     generated at runtime, you can start by generating the table for */
+/*     the polynomial in question and use exactly the same "updcrc",   */
+/*     if your application needn't simultaneously handle two CRC       */
+/*     polynomials.  (Note, however, that XMODEM is strange.)          */
+/*                                                                     */
+/*  3. For 16-bit CRCs, the table entries need be only 16 bits wide;   */
+/*     of course, 32-bit entries work OK if the high 16 bits are zero. */
+/*                                                                     */
+/*  4. The values must be right-shifted by eight bits by the "updcrc"  */
+/*     logic; the shift must be unsigned (bring in zeroes).  On some   */
+/*     hardware you could probably optimize the shift in assembler by  */
+/*     using byte-swap instructions.                                   */
+
+static const uint32_t crc_32_tab[] = { /* CRC polynomial 0xedb88320 */
+0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+#define UPDC32(octet,crc) (crc_32_tab[((crc) ^ (octet)) & 0xff] ^ ((crc) >> 8))
+
+uint32_t crc32buf(char *buf, size_t len)
+{
+      uint32_t crc;
+
+      crc = 0xFFFFFFFF;
+
+      for ( ; len; --len, ++buf)
+      {
+            crc = UPDC32(*buf, crc);
+      }
+
+      return crc;
+}
diff --git a/trunk/tools/firmware-utils/src/trx2edips.c b/trunk/tools/firmware-utils/src/trx2edips.c
new file mode 100644 (file)
index 0000000..f8d068d
--- /dev/null
@@ -0,0 +1,171 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define STORE32_LE(X)          bswap_32(X)
+#define LOAD32_LE(X)           bswap_32(X)
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+#define STORE32_LE(X)          (X)
+#define LOAD32_LE(X)           (X)
+#else
+#error unkown endianness!
+#endif
+
+/**********************************************************************/
+/* from trxhdr.h */
+
+#define TRX_MAGIC      0x30524448      /* "HDR0" */
+#define TRX_VERSION    1
+#define TRX_MAX_LEN    0x5A0000
+#define TRX_NO_HEADER  1               /* Do not write TRX header */
+
+struct trx_header {
+       uint32_t magic;                 /* "HDR0" */
+       uint32_t len;                   /* Length of file including header */
+       uint32_t crc32;                 /* 32-bit CRC from flag_version to end of file */
+       uint32_t flag_version;  /* 0:15 flags, 16:31 version */
+       uint32_t offsets[3];    /* Offsets of partitions from start of header */
+};
+
+
+struct edimax_header {
+       uint32_t sign;                  /* signature for header */
+       uint32_t length;                /* start address but doesn't seems to be used... */
+       uint32_t start_addr;            /* length of data, not used too ...*/
+};
+
+
+#define EDIMAX_PS16    0x36315350      /* "PS16" */
+#define EDIMAX_HDR_LEN         0xc
+
+
+/**********************************************************************/
+static const uint32_t crc_32_tab[] = { /* CRC polynomial 0xedb88320 */
+0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+#define UPDC32(octet, crc) (crc_32_tab[((crc) ^ (octet)) & 0xff] ^ ((crc) >> 8))
+
+uint32_t crc32buf(char *buf, size_t len)
+{
+       uint32_t crc;
+
+       crc = 0xFFFFFFFF;
+
+       for (; len; --len, ++buf)
+               crc = UPDC32(*buf, crc);
+
+       return crc;
+}
+
+
+int main(int argc, char *argv[])
+{
+       FILE *fpIn = NULL;
+       FILE *fpOut = NULL;
+       struct edimax_header eh;
+       size_t res;
+       int length;
+
+       char *buf;
+       struct trx_header *p;
+
+       if (argc != 3) {
+               printf("Usage: %s <input file> <output file>\n", argv[0]);
+               return -1;
+       }
+
+       fpIn = fopen(argv[1], "rb");
+       if (fpIn == NULL) {
+               fprintf(stderr, "Unable to open %s\n", argv[1]);
+               return EXIT_FAILURE;
+       }
+       /* compute the length of the file */
+       fseek(fpIn, 0, SEEK_END);
+       length = ftell(fpIn);
+       /* alloc enough memory to store the file */
+       buf = (char *)malloc(length);
+       if (!buf) {
+               fprintf(stderr, "malloc of buffers failed\n");
+               return EXIT_FAILURE;
+       }
+       
+       rewind(fpIn);
+       /* read the whole file*/
+       res = fread(buf, 1, length, fpIn);
+
+       p = (struct trx_header *)buf;
+       if (LOAD32_LE(p->magic) != TRX_MAGIC) {
+               fprintf(stderr, "Not a trx file...%x\n", LOAD32_LE(p->magic));
+               return EXIT_FAILURE;
+       }
+
+       fclose(fpIn);
+
+       fpOut = fopen(argv[2], "wb+");
+       if (fpOut == NULL) {
+               fprintf(stderr, "Unable to open %s\n", argv[2]);
+               return EXIT_FAILURE;
+       }
+       /* make the 3 partition beeing 12 bytes closer from the header */
+       memcpy(buf + LOAD32_LE(p->offsets[2]) - EDIMAX_HDR_LEN, buf + LOAD32_LE(p->offsets[2]), length - LOAD32_LE(p->offsets[2]));
+       /* recompute the crc32 check */
+       p->crc32 = STORE32_LE(crc32buf((char *) &p->flag_version, length - offsetof(struct trx_header, flag_version)));
+
+       eh.sign = STORE32_LE(EDIMAX_PS16);
+       eh.length = STORE32_LE(length);
+       eh.start_addr = STORE32_LE(0x80500000);
+
+       /* write the modified file */
+       fwrite(&eh, sizeof(struct edimax_header), 1, fpOut);
+       fwrite(buf, sizeof(char), length, fpOut);
+       fclose(fpOut);
+}
+
diff --git a/trunk/tools/firmware-utils/src/trx2usr.c b/trunk/tools/firmware-utils/src/trx2usr.c
new file mode 100644 (file)
index 0000000..96c0ab2
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * trx2usr - Convert a TRX firmware image to a U.S. Robotics firmware
+ *           image by prepending a 28-byte header.
+ *
+ * This program was modeled after the usr-hdr.c program from the GPL'ed
+ * firmware for the U.S. Robotics Wireless MAXg Router (USR5461). The
+ * output file of this program can be uploaded via the web interface
+ * of the original U.S. Robotics firmware. Note that this program only
+ * works on a little-endian host platform.
+ *
+ * Copyright (C) 2006 Dick Streefland
+ *
+ * This is free software, licensed under the terms of the GNU General
+ * Public License as published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#define        TRX_MAGIC               "HDR0"
+
+#define        USR_MAGIC               0x30525355      // "USR0"
+#define        EPI_VERSION             0x06235d03
+#define        COMPAT_ID               1               // USR5461
+#define        HARDWARE_REV            1
+
+#define        CRC32_INIT              0xffffffff
+#define        CHUNK                   (64*1024)
+
+typedef        unsigned char           uint8;
+typedef        unsigned short          uint16;
+typedef        unsigned int            uint32;
+
+struct usr_header
+{
+       uint32  magic;                  // "USR0" 
+       uint32  len;                    // file length without this header 
+       uint32  crc32;                  // CRC32 of the file without header 
+       uint32  version;                // EPI_VERSION
+       uint16  compatibility_id;       // COMPAT_ID
+       uint16  hardware_revision;      // HARDWARE_REV
+       uint32  reserved[2];
+};
+       
+static const   uint32          crc_32_tab [] = // CRC polynomial 0xedb88320
+{
+       0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+       0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+       0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+       0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+       0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+       0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+       0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+       0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+       0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+       0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+       0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+       0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+       0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+       0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+       0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+       0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+       0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+       0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+       0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+       0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+       0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+       0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+       0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+       0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+       0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+       0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+       0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+       0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+       0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+       0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+       0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+       0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+       0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+       0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+       0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+       0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+       0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+       0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+       0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+       0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+       0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+       0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+       0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
+};
+
+static char    buf[CHUNK];
+
+static uint32  crc32(uint32 crc, uint8* p, size_t n)
+{
+       while (n--)
+       {
+               crc = crc_32_tab[(crc ^ *p++) & 0xff] ^ (crc >> 8);
+       }
+       return crc;
+}
+
+static int     trx2usr(FILE* trx, FILE* usr)
+{
+       struct usr_header       hdr;
+       size_t                  n;
+
+       hdr.magic               = USR_MAGIC;
+       hdr.len                 = 0;
+       hdr.crc32               = CRC32_INIT;
+       hdr.version             = EPI_VERSION;
+       hdr.compatibility_id    = COMPAT_ID;
+       hdr.hardware_revision   = HARDWARE_REV;
+       hdr.reserved[0]         = 0;
+       hdr.reserved[1]         = 0;
+       fwrite(& hdr, sizeof(hdr), 1, usr);
+       while ((n = fread(buf, 1, CHUNK, trx)))
+       {
+               if (hdr.len == 0 && strncmp(buf, TRX_MAGIC, strlen(TRX_MAGIC)) != 0)
+               {
+                       break;
+               }
+               fwrite(& buf, 1, n, usr);
+               hdr.len += n;
+               hdr.crc32 = crc32( hdr.crc32, (uint8 *) & buf, n);
+       }
+       fseek(usr, 0L, SEEK_SET);
+       fwrite(& hdr, sizeof(hdr), 1, usr);
+       if (n != 0)
+       {
+               fprintf(stderr, "Input is not a TRX file\n");
+               return 1;
+       }
+       if (hdr.len == 0)
+       {
+               fprintf(stderr, "Empty input\n");
+               return 1;
+       }
+       if (ferror(trx))
+       {
+               fprintf(stderr, "Read error\n");
+               return 1;
+       }
+       if (ferror(usr))
+       {
+               fprintf(stderr, "Write error\n");
+               return 1;
+       }
+       return 0;
+}
+
+extern int     main(int argc, char *argv[])
+{
+       FILE*   in;
+       FILE*   out;
+       int     ret;
+
+       if (argc != 3)
+       {
+               fprintf(stderr, "Usage: trx2usr <trx input> <usr output>\n");
+               exit(2);
+       }
+       in  = fopen(argv[1], "rb");
+       if (!in)
+       {
+               fprintf(stderr, "Cannot open \"%s\": %s\n", argv[1], strerror(errno));
+               exit(1);
+       }
+       out = fopen(argv[2], "wb");
+       if (!out)
+       {
+               fprintf(stderr, "Cannot create \"%s\": %s\n", argv[2], strerror(errno));
+               exit(1);
+       }
+       ret = trx2usr(in, out);
+       fclose(in);
+       fclose(out);
+       if (ret)
+       {
+               unlink(argv[2]);
+       }
+       return ret;
+}
diff --git a/trunk/tools/firmware-utils/src/wrt400n.c b/trunk/tools/firmware-utils/src/wrt400n.c
new file mode 100644 (file)
index 0000000..69ecadd
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ * WRT400n - Firmware Generation Creator
+ *
+ * Creates a firmware image for the Linksys WRT400n router,
+ * that can be uploaded via the firmware upload page,
+ * from a kernel image file and root fs file
+ *
+ *     Author: Sandeep Mistry
+ */
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "cyg_crc.h"
+
+// https://dev.librecmc.org/browser/trunk/target/linux/rdc-2.6/files/drivers/mtd/maps/rdc3210.c
+static uint32_t crctab[257] =
+{
+       0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
+       0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+       0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+       0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+       0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+       0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+       0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+       0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+       0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+       0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+       0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
+       0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+       0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
+       0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+       0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+       0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+       0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
+       0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+       0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
+       0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+       0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+       0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+       0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
+       0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+       0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+       0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+       0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+       0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+       0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
+       0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+       0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
+       0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+       0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+       0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+       0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+       0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+       0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
+       0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+       0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+       0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+       0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
+       0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+       0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
+       0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+       0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+       0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+       0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
+       0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+       0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+       0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+       0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+       0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+       0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
+       0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+       0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+       0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+       0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+       0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+       0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
+       0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+       0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
+       0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+       0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+       0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
+       0
+};
+
+static uint32_t crc32(uint8_t* buf, uint32_t len)
+{
+       register int i;
+       uint32_t sum;
+       register uint32_t s0;
+       s0 = ~0;
+       for (i = 0; i < len; i++)
+       {
+               s0 = (s0 >> 8) ^ crctab[(uint8_t) (s0 & 0xFF) ^ buf[i]];
+       }
+       sum = ~s0;
+       return sum;
+}
+
+#define HEADERSIZE     60
+#define MAGIC          "GMTKRT400N"
+
+// global variables
+uint8_t kernelbuf[0x100000];   // kernel - lzma - uImage
+uint8_t rootfsbuf[0x2FFFC4];   // root - squashfs
+
+uint8_t buf[0x400000];         // buffer for image
+
+
+// Header format:
+//
+//             GPL Tarball: http://downloads.linksysbycisco.com/downloads/WRT400N_1.0.01.19_US.tar,0.gz
+//             File: WRT400N_1.0.01.19_US/FW_WRT400N_1.0.01.19_US_20081229/GTK/user/include/fw_upgrade.h
+//
+//
+//             Struct:
+//                     typedef struct
+//                     {
+//                             UINT32          checksum;               /* CRC32 */
+//                             UINT8                   magic[11];              /* The value of GTIMG_MAGIC */
+//                             UINT32          kernel_length;          /* The length of the kernel image */
+//                             //UINT32                kernel_entry_point;     /* Kernel's entry point for RedBoot's information */
+//                             UINT32          kernel_upgrade_flag;    /* Set to 1 if we need to upgrade the kernel parition of the Flash */
+//                             UINT32          rootfs_length;          /* The length of the rootfs image */
+//                             //UINT32                rootfs_entry_point;     /* Not in use */
+//                             UINT32          rootfs_upgrade_flag;    /* Set to 1 if we need to upgrade the rootfs parition of the Flash */
+//
+//                             // Add 3 items by Vic Yu, 2006-05/10
+//                             UINT32          kernel_checksum;
+//                             UINT32          rootfs_checksum;
+//                             UINT32          fw_totalsize;
+//                             UINT32          reserved[4];
+//                     }imghdr_t , *pLinuxFWHeader_T;
+//
+//
+//             Description
+//                     - checksum:                     CRC32 of kernel and root fs, back to back
+//                     - magic:                                GMTKRT400N
+//                     - kernel_length:                kernel length in bytes
+//                     - kernel_upgrade_flag:  should we upgrade the kernel - set to 1
+//                     - rootfs_length:                root fs length in byte
+//                     - rootfs_upgrade_flag:  should we upgrade the root fs - set to 1
+//                     - kernel_checksum:              Gary S. Brown's 32 bit CRC algorithm for kernel, with remaining bits
+//                                                                     set to 0xFF upto 0x100000 bytes (total length)
+//                     - rootfs_checksum:              Gary S. Brown's 32 bit CRC algorithm for root fs, with remaining bits
+//                                                                     set to 0xFF upto 0x2FFFC4 bytes (total length)
+//                     - fw_totalsize:                 total firmware image file length (header length + kernel length + root fs length)
+//                     - reserved[4]:                  reserved ??? - set to all 0xFF
+
+
+
+int main(int argc, char *argv[])
+{
+       // file descriptors ...
+       int             kernelfd                = -1;
+       int             rootfsfd                        = -1;
+       int                     outfd                   = -1;
+
+       char*           kernelfilename  = NULL;
+       char*           rootfsfilename  = NULL;
+       char*           outputfilename  = NULL;
+
+       // file sizes
+       uint32_t        kernelsize              = 0;
+       uint32_t        rootfssize              = 0;
+       uint32_t        totalsize               = 0;
+
+       // header flags
+       uint32_t        kernelflag              = 0;
+       uint32_t        rootfsflag              = 0;
+
+       // checksums
+       uint32_t        kernelchecksum  = 0;
+       uint32_t        rootfschecksum  = 0;
+       uint32_t        crc                             = 0;
+
+       if(argc != 4)
+       {
+               printf("Usage:\n\t%s <kernel file> <rootfs file> <output file>\n", argv[0]);
+               return 1;
+       }
+
+       kernelfilename = argv[1];
+       rootfsfilename = argv[2];
+       outputfilename = argv[3];
+
+       // Fill the kernel, rootfs, main buffer
+       memset(kernelbuf, 0xFF, sizeof(kernelbuf));
+       memset(rootfsbuf, 0xFF, sizeof(rootfsbuf));
+       memset(buf, 0xFF, sizeof(buf));
+
+       // open the kernel ..
+       kernelfd = open(kernelfilename, O_RDONLY);
+
+       if(kernelfd == -1)
+       {
+               printf("Error: opening '%s'\n", kernelfilename);
+               goto done;
+       }
+
+       // read in the kernel ...
+       kernelsize = read(kernelfd, kernelbuf, sizeof(kernelbuf));
+
+       if(kernelsize == -1)
+       {
+               printf("Error: reading '%s'\n", kernelfilename);
+               goto done;
+       }
+
+       // calculate the kernel checksum ...
+       kernelchecksum = cyg_crc32_accumulate(0, kernelbuf, sizeof(kernelbuf));
+
+       // print out stats
+       printf("%s: size %d (0x%x), crc32 = 0x%x\n", kernelfilename, kernelsize, kernelsize, kernelchecksum);
+
+
+       // open the root fs ..
+       rootfsfd = open(rootfsfilename, O_RDONLY);
+
+       if(rootfsfd == -1)
+       {
+               printf("Error: opening '%s'\n", rootfsfilename);
+               goto done;
+       }
+
+       // read in the root fs ..
+       rootfssize = read(rootfsfd, rootfsbuf, sizeof(rootfsbuf));
+
+       if(rootfssize == -1)
+       {
+               printf("Error: reading '%s'\n", rootfsfilename);
+               goto done;
+       }
+
+       // calculate the root fs checksum ...
+       rootfschecksum = cyg_crc32_accumulate(0, rootfsbuf, sizeof(rootfsbuf));
+
+       // print out stats
+       printf("%s: size %d (0x%x), crc32 = 0x%x\n", rootfsfilename, rootfssize, rootfssize, rootfschecksum);
+
+
+       // now for the header ...
+
+       totalsize = HEADERSIZE;
+
+       // copy over kernel
+       memcpy(buf + totalsize, kernelbuf, kernelsize);
+       totalsize += kernelsize;
+
+       // copy over root fs
+       memcpy(buf + totalsize, rootfsbuf, rootfssize);
+       totalsize += rootfssize;
+
+       // calculate crc
+       crc = crc32(buf + HEADERSIZE, totalsize - HEADERSIZE);
+
+       // print some stats out
+       printf("crc = 0x%x, total size = %d (0x%x)\n", crc, totalsize, totalsize);
+
+       // copy crc into header
+       crc = htonl(crc);
+       memcpy(buf, &crc, sizeof(crc));
+
+       // copy over magic
+       strcpy((char *)buf + 4, MAGIC);
+
+       // copy over kernel size
+       kernelsize = htonl(kernelsize);
+       memcpy(buf + 16, &kernelsize, sizeof(kernelsize));
+
+       // copy over kernal flag
+       kernelflag = htonl(0x1);
+       memcpy(buf + 20, &kernelflag, sizeof(kernelflag));
+
+       // copy over root fs size
+       rootfssize = htonl(rootfssize);
+       memcpy(buf + 24, &rootfssize, sizeof(rootfssize));
+
+       // copy over root fs flag
+       rootfsflag = htonl(0x1);
+       memcpy(buf + 28, &rootfsflag, sizeof(rootfsflag));
+
+       // copy over kernel check sum
+       kernelchecksum = htonl(kernelchecksum);
+       memcpy(buf + 32, &kernelchecksum, sizeof(kernelchecksum));
+
+       // copy over root fs checksum
+       rootfschecksum = htonl(rootfschecksum);
+       memcpy(buf + 36, &rootfschecksum, sizeof(rootfschecksum));
+
+       // copy over total size
+       totalsize = htonl(totalsize);
+       memcpy(buf + 40, &totalsize, sizeof(totalsize));
+
+       // undo the htonl (for write)
+       totalsize = htonl(totalsize);
+
+
+       // write out the file from the buffer
+       outfd = open(outputfilename, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+       if(outfd == -1)
+       {
+               printf("ERROR: opening '%s' for write\n", outputfilename);
+       }
+
+       write(outfd, buf, totalsize);
+
+done:
+       // close open fd's
+
+       if(kernelfd != -1)
+       {
+               close(kernelfd);
+               kernelfd = -1;
+       }
+
+       if(rootfsfd != -1)
+       {
+               close(rootfsfd);
+               rootfsfd = -1;
+       }
+
+       if(outfd != -1)
+       {
+               close(outfd);
+               outfd = -1;
+       }
+
+       return 0;
+}
diff --git a/trunk/tools/firmware-utils/src/xorimage.c b/trunk/tools/firmware-utils/src/xorimage.c
new file mode 100644 (file)
index 0000000..e33f5d5
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * xorimage.c - partially based on libreCMC's addpattern.c
+ *
+ * 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
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+static char default_pattern[] = "12345678";
+
+
+int xor_data(uint8_t *data, size_t len, const uint8_t *pattern, int p_len, int p_off)
+{
+       int offset = p_off;
+       while (len--) {
+               *data ^= pattern[offset];
+               data++;
+               offset = (offset + 1) % p_len;
+       }
+       return offset;
+}
+
+
+void usage(void) __attribute__ (( __noreturn__ ));
+
+void usage(void)
+{
+       fprintf(stderr, "Usage: xorimage [-i infile] [-o outfile] [-p <pattern>]\n");
+       exit(EXIT_FAILURE);
+}
+
+
+int main(int argc, char **argv)
+{
+       char buf[1024]; /* keep this at 1k or adjust garbage calc below */
+       FILE *in = stdin;
+       FILE *out = stdout;
+       char *ifn = NULL;
+       char *ofn = NULL;
+       const char *pattern = default_pattern;
+       int c;
+       int v0, v1, v2;
+       size_t n;
+       int p_len, p_off = 0;
+
+       while ((c = getopt(argc, argv, "i:o:p:h")) != -1) {
+               switch (c) {
+                       case 'i':
+                               ifn = optarg;
+                               break;
+                       case 'o':
+                               ofn = optarg;
+                               break;
+                       case 'p':
+                               pattern = optarg;
+                               break;
+                       case 'h':
+                       default:
+                               usage();
+               }
+       }
+
+       if (optind != argc || optind == 1) {
+               fprintf(stderr, "illegal arg \"%s\"\n", argv[optind]);
+               usage();
+       }
+
+       if (ifn && !(in = fopen(ifn, "r"))) {
+               fprintf(stderr, "can not open \"%s\" for reading\n", ifn);
+               usage();
+       }
+
+       if (ofn && !(out = fopen(ofn, "w"))) {
+               fprintf(stderr, "can not open \"%s\" for writing\n", ofn);
+               usage();
+       }
+
+       p_len = strlen(pattern);
+
+       if (p_len == 0) {
+               fprintf(stderr, "pattern cannot be empty\n");
+               usage();
+       }
+
+
+       while ((n = fread(buf, 1, sizeof(buf), in)) > 0) {
+               if (n < sizeof(buf)) {
+                       if (ferror(in)) {
+                       FREAD_ERROR:
+                               fprintf(stderr, "fread error\n");
+                               return EXIT_FAILURE;
+                       }
+               }
+
+               p_off = xor_data(buf, n, pattern, p_len, p_off);
+
+               if (!fwrite(buf, n, 1, out)) {
+               FWRITE_ERROR:
+                       fprintf(stderr, "fwrite error\n");
+                       return EXIT_FAILURE;
+               }
+       }
+
+       if (ferror(in)) {
+               goto FREAD_ERROR;
+       }
+
+       if (fflush(out)) {
+               goto FWRITE_ERROR;
+       }
+
+       fclose(in);
+       fclose(out);
+
+       return EXIT_SUCCESS;
+}
diff --git a/trunk/tools/firmware-utils/src/zynos.h b/trunk/tools/firmware-utils/src/zynos.h
new file mode 100644 (file)
index 0000000..e16913d
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ *
+ *  Copyright (C) 2007-2008 OpenWrt.org
+ *  Copyright (C) 2007-2008 Gabor Juhos <juhosg at librecmc.org>
+ *
+ *  This code was based on the information of the ZyXEL's firmware
+ *  image format written by Kolja Waschk, can be found at:
+ *  http://www.ixo.de/info/zyxel_uclinux
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ *
+ */
+
+#ifndef _ZYNOS_H
+#define _ZYNOS_H
+
+#define BOOTBASE_NAME_LEN      32
+#define BOOTBASE_MAC_LEN       6
+#define BOOTBASE_FEAT_LEN      22
+
+#define BOOTEXT_DEF_SIZE       0x18000
+
+struct zyn_bootbase_info {
+       char            vendor[BOOTBASE_NAME_LEN]; /* Vendor name */
+       char            model[BOOTBASE_NAME_LEN]; /* Model name */
+       uint32_t        bootext_addr;   /* absolute address of the Boot Extension */
+       uint16_t        res0;           /* reserved/unknown */
+       uint8_t         sys_type;       /* system type */
+       uint8_t         res1;           /* reserved/unknown */
+       uint16_t        model_id;       /* model id */
+       uint8_t         feat_other[BOOTBASE_FEAT_LEN]; /* other feature bits */
+       uint8_t         feat_main;      /* main feature bits */
+       uint8_t         res2;           /* reserved/unknown */
+       uint8_t         mac[BOOTBASE_MAC_LEN]; /* mac address */
+       uint8_t         country;        /* default country code */
+       uint8_t         dbgflag;        /* debug flag */
+} __attribute__((packed));
+
+#define ROMBIN_SIG_LEN 3
+#define ROMBIN_VER_LEN 15
+
+struct zyn_rombin_hdr {
+       uint32_t        addr;           /* load address of the object */
+       uint16_t        res0;           /* unknown/unused */
+       char            sig[ROMBIN_SIG_LEN];    /* magic, must be "SIG" */
+       uint8_t         type;           /* type of the object */
+       uint32_t        osize;          /* size of the uncompressed data */
+       uint32_t        csize;          /* size of the compressed data */
+       uint8_t         flags;          /* various flags */
+       uint8_t         res1;           /* unknown/unused */
+       uint16_t        ocsum;          /* csum of the uncompressed data */
+       uint16_t        ccsum;          /* csum of the compressed data */
+       char            ver[ROMBIN_VER_LEN];
+       uint32_t        mmap_addr;      /* address of the Memory Map Table*/
+       uint32_t        res2;           /* unknown/unused*/
+       uint8_t         res3;           /* unknown/unused*/
+} __attribute__((packed));
+
+#define ROMBIN_SIGNATURE       "SIG"
+
+/* Rombin flag bits */
+#define ROMBIN_FLAG_01         0x01
+#define ROMBIN_FLAG_02         0x02
+#define ROMBIN_FLAG_04         0x04
+#define ROMBIN_FLAG_08         0x08
+#define ROMBIN_FLAG_10         0x10
+#define ROMBIN_FLAG_CCSUM      0x20    /* compressed checksum is valid */
+#define ROMBIN_FLAG_OCSUM      0x40    /* original checksum is valid */
+#define ROMBIN_FLAG_COMPRESSED 0x80    /* the binary is compressed */
+
+/* Object types */
+#define OBJECT_TYPE_ROMIMG     0x01
+#define OBJECT_TYPE_ROMBOOT    0x02
+#define OBJECT_TYPE_BOOTEXT    0x03
+#define OBJECT_TYPE_ROMBIN     0x04
+#define OBJECT_TYPE_ROMDIR     0x05
+#define OBJECT_TYPE_6          0x06
+#define OBJECT_TYPE_ROMMAP     0x07
+#define OBJECT_TYPE_RAM                0x80
+#define OBJECT_TYPE_RAMCODE    0x81
+#define OBJECT_TYPE_RAMBOOT    0x82
+
+/*
+ * Memory Map Table header
+ */
+struct zyn_mmt_hdr {
+       uint16_t        count;
+       uint32_t        user_start;
+       uint32_t        user_end;
+       uint16_t        csum;
+       uint8_t         res[12];
+} __attribute__((packed));
+
+#define OBJECT_NAME_LEN                8
+
+struct zyn_mmt_item {
+       uint8_t         type;   /* type of the object */
+       uint8_t         name[OBJECT_NAME_LEN]; /* name of the object */
+       uint8_t         res0;   /* unused/unknown */
+       uint32_t        addr;
+       uint32_t        size;   /* size of the object */
+       uint8_t         res1[3]; /* unused/unknown */
+       uint8_t         type2;
+} __attribute__((packed));
+
+/*
+ * Vendor IDs
+ */
+#define ZYNOS_VENDOR_ID_ZYXEL  0
+#define ZYNOS_VENDOR_ID_NETGEAR        1
+#define ZYNOS_VENDOR_ID_DLINK  2
+#define ZYNOS_VENDOR_ID_03     3
+#define ZYNOS_VENDOR_ID_LUCENT 4
+#define ZYNOS_VENDOR_ID_O2     10
+
+/*
+ * Model IDs (in big-endian format)
+ */
+#define MID(x) (((x) & 0xFF) << 8) | (((x) & 0xFF00) >> 8)
+
+/*
+ * Infineon/ADMtek ADM5120 based models
+ */
+#define ZYNOS_MODEL_ES_2024A           MID(  221)
+#define ZYNOS_MODEL_ES_2024PWR         MID( 4097)
+#define ZYNOS_MODEL_ES_2108            MID(61952)
+#define ZYNOS_MODEL_ES_2108_F          MID(44801)
+#define ZYNOS_MODEL_ES_2108_G          MID(62208)
+#define ZYNOS_MODEL_ES_2108_LC         MID(64512)
+#define ZYNOS_MODEL_ES_2108PWR         MID(62464)
+#define ZYNOS_MODEL_HS_100             MID(61855)
+#define ZYNOS_MODEL_HS_100W            ZYNOS_MODEL_HS_100
+#define ZYNOS_MODEL_P_334              MID(62879)
+#define ZYNOS_MODEL_P_334U             MID(56735)
+#define ZYNOS_MODEL_P_334W             MID(62367)
+#define ZYNOS_MODEL_P_334WH            MID(57344)
+#define ZYNOS_MODEL_P_334WHD           MID(57600)
+#define ZYNOS_MODEL_P_334WT            MID(61343)
+#define ZYNOS_MODEL_P_335              MID(60831)
+#define ZYNOS_MODEL_P_335PLUS          MID( 9472)
+#define ZYNOS_MODEL_P_335U             MID(56479)
+#define ZYNOS_MODEL_P_335WT            ZYNOS_MODEL_P_335
+
+/*
+ * Texas Instruments AR7 based models
+ */
+#define ZYNOS_MODEL_P_2602H_61C                MID( 3229)
+#define ZYNOS_MODEL_P_2602H_63C                MID( 3485)
+#define ZYNOS_MODEL_P_2602H_D1A                /* n.a. */
+#define ZYNOS_MODEL_P_2602H_D3A                /* n.a. */
+#define ZYNOS_MODEL_P_2602HW_61C       /* n.a. */
+#define ZYNOS_MODEL_P_2602HW_63                /* n.a. */
+#define ZYNOS_MODEL_P_2602HW_63C       ZYNOS_MODEL_P_2602H_63C
+#define ZYNOS_MODEL_P_2602HW_D1A       MID( 6301)
+#define ZYNOS_MODEL_P_2602HW_D3A       /* n.a. */
+#define ZYNOS_MODEL_P_2602HWL_61       MID( 1181)
+#define ZYNOS_MODEL_P_2602HWL_61C      ZYNOS_MODEL_P_2602H_61C
+#define ZYNOS_MODEL_P_2602HWL_63C      ZYNOS_MODEL_P_2602H_63C
+#define ZYNOS_MODEL_P_2602HWL_D1A      ZYNOS_MODEL_P_2602HW_D1A
+#define ZYNOS_MODEL_P_2602HWL_D3A      MID( 7581)
+#define ZYNOS_MODEL_P_2602HWN_D7A      MID(30464)
+#define ZYNOS_MODEL_P_2602HWNLI_D7A    MID( 6813)
+
+#define ZYNOS_MODEL_P_2602R_61         MID( 2205)
+#define ZYNOS_MODEL_P_2602R_63         MID( 3997)
+#define ZYNOS_MODEL_P_2602R_D1A                /* n.a. */
+#define ZYNOS_MODEL_P_2602R_D3A                /* n.a. */
+#define ZYNOS_MODEL_P_2602RL_D1A       MID( 6045)
+#define ZYNOS_MODEL_P_2602RL_D3A       MID( 7069)
+
+#define ZYNOS_MODEL_P_660H_61          MID(19346)
+#define ZYNOS_MODEL_P_660H_63          MID(22162)
+#define ZYNOS_MODEL_P_660H_67          /* n.a. */
+#define ZYNOS_MODEL_P_660H_D1          MID( 7066)
+#define ZYNOS_MODEL_P_660H_D3          MID(13210)
+
+#define ZYNOS_MODEL_P_660HW_61         ZYNOS_MODEL_P_660H_61
+#define ZYNOS_MODEL_P_660HW_63         ZYNOS_MODEL_P_660H_63
+#define ZYNOS_MODEL_P_660HW_67         ZYNOS_MODEL_P_660HW_63
+#define ZYNOS_MODEL_P_660HW_D1         MID( 9114)
+#define ZYNOS_MODEL_P_660HW_D3         MID(12698)
+
+#define ZYNOS_MODEL_P_660R_61          MID(20882)
+#define ZYNOS_MODEL_P_660R_61C         MID( 1178)
+#define ZYNOS_MODEL_P_660R_63          MID(21138)
+#define ZYNOS_MODEL_P_660R_63C         MID(  922)
+#define ZYNOS_MODEL_P_660R_67          ZYNOS_MODEL_P_660R_63
+#define ZYNOS_MODEL_P_660R_67C         /* n.a. */
+#define ZYNOS_MODEL_P_660R_D1          MID( 7322)
+#define ZYNOS_MODEL_P_660R_D3          MID(10138)
+
+#define ZYNOS_MODEL_P_661H_61          MID(19346)
+#define ZYNOS_MODEL_P_661H_63          MID( 1946)
+#define ZYNOS_MODEL_P_661H_D1          MID(10650)
+#define ZYNOS_MODEL_P_661H_D3          MID(12442)
+
+#define ZYNOS_MODEL_P_661HW_61         ZYNOS_MODEL_P_661H_61
+#define ZYNOS_MODEL_P_661HW_63         ZYNOS_MODEL_P_661H_63
+#define ZYNOS_MODEL_P_661HW_D1         MID(10906)
+#define ZYNOS_MODEL_P_661HW_D3         MID(14746)
+
+#define ZYNOS_MODEL_P_662H_61          MID(22418)
+#define ZYNOS_MODEL_P_662H_63          /* n.a. */
+#define ZYNOS_MODEL_P_662H_67          /* n.a. */
+#define ZYNOS_MODEL_P_662H_D1          /* n.a. */
+#define ZYNOS_MODEL_P_662H_D3          /* n.a. */
+
+#define ZYNOS_MODEL_P_662HW_61         /* n.a. */
+#define ZYNOS_MODEL_P_662HW_63         MID(22674)
+#define ZYNOS_MODEL_P_662HW_67         /* n.a. */
+#define ZYNOS_MODEL_P_662HW_D1         MID(10394)
+#define ZYNOS_MODEL_P_662HW_D3         MID(12954)
+
+/* OEM boards */
+#define ZYNOS_MODEL_O2SURF             ZYNOS_MODEL_P_2602HWN_D7A
+
+/* Atheros AR2318 based boards */
+#define ZYNOS_MODEL_NBG_318S           MID(59392)
+
+/* Atheros AR71xx based boards */
+#define ZYNOS_MODEL_NBG_460N           MID(61441)
+
+#endif /* _ZYNOS_H */
diff --git a/trunk/tools/firmware-utils/src/zyxbcm.c b/trunk/tools/firmware-utils/src/zyxbcm.c
new file mode 100644 (file)
index 0000000..58205b2
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * zyxbcm.c - based on Jonas Gorski's spw303v.c
+ *
+ * Copyright (C) 2014 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * 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
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#define TAGVER_LEN 4                   /* Length of Tag Version */
+#define SIG1_LEN 20                    /* Company Signature 1 Length */
+#define SIG2_LEN 14                    /* Company Signature 2 Lenght */
+#define BOARDID_LEN 16                 /* Length of BoardId */
+#define ENDIANFLAG_LEN 2               /* Endian Flag Length */
+#define CHIPID_LEN 6                   /* Chip Id Length */
+#define IMAGE_LEN 10                   /* Length of Length Field */
+#define ADDRESS_LEN 12                 /* Length of Address field */
+#define DUALFLAG_LEN 2                 /* Dual Image flag Length */
+#define INACTIVEFLAG_LEN 2             /* Inactie Flag Length */
+#define RSASIG_LEN 20                  /* Length of RSA Signature in tag */
+#define TAGINFO1_LEN 30                        /* Length of vendor information field1 in tag */
+#define ZYX_TAGINFO1_LEN 20            /* Length of vendor information field1 in tag */
+#define FLASHLAYOUTVER_LEN 4           /* Length of Flash Layout Version String tag */
+#define TAGINFO2_LEN 16                        /* Length of vendor information field2 in tag */
+#define CRC_LEN 4                      /* Length of CRC in bytes */
+
+#define IMAGETAG_CRC_START 0xFFFFFFFF
+
+struct bcm_tag {
+       char tagVersion[TAGVER_LEN];                    // 0-3: Version of the image tag
+       char sig_1[SIG1_LEN];                           // 4-23: Company Line 1
+       char sig_2[SIG2_LEN];                           // 24-37: Company Line 2
+       char chipid[CHIPID_LEN];                        // 38-43: Chip this image is for
+       char boardid[BOARDID_LEN];                      // 44-59: Board name
+       char big_endian[ENDIANFLAG_LEN];                // 60-61: Map endianness -- 1 BE 0 LE
+       char totalLength[IMAGE_LEN];                    // 62-71: Total length of image
+       char cfeAddress[ADDRESS_LEN];                   // 72-83: Address in memory of CFE
+       char cfeLength[IMAGE_LEN];                      // 84-93: Size of CFE
+       char flashImageStart[ADDRESS_LEN];              // 94-105: Address in memory of image start (kernel for libreCMC, rootfs for stock firmware)
+       char flashRootLength[IMAGE_LEN];                // 106-115: Size of rootfs for flashing
+       char kernelAddress[ADDRESS_LEN];                // 116-127: Address in memory of kernel
+       char kernelLength[IMAGE_LEN];                   // 128-137: Size of kernel
+       char dualImage[DUALFLAG_LEN];                   // 138-139: Unused at present
+       char inactiveFlag[INACTIVEFLAG_LEN];            // 140-141: Unused at present
+       char rsa_signature[RSASIG_LEN];                 // 142-161: RSA Signature (unused at present; some vendors may use this)
+       char information1[TAGINFO1_LEN];                // 162-191: Compilation and related information (not generated/used by libreCMC)
+       char flashLayoutVer[FLASHLAYOUTVER_LEN];        // 192-195: Version flash layout
+       char fskernelCRC[CRC_LEN];                      // 196-199: kernel+rootfs CRC32
+       char information2[TAGINFO2_LEN];                // 200-215: Unused at present except Alice Gate where is is information
+       char imageCRC[CRC_LEN];                         // 216-219: CRC32 of image less imagetag (kernel for Alice Gate)
+       char rootfsCRC[CRC_LEN];                        // 220-223: CRC32 of rootfs partition
+       char kernelCRC[CRC_LEN];                        // 224-227: CRC32 of kernel partition
+       char imageSequence[4];                          // 228-231: Image sequence number
+       char rootLength[4];                             // 232-235: steal from reserved1 to keep the real root length so we can use in the flash map even after we have change the rootLength to 0 to satisfy devices that check CRC on every boot
+       char headerCRC[CRC_LEN];                        // 236-239: CRC32 of header excluding tagVersion
+       char reserved2[16];                             // 240-255: Unused at present
+};
+
+struct zyxbcm_tag {
+       char tagVersion[TAGVER_LEN];                    // 0-3: Version of the image tag
+       char sig_1[SIG1_LEN];                           // 4-23: Company Line 1
+       char sig_2[SIG2_LEN];                           // 24-37: Company Line 2
+       char chipid[CHIPID_LEN];                        // 38-43: Chip this image is for
+       char boardid[BOARDID_LEN];                      // 44-59: Board name
+       char big_endian[ENDIANFLAG_LEN];                // 60-61: Map endianness -- 1 BE 0 LE
+       char totalLength[IMAGE_LEN];                    // 62-71: Total length of image
+       char cfeAddress[ADDRESS_LEN];                   // 72-83: Address in memory of CFE
+       char cfeLength[IMAGE_LEN];                      // 84-93: Size of CFE
+       char flashImageStart[ADDRESS_LEN];              // 94-105: Address in memory of image start (kernel for libreCMC, rootfs for stock firmware)
+       char flashRootLength[IMAGE_LEN];                // 106-115: Size of rootfs for flashing
+       char kernelAddress[ADDRESS_LEN];                // 116-127: Address in memory of kernel
+       char kernelLength[IMAGE_LEN];                   // 128-137: Size of kernel
+       char dualImage[DUALFLAG_LEN];                   // 138-139: Unused at present
+       char inactiveFlag[INACTIVEFLAG_LEN];            // 140-141: Unused at present
+       char rsa_signature[RSASIG_LEN];                 // 142-161: RSA Signature (unused at present; some vendors may use this)
+       char information1[ZYX_TAGINFO1_LEN];            // 162-181: Compilation and related information (not generated/used by libreCMC)
+       char flashImageEnd[ADDRESS_LEN];                // 182-193: Address in memory of image end
+       char fskernelCRC[CRC_LEN];                      // 194-197: kernel+rootfs CRC32
+       char reserved1[2];                              // 198-199: Unused at present
+       char information2[TAGINFO2_LEN];                // 200-215: Unused at present except Alice Gate where is is information
+       char imageCRC[CRC_LEN];                         // 216-219: CRC32 of image less imagetag (kernel for Alice Gate)
+       char rootfsCRC[CRC_LEN];                        // 220-223: CRC32 of rootfs partition
+       char kernelCRC[CRC_LEN];                        // 224-227: CRC32 of kernel partition
+       char imageSequence[4];                          // 228-231: Image sequence number
+       char rootLength[4];                             // 232-235: steal from reserved1 to keep the real root length so we can use in the flash map even after we have change the rootLength to 0 to satisfy devices that check CRC on every boot
+       char headerCRC[CRC_LEN];                        // 236-239: CRC32 of header excluding tagVersion
+       char reserved2[16];                             // 240-255: Unused at present
+};
+
+static uint32_t crc32tab[256] = {
+       0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
+       0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
+       0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
+       0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
+       0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
+       0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
+       0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
+       0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
+       0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
+       0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
+       0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
+       0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
+       0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
+       0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
+       0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+       0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
+       0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
+       0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
+       0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
+       0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
+       0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+       0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
+       0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
+       0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
+       0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
+       0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
+       0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
+       0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
+       0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
+       0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+       0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
+       0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
+};
+
+uint32_t crc32(uint32_t crc, uint8_t *data, size_t len)
+{
+       while (len--)
+               crc = (crc >> 8) ^ crc32tab[(crc ^ *data++) & 0xFF];
+
+       return crc;
+}
+
+void fix_header(void *buf)
+{
+       struct bcm_tag *bcmtag = buf;
+       struct zyxbcm_tag *zyxtag = buf;
+       uint8_t fskernel_crc[CRC_LEN];
+       uint32_t crc;
+       uint64_t flash_start, rootfs_len, kernel_len;
+
+       /* Backup values */
+       flash_start = strtoul(bcmtag->flashImageStart, NULL, 10);
+       rootfs_len = strtoul(bcmtag->flashRootLength, NULL, 10);
+       kernel_len = strtoul(bcmtag->kernelLength, NULL, 10);
+       memcpy(fskernel_crc, bcmtag->fskernelCRC, CRC_LEN);
+
+       /* Clear values */
+       zyxtag->information1[ZYX_TAGINFO1_LEN - 1] = 0;
+       memset(zyxtag->flashImageEnd, 0, ADDRESS_LEN);
+       memset(zyxtag->fskernelCRC, 0, CRC_LEN);
+       memset(zyxtag->reserved1, 0, 2);
+
+       /* Replace values */
+       sprintf(zyxtag->flashImageEnd, "%lu", flash_start + rootfs_len + kernel_len);
+       memcpy(zyxtag->fskernelCRC, fskernel_crc, CRC_LEN);
+
+       /* Update tag crc */
+       crc = htonl(crc32(IMAGETAG_CRC_START, buf, 236));
+       memcpy(zyxtag->headerCRC, &crc, 4);
+}
+
+void usage(void) __attribute__ (( __noreturn__ ));
+
+void usage(void)
+{
+       fprintf(stderr, "Usage: zyxbcm [-i <inputfile>] [-o <outputfile>]\n");
+       exit(EXIT_FAILURE);
+}
+
+int main(int argc, char **argv)
+{
+       char buf[1024]; /* keep this at 1k or adjust garbage calc below */
+       FILE *in = stdin, *out = stdout;
+       char *ifn = NULL, *ofn = NULL;
+       size_t n;
+       int c, first_block = 1;
+
+       while ((c = getopt(argc, argv, "i:o:h")) != -1) {
+               switch (c) {
+                       case 'i':
+                               ifn = optarg;
+                               break;
+                       case 'o':
+                               ofn = optarg;
+                               break;
+                       case 'h':
+                       default:
+                               usage();
+               }
+       }
+
+       if (optind != argc || optind == 1) {
+               fprintf(stderr, "illegal arg \"%s\"\n", argv[optind]);
+               usage();
+       }
+
+       if (ifn && !(in = fopen(ifn, "r"))) {
+               fprintf(stderr, "can not open \"%s\" for reading\n", ifn);
+               usage();
+       }
+
+       if (ofn && !(out = fopen(ofn, "w"))) {
+               fprintf(stderr, "can not open \"%s\" for writing\n", ofn);
+               usage();
+       }
+
+       while ((n = fread(buf, 1, sizeof(buf), in)) > 0) {
+               if (n < sizeof(buf)) {
+                       if (ferror(in)) {
+                       FREAD_ERROR:
+                               fprintf(stderr, "fread error\n");
+                               return EXIT_FAILURE;
+                       }
+               }
+
+               if (first_block && n >= 256) {
+                       fix_header(buf);
+                       first_block = 0;
+               }
+
+               if (!fwrite(buf, n, 1, out)) {
+               FWRITE_ERROR:
+                       fprintf(stderr, "fwrite error\n");
+                       return EXIT_FAILURE;
+               }
+       }
+
+       if (ferror(in)) {
+               goto FREAD_ERROR;
+       }
+
+       if (fflush(out)) {
+               goto FWRITE_ERROR;
+       }
+
+       fclose(in);
+       fclose(out);
+
+       return EXIT_SUCCESS;
+}