OpenWrt

Subversion Repositories:
Compare Path: Rev
With Path: Rev
?path1? @ 3  →  ?path2? @ 4
/branches/gl-inet/tools/firmware-utils/Makefile
@@ -0,0 +1,93 @@
#
# 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,asustrx)
$(call cc,trx)
$(call cc,otrx)
$(call cc,motorola-bin)
$(call cc,dgfirmware)
$(call cc,mksenaofw md5)
$(call cc,trx2usr)
$(call cc,ptgen)
$(call cc,srec2bin)
$(call cc,mkmylofw)
$(call cc,mkcsysimg)
$(call cc,mkzynfw)
$(call cc,lzma2eva,-lz)
$(call cc,mkcasfw)
$(call cc,mkfwimage,-lz -Wall)
$(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 mktplinkfw-lib md5, -Wall -fgnu89-inline)
$(call cc,mktplinkfw2 mktplinkfw-lib md5, -fgnu89-inline)
$(call cc,tplink-safeloader md5, -Wall --std=gnu99)
$(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,mkwrggimg md5, -Wall)
$(call cc,mkedimaximg)
$(call cc,mkbrncmdline)
$(call cc,mkbrnimg)
$(call cc,mkdapimg)
$(call cc,mkdapimg2)
$(call cc, mkcameofw, -Wall)
$(call cc,seama md5)
$(call cc,oseama md5, -Wall)
$(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, -Wall)
$(call cc,edimax_fw_header, -Wall)
$(call cc,mkmerakifw sha1, -Wall)
$(call cc,mkmerakifw-old, -Wall)
$(call cc,jcgimage, -lz -Wall)
$(call cc,mkbuffaloimg, -Wall)
$(call cc,zyimage, -Wall)
$(call cc,mkdhpimg buffalo-lib, -Wall)
$(call cc,mkdlinkfw mkdlinkfw-lib, -lz -Wall --std=gnu99)
$(call cc,dns313-header, -Wall)
endef
 
define Host/Install
$(INSTALL_BIN) $(HOST_BUILD_DIR)/bin/* $(STAGING_DIR_HOST)/bin/
endef
 
$(eval $(call HostBuild))
/branches/gl-inet/tools/firmware-utils/src/add_header.c
@@ -0,0 +1,138 @@
/*
* add_header.c - partially based on OpenWrt'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;
}
/branches/gl-inet/tools/firmware-utils/src/addpattern.c
@@ -0,0 +1,358 @@
/*
* 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 <errno.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 = "E2100L",
.pattern = "NL1X",
.hw_ver = 0x00,
.sn = 0x0f,
.flags = {0x3f, 0x00},
},
{
.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);
}
 
static time_t source_date_epoch = -1;
static void set_source_date_epoch() {
char *env = getenv("SOURCE_DATE_EPOCH");
char *endptr = env;
errno = 0;
if (env && *env) {
source_date_epoch = strtoull(env, &endptr, 10);
if (errno || (endptr && *endptr != '\0')) {
fprintf(stderr, "Invalid SOURCE_DATE_EPOCH");
exit(1);
}
}
}
 
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();
}
 
set_source_date_epoch();
if (source_date_epoch != -1) {
t = source_date_epoch;
} else 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;
}
/branches/gl-inet/tools/firmware-utils/src/asustrx.c
@@ -0,0 +1,256 @@
/*
* asustrx
*
* Copyright (C) 2015 Rafał Miłecki <zajec5@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.
*/
 
#include <byteswap.h>
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
 
#if __BYTE_ORDER == __BIG_ENDIAN
#define cpu_to_le32(x) bswap_32(x)
#define le32_to_cpu(x) bswap_32(x)
#elif __BYTE_ORDER == __LITTLE_ENDIAN
#define cpu_to_le32(x) (x)
#define le32_to_cpu(x) (x)
#else
#error "Unsupported endianness"
#endif
 
#define TRX_MAGIC 0x30524448
#define TRX_FLAGS_OFFSET 12
 
struct trx_header {
uint32_t magic;
uint32_t length;
uint32_t crc32;
uint16_t flags;
uint16_t version;
uint32_t offset[3];
};
 
struct asustrx_tail {
uint8_t version[4];
char productid[12];
uint8_t unused[48];
};
 
char *in_path = NULL;
char *out_path = NULL;
char *productid = NULL;
uint8_t version[4] = { };
 
static const uint32_t crc32_tbl[] = {
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 void parse_options(int argc, char **argv) {
int c;
 
while ((c = getopt(argc, argv, "i:o:p:v:")) != -1) {
switch (c) {
case 'i':
in_path = optarg;
break;
case 'o':
out_path = optarg;
break;
case 'p':
productid = optarg;
break;
case 'v':
if (sscanf(optarg, "%hu.%hu.%hu.%hu", &version[0], &version[1], &version[2], &version[3]) != 4)
fprintf(stderr, "Version %s doesn't match suppored 4-digits format\n", optarg);
break;
}
}
}
 
static void usage() {
printf("Usage:\n");
printf("\t-i file\t\t\t\tinput TRX file\n");
printf("\t-o file\t\t\t\toutput Asus TRX file\n");
printf("\t-p productid\t\t\tproduct (device) ID\n");
printf("\t-v version\t\t\tfirmware version formatted with 4 digits like: 1.2.3.4\n");
}
 
int main(int argc, char **argv) {
struct trx_header hdr;
struct asustrx_tail tail = { };
FILE *in, *out;
uint8_t buf[1024];
size_t bytes;
size_t length = 0;
uint32_t crc32 = 0xffffffff;
int i;
int err = 0;
 
/* Parse & validate arguments */
parse_options(argc, argv);
if (!in_path || !out_path || !productid) {
usage();
err = -EINVAL;
goto err;
}
 
/* Fill Asus tail */
tail.version[0] = version[0];
tail.version[1] = version[1];
tail.version[2] = version[2];
tail.version[3] = version[3];
strncpy(tail.productid, productid, sizeof(tail.productid));
 
/* Open files */
in = fopen(in_path, "r");
if (!in) {
fprintf(stderr, "Couldn't open %s\n", in_path);
err = -EIO;
goto err;
}
out = fopen(out_path, "w+");
if (!out) {
fprintf(stderr, "Couldn't open %s\n", out_path);
err = -EIO;
goto err;
}
 
/* Check is there is empty place for Asus tail */
bytes = sizeof(struct asustrx_tail);
fseek(in, -bytes, SEEK_END);
if (fread(buf, 1, bytes, in) != bytes) {
fprintf(stderr, "Couldn't read %zu B from %s\n", bytes, in_path);
err = -EIO;
goto err;
}
for (i = 0; i < bytes; i++) {
if (buf[i]) {
fprintf(stderr, "Input TRX doesn't have last 64 B empty %s\n", out_path);
err = -ENOSPC;
goto err;
}
}
 
/* Copy whole TRX */
rewind(in);
while ((bytes = fread(buf, 1, sizeof(buf), in)) > 0) {
if (fwrite(buf, 1, bytes, out) != bytes) {
fprintf(stderr, "Couldn't write %zu B to %s\n", bytes, out_path);
err = -EIO;
goto err;
}
}
 
/* Overwrite last 64 B with Asus tail */
bytes = sizeof(tail);
fseek(out, -bytes, SEEK_CUR);
if (fwrite(&tail, 1, bytes, out) != bytes) {
fprintf(stderr, "Couldn't write %zu B to %s\n", bytes, out_path);
err = -EIO;
goto err;
}
 
/* Calculate crc32 */
fseek(out, TRX_FLAGS_OFFSET, SEEK_SET);
length = TRX_FLAGS_OFFSET;
while ((bytes = fread(buf, 1, sizeof(buf), out )) > 0) {
length += bytes;
for (i = 0; i < bytes; i++)
crc32 = crc32_tbl[(crc32 ^ buf[i]) & 0xff] ^ (crc32 >> 8);
}
 
/* Update header */
bytes = sizeof(hdr);
rewind(out);
if (fread(&hdr, 1, sizeof(hdr), out) != bytes) {
fprintf(stderr, "Couldn't read %zu B from %s\n", bytes, in_path);
err = -EIO;
goto err;
}
hdr.crc32 = cpu_to_le32(crc32);
rewind(out);
if (fwrite(&hdr, 1, bytes, out) != bytes) {
fprintf(stderr, "Couldn't write %zu B to %s\n", bytes, out_path);
err = -EIO;
goto err;
}
 
err:
if (out)
fclose(out);
if (in)
fclose(in);
return err;
}
/branches/gl-inet/tools/firmware-utils/src/bcm_tag.h
@@ -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 OpenWRT, 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 OpenWRT)
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 */
/branches/gl-inet/tools/firmware-utils/src/bcmalgo.c
@@ -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" );
}
/branches/gl-inet/tools/firmware-utils/src/bcmalgo.h
@@ -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 );
/branches/gl-inet/tools/firmware-utils/src/buffalo-enc.c
@@ -0,0 +1,322 @@
/*
* 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;
static int offset;
static int size;
 
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"
" -O Offset of encrypted data in file (decryption)\n"
" -S Size of unencrypted data in file (encryption)\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 + offset, src_len - offset);
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 + offset, 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, tail_dst, tail_len, tail_src;
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;
}
 
if (size) {
tail_dst = enc_compute_buf_len(product, version, size);
tail_len = src_len - size;
totlen = tail_dst + tail_len;
} else
totlen = enc_compute_buf_len(product, version, src_len);
 
buf = malloc(totlen);
if (buf == NULL) {
ERR("no memory for the buffer");
goto out;
}
 
hdrlen = enc_compute_header_len(product, version);
 
err = read_file_to_buf(ifname, &buf[hdrlen], src_len);
if (err) {
ERR("unable to read from file '%s'", ofname);
goto free_buf;
}
 
if (size) {
tail_src = hdrlen + size;
memmove(&buf[tail_dst], &buf[tail_src], tail_len);
memset(&buf[tail_src], 0, tail_dst - tail_src);
src_len = size;
}
 
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:O:r:s: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 'O':
offset = strtoul(optarg, NULL, 0);
break;
case 'S':
size = strtoul(optarg, NULL, 0);
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;
}
/branches/gl-inet/tools/firmware-utils/src/buffalo-lib.c
@@ -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)
{
signed 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;
}
/branches/gl-inet/tools/firmware-utils/src/buffalo-lib.h
@@ -0,0 +1,141 @@
/*
* 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));
 
struct buffalo_tag3 {
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 base2;
} __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 */
/branches/gl-inet/tools/firmware-utils/src/buffalo-tag.c
@@ -0,0 +1,414 @@
/*
* 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;
static int dhp;
 
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"
" -I <file> read input from the file <file> for DHP series\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 void fixup_tag3(unsigned char *buf, ssize_t totlen)
{
struct buffalo_tag3 *tag = (struct buffalo_tag3 *) 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(totlen);
tag->len1 = htonl(fsize[0]);
tag->base2 = htonl(base2);
 
if (hwver) {
memcpy(tag->hwv, "hwv", 3);
memcpy(tag->hwv_val, hwver, strlen(hwver));
}
}
 
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 (dhp)
hdrlen = sizeof(struct buffalo_tag3);
else 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 (dhp)
fixup_tag3(buf, fsize[0] + 200);
else 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:I:");
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':
dhp = 1;
/* FALLTHROUGH */
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;
}
/branches/gl-inet/tools/firmware-utils/src/buffalo-tftp.c
@@ -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;
}
/branches/gl-inet/tools/firmware-utils/src/csysimg.h
@@ -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;
};
/branches/gl-inet/tools/firmware-utils/src/cyg_crc.h
@@ -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_
 
 
 
/branches/gl-inet/tools/firmware-utils/src/cyg_crc16.c
@@ -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;
}
 
/branches/gl-inet/tools/firmware-utils/src/cyg_crc32.c
@@ -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);
}
 
 
/branches/gl-inet/tools/firmware-utils/src/dgfirmware.c
@@ -0,0 +1,377 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.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;
}
 
/branches/gl-inet/tools/firmware-utils/src/dgn3500sum.c
@@ -0,0 +1,166 @@
/* **************************************************************************
 
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 = 0, sum1 = 0;
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;
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;
}
/branches/gl-inet/tools/firmware-utils/src/dns313-header.c
@@ -0,0 +1,239 @@
/*
* dns313-header.c
*
* Program to add the modified U-Boot header to a binary used with
* the D-Link DNS-313 boot loader when booting directly from an
* EXT2 formatted hard drive.
*
* The DNS313 use the same header on zImage, ramdisk, rootfs.
*
* Written by Linus Walleij <linus.walleij@linaro.org>
* License terms: GPLv2
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
 
/*
* This is the U-Boot magic number, so the U-Boot header was used
* (obviously) as a template for this custom header.
*/
#define IH_MAGIC 0x27051956
#define HEADER_SIZE 0x68
 
#define OFFSET_MAGIC 0x00
#define OFFSET_HCRC 0x04
#define OFFSET_TIME 0x08
#define OFFSET_SIZE 0x0c
#define OFFSET_LOAD 0x10
#define OFFSET_EP 0x14
#define OFFSET_DCRC 0x18
#define OFFSET_OS 0x1c
#define OFFSET_ARCH 0x1d
#define OFFSET_TYPE 0x1e
#define OFFSET_COMP 0x1f
#define OFFSET_NAME 0x20
#define NAME_LEN 0x20
#define OFFSET_MODEL 0x40
#define MODEL_LEN 0x10
#define OFFSET_VERSION 0x50
#define VERSION_LEN 0x10
#define OFFSET_MAC 0x60
#define MAC_LEN 6
 
static const uint32_t crc32_table[256] = {
0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,
0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,
0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,
0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,
0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,
0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,
0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,
0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,
0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,
0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,
0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,
0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,
0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,
0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,
0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,
0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,
0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,
0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,
0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,
0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,
0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,
0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,
0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
0x2d02ef8dUL
};
 
static uint32_t crc32(uint32_t crc,
const unsigned char *buf,
unsigned int len)
{
crc = crc ^ 0xffffffffUL;
do {
crc = crc32_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
} while (--len);
return crc ^ 0xffffffffUL;
}
 
static void be_wr(unsigned char *buf, uint32_t val)
{
buf[0] = (val >> 24) & 0xFFU;
buf[1] = (val >> 16) & 0xFFU;
buf[2] = (val >> 8) & 0xFFU;
buf[3] = val & 0xFFU;
}
 
int main(int argc, char **argv)
{
int fdin;
int fdout;
struct stat sb;
uint32_t filesize;
uint32_t padding;
int ret = 0;
const char *pathin;
const char *pathout;
unsigned char *buffer;
unsigned char *infop;
uint32_t sum;
size_t bufsize;
size_t bytes;
int i;
 
if (argc < 3) {
printf("Too few arguments.\n");
printf("%s <infile> <outfile>\n", argv[0]);
}
 
pathin = argv[1];
pathout = argv[2];
 
ret = stat(pathin, &sb);
if (ret < 0)
return ret;
 
filesize = sb.st_size;
padding = filesize % 4;
printf("INFILE: %s, size: %08x bytes\n", pathin, filesize);
/* File + extended header size */
bufsize = filesize + HEADER_SIZE;
 
printf("Allocate %08x bytes\n", bufsize);
buffer = malloc(bufsize);
if (!buffer) {
printf("OOM: could not allocate buffer\n");
return 0;
}
 
memset(buffer, 0x00, bufsize);
 
/* Read file to buffer */
fdin = open(pathin, O_RDONLY);
if (!fdin) {
printf("ERROR: could not open input file\n");
return 0;
}
bytes = read(fdin, buffer + HEADER_SIZE, filesize);
if (bytes < filesize) {
printf("ERROR: could not read entire file\n");
return 0;
}
close(fdin);
 
/* PREP HEADER AND FOOTER */
infop = buffer;
 
be_wr(buffer + OFFSET_MAGIC, IH_MAGIC);
 
/* FIXME: use actual time */
be_wr(buffer + OFFSET_TIME, 0x4c06738c);
be_wr(buffer + OFFSET_SIZE, filesize);
 
/* Load address & entry point */
be_wr(buffer + OFFSET_LOAD, 0x00008000);
be_wr(buffer + OFFSET_EP, 0x00008000);
 
buffer[OFFSET_OS] = 0x05; /* Linux */
buffer[OFFSET_ARCH] = 0x02; /* ARM */
buffer[OFFSET_TYPE] = 0x02; /* OS kernel image */
buffer[OFFSET_COMP] = 0x01; /* gzip */
 
/* The vendor firmware just hardcodes this */
strncpy(buffer + OFFSET_NAME, "kernel.img", NAME_LEN);
buffer[OFFSET_NAME + NAME_LEN - 1] = '\0';
strncpy(buffer + OFFSET_MODEL, "dns-313v3", MODEL_LEN);
buffer[OFFSET_MODEL + MODEL_LEN - 1] = '\0';
strncpy(buffer + OFFSET_VERSION, "2.01b04", VERSION_LEN);
buffer[OFFSET_VERSION + VERSION_LEN - 1] = '\0';
/* Just some MAC address from the example */
buffer[OFFSET_MAC] = 0x00;
buffer[OFFSET_MAC + 1] = 0x80;
buffer[OFFSET_MAC + 2] = 0xc8;
buffer[OFFSET_MAC + 3] = 0x16;
buffer[OFFSET_MAC + 4] = 0x81;
buffer[OFFSET_MAC + 5] = 0x68;
 
/* Checksum payload */
sum = crc32(0, buffer + HEADER_SIZE, filesize);
be_wr(buffer + OFFSET_DCRC, sum);
printf("data checksum: 0x%08x\n", sum);
 
/* Checksum header, then write that into the header checksum */
sum = crc32(0, buffer, HEADER_SIZE);
be_wr(buffer + OFFSET_HCRC, sum);
printf("header checksum: 0x%08x\n", sum);
 
printf("OUTFILE: %s, size: %08x bytes\n", pathout, bufsize);
fdout = open(pathout, O_RDWR|O_CREAT|O_TRUNC,S_IRWXU|S_IRGRP);
if (!fdout) {
printf("ERROR: could not open output file\n");
return 0;
}
bytes = write(fdout, buffer, bufsize);
if (bytes < bufsize) {
printf("ERROR: could not write complete output file\n");
return 0;
}
close(fdout);
 
free(buffer);
 
return 0;
}
/branches/gl-inet/tools/firmware-utils/src/edimax_fw_header.c
@@ -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;
}
/branches/gl-inet/tools/firmware-utils/src/encode_crc.c
@@ -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;
}
/branches/gl-inet/tools/firmware-utils/src/fix-u-media-header.c
@@ -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;
}
/branches/gl-inet/tools/firmware-utils/src/fw.h
@@ -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
/branches/gl-inet/tools/firmware-utils/src/hcsmakeimage.c
@@ -0,0 +1,203 @@
#include <stdlib.h>
#include <sys/types.h>
#include <stdio.h>
#include <inttypes.h>
#include <string.h>
#include <getopt.h>
#include <unistd.h>
#include <errno.h>
#include <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" );
}
 
static time_t source_date_epoch = -1;
static void set_source_date_epoch() {
char *env = getenv("SOURCE_DATE_EPOCH");
char *endptr = env;
errno = 0;
if (env && *env) {
source_date_epoch = strtoull(env, &endptr, 10);
if (errno || (endptr && *endptr != '\0')) {
fprintf(stderr, "Invalid SOURCE_DATE_EPOCH");
exit(1);
}
}
}
 
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;
}
 
time_t t = -1;
set_source_date_epoch();
if (source_date_epoch != -1) {
t = source_date_epoch;
} else if ((time(&t) == (time_t)(-1))) {
fprintf(stderr, "time call failed\n");
return EXIT_FAILURE;
}
 
struct stat buf;
stat ( input,&buf );
ldr_header_t* head = construct_header ( magicnum, (uint16_t) majrev, (uint16_t) minrev, ( uint32_t ) t, ( 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;
}
/branches/gl-inet/tools/firmware-utils/src/imagetag.c
@@ -0,0 +1,491 @@
/*
* 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 <openwrt@cshore.neomailbox.net>
*/
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <inttypes.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;
else
rootfsoff = (rootfsoff % 4) > 0 ? (((rootfsoff / 4) + 1) * 4) : 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, "%" PRIu32, 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, args->altinfo_arg, TAGINFO1_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);
}
/branches/gl-inet/tools/firmware-utils/src/imagetag.ggo
@@ -0,0 +1,46 @@
# Command line option parsing generator file for imagetag
# Supplied-To: gengetopt
#
# Copyright 2010 Daniel Dickinson <openwrt@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
/branches/gl-inet/tools/firmware-utils/src/imagetag_cmdline.c
@@ -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);
}
/branches/gl-inet/tools/firmware-utils/src/imagetag_cmdline.h
@@ -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 */
/branches/gl-inet/tools/firmware-utils/src/jcgimage.c
@@ -0,0 +1,425 @@
/*
* jcgimage - Create a JCG firmware image
*
* Copyright (C) 2015 Reinhard Max <reinhard@m4x.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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
 
/*
* JCG firmware update images consist of a 512 byte header and a
* modified uImage (details below) as the payload.
*
* The payload is obfuscated by XORing it with a key that is generated
* from parts of the header. Fortunately only non-essential parts of
* the header are used for this and zeroing them results in a zero
* key, effectively disabling the obfuscation and allowing us to use
* clear text payloads.
*
* The mandatory parts of the header are:
*
* - A magic string of "YSZJ" at offset 0.
* - A value of 1 at offset 39 (header format version?)
* - A CRC32 checksum of the payload at offset 504.
* - A CRC32 checksum of the header at offset 508.
*
* An image constructed by these rules will be accepted by JCG's
* U-Boot in resuce mode via TFTP and the payload will be written to
* the flash starting at offset 0x00050000.
*
* JCG's U-Boot does check the content or size of the payload
* image. If it is too large, it wraps around and overwrites U-Boot,
* requiring JTAG to revive the board. To prevent such bricking from
* happening, this tool refuses to build such overlong images.
*
* Two more conditions have to be met for a JCG image to be accepted
* as a valid update by the web interface of the stock firware:
*
* - The bytes at offsets 109 and 111 in the header must be a binary
* representation of the first two components of the firmware
* version as displayed in the update web form, or it will be
* rejected as "incorrect product".
*
* - The payload must start with a valid uImage header whose data
* CRC checksum matches the whole rest of the update file rather
* than just the number of bytes specified in the size field of the
* header.
*
* This last condition is met by JCG's original firmware images,
* because they have both, kernel and rootfs inside the uImage and
* abuse the last four bytes of the name field to record the offset of
* the file system from the start of the uImage header. This tool
* produces such images when called with -k and -r, which are meant to
* repack the original firmware after modifying the file systen,
* e.g. to add debugging tools and enable shell access.
*
* In contrast, OpenWrt sysupgrade images consist of a uImage that
* only contains the kernel and has the rootfs appended to it. Hence,
* the CRC over kernel and file system does not match the one in the
* uImage header. Fixing this by adjusting the uImage header is not
* possible, because it makes the uImage unusable for booting. Instead
* we append four "patch" bytes to the end of the file system, that
* are calculated to force the checksum of kernel+fs to be the same as
* for the kernel alone.
*
*/
 
#include <zlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <libgen.h>
#include <stdlib.h>
#include <errno.h>
#include <err.h>
#include <time.h>
#include <sys/mman.h>
#include <arpa/inet.h>
#include <assert.h>
 
/*
* JCG Firmware image header
*/
#define JH_MAGIC 0x59535a4a /* "YSZJ" */
struct jcg_header {
uint32_t jh_magic;
uint8_t jh_version[32]; /* Firmware version string.
Fill with zeros to avoid encryption */
uint32_t jh_type; /* must be 1 */
uint8_t jh_info[64]; /* Firmware info string. Fill with
zeros to avoid encryption */
uint32_t jh_time; /* Image creation time in seconds since
* the Epoch. Does not seem to be used
* by the stock firmware. */
uint16_t jh_major; /* Major fimware version */
uint16_t jh_minor; /* Minor fimrmware version */
uint8_t jh_unknown[392]; /* Apparently unused and all zeros */
uint32_t jh_dcrc; /* CRC checksum of the payload */
uint32_t jh_hcrc; /* CRC checksum of the header */
};
 
/*
* JCG uses a modified uImage header that replaces the last four bytes
* of the image name with the length of the kernel in the image.
*/
#define IH_MAGIC 0x27051956 /* Image Magic Number */
#define IH_NMLEN 28 /* Image Name Length */
 
struct uimage_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 */
uint32_t ih_fsoff; /* Offset of the file system
partition from the start of
the header */
};
 
/*
* Open the named file and return its size and file descriptor.
* Exit in case of errors.
*/
int
opensize(char *name, size_t *size)
{
struct stat s;
int fd = open(name, O_RDONLY);
if (fd < 0) {
err(1, "cannot open \"%s\"", name);
}
if (fstat(fd, &s) == -1) {
err(1, "cannot stat \"%s\"", name);
}
*size = s.st_size;
return fd;
}
 
static time_t source_date_epoch = -1;
static void set_source_date_epoch() {
char *env = getenv("SOURCE_DATE_EPOCH");
char *endptr = env;
errno = 0;
if (env && *env) {
source_date_epoch = strtoull(env, &endptr, 10);
if (errno || (endptr && *endptr != '\0')) {
fprintf(stderr, "Invalid SOURCE_DATE_EPOCH");
exit(1);
}
}
}
 
/*
* Write the JCG header
*/
void
mkjcgheader(struct jcg_header *h, size_t psize, char *version)
{
uLong crc;
uint16_t major = 0, minor = 0;
void *payload = (void *)h + sizeof(*h);
time_t t;
 
if (source_date_epoch != -1) {
t = source_date_epoch;
} else if ((time(&t) == (time_t)(-1))) {
err(1, "time call failed");
}
 
if (version != NULL) {
if (sscanf(version, "%hu.%hu", &major, &minor) != 2) {
err(1, "cannot parse version \"%s\"", version);
}
}
 
memset(h, 0, sizeof(*h));
h->jh_magic = htonl(JH_MAGIC);
h->jh_type = htonl(1);
h->jh_time = htonl(t);
h->jh_major = htons(major);
h->jh_minor = htons(minor);
 
/* CRC over JCG payload (uImage) */
crc = crc32(0L, Z_NULL, 0);
crc = crc32(crc, payload, psize);
h->jh_dcrc = htonl(crc);
 
/* CRC over JCG header */
crc = crc32(0L, Z_NULL, 0);
crc = crc32(crc, (void *)h, sizeof(*h));
h->jh_hcrc = htonl(crc);
}
 
/*
* Write the uImage header
*/
void
mkuheader(struct uimage_header *h, size_t ksize, size_t fsize)
{
uLong crc;
void *payload = (void *)h + sizeof(*h);
 
// printf("mkuheader: %p, %zd, %zd\n", h, ksize, fsize);
memset(h, 0, sizeof(*h));
h->ih_magic = htonl(IH_MAGIC);
h->ih_time = htonl(time(NULL));
h->ih_size = htonl(ksize + fsize);
h->ih_load = htonl(0x80000000);
h->ih_ep = htonl(0x80292000);
h->ih_os = 0x05;
h->ih_arch = 0x05;
h->ih_type = 0x02;
h->ih_comp = 0x03;
h->ih_fsoff = htonl(sizeof(*h) + ksize);
strcpy((char *)h->ih_name, "Linux Kernel Image");
 
/* CRC over uImage payload (kernel and file system) */
crc = crc32(0L, Z_NULL, 0);
crc = crc32(crc, payload, ntohl(h->ih_size));
h->ih_dcrc = htonl(crc);
printf("CRC1: %08lx\n", crc);
 
/* CRC over uImage header */
crc = crc32(0L, Z_NULL, 0);
crc = crc32(crc, (void *)h, sizeof(*h));
h->ih_hcrc = htonl(crc);
printf("CRC2: %08lx\n", crc);
}
 
/*
* Calculate a "patch" value and write it into the last four bytes of
* buf, so that the CRC32 checksum of the whole buffer is dcrc.
*
* Based on: SAR-PR-2006-05: Reversing CRC – Theory and Practice.
* Martin Stigge, Henryk Plötz, Wolf Müller, Jens-Peter Redlich.
* http://sar.informatik.hu-berlin.de/research/publications/#SAR-PR-2006-05
*/
void
craftcrc(uint32_t dcrc, uint8_t *buf, size_t len)
{
int i;
uint32_t a;
uint32_t patch = 0;
uint32_t crc = crc32(0L, Z_NULL, 0);
 
a = ~dcrc;
for (i = 0; i < 32; i++) {
if (patch & 1) {
patch = (patch >> 1) ^ 0xedb88320L;
} else {
patch >>= 1;
}
if (a & 1) {
patch ^= 0x5b358fd3L;
}
a >>= 1;
}
patch ^= ~crc32(crc, buf, len - 4);
for (i = 0; i < 4; i++) {
buf[len - 4 + i] = patch & 0xff;
patch >>= 8;
}
/* Verify that we actually get the desired result */
crc = crc32(0L, Z_NULL, 0);
crc = crc32(crc, buf, len);
if (crc != dcrc) {
errx(1, "CRC patching is broken: wanted %08x, but got %08x.",
dcrc, crc);
}
}
 
void
usage() {
fprintf(stderr, "Usage:\n"
"jcgimage -o outfile -u uImage [-v version]\n"
"jcgimage -o outfile -k kernel -f rootfs [-v version]\n");
exit(1);
}
 
#define MODE_UNKNOWN 0
#define MODE_UIMAGE 1
#define MODE_KR 2
 
/* The output image must not be larger than 4MiB - 5*64kiB */
#define MAXSIZE (size_t)(4 * 1024 * 1024 - 5 * 64 * 1024)
 
int
main(int argc, char **argv)
{
struct jcg_header *jh;
struct uimage_header *uh;
int c;
char *imagefile = NULL;
char *file1 = NULL;
char *file2 = NULL;
char *version = NULL;
int mode = MODE_UNKNOWN;
int fdo, fd1, fd2;
size_t size1, size2, sizeu, sizeo, off1, off2;
void *map;
 
/* Make sure the headers have the right size */
assert(sizeof(struct jcg_header) == 512);
assert(sizeof(struct uimage_header) == 64);
set_source_date_epoch();
 
while ((c = getopt(argc, argv, "o:k:f:u:v:h")) != -1) {
switch (c) {
case 'o':
imagefile = optarg;
break;
case 'k':
if (mode == MODE_UIMAGE) {
errx(1,"-k cannot be combined with -u");
}
mode = MODE_KR;
file1 = optarg;
break;
case 'f':
if (mode == MODE_UIMAGE) {
errx(1,"-f cannot be combined with -u");
}
mode = MODE_KR;
file2 = optarg;
break;
case 'u':
if (mode == MODE_KR) {
errx(1,"-u cannot be combined with -k and -r");
}
mode = MODE_UIMAGE;
file1 = optarg;
break;
case 'v':
version = optarg;
break;
case 'h':
default:
usage();
}
}
if (optind != argc) {
errx(1, "illegal arg \"%s\"", argv[optind]);
}
if (imagefile == NULL) {
errx(1, "no output file specified");
}
if (mode == MODE_UNKNOWN) {
errx(1, "specify either -u or -k and -r");
}
if (mode == MODE_KR) {
if (file1 == NULL || file2 == NULL) {
errx(1,"need -k and -r");
}
fd2 = opensize(file2, &size2);
}
fd1 = opensize(file1, &size1);
if (mode == MODE_UIMAGE) {
off1 = sizeof(*jh);
sizeu = size1 + 4;
sizeo = sizeof(*jh) + sizeu;
} else {
off1 = sizeof(*jh) + sizeof(*uh);
off2 = sizeof(*jh) + sizeof(*uh) + size1;
sizeu = sizeof(*uh) + size1 + size2;
sizeo = sizeof(*jh) + sizeu;
}
 
if (sizeo > MAXSIZE) {
errx(1,"payload too large: %zd > %zd\n", sizeo, MAXSIZE);
}
 
fdo = open(imagefile, O_RDWR | O_CREAT | O_TRUNC, 00644);
if (fdo < 0) {
err(1, "cannot open \"%s\"", imagefile);
}
 
if (ftruncate(fdo, sizeo) == -1) {
err(1, "cannot grow \"%s\" to %zd bytes", imagefile, sizeo);
}
map = mmap(NULL, sizeo, PROT_READ|PROT_WRITE, MAP_SHARED, fdo, 0);
uh = map + sizeof(*jh);
if (map == MAP_FAILED) {
err(1, "cannot mmap \"%s\"", imagefile);
}
 
if (read(fd1, map + off1, size1) != size1) {
err(1, "cannot copy %s", file1);
}
 
if (mode == MODE_KR) {
if (read(fd2, map+off2, size2) != size2) {
err(1, "cannot copy %s", file2);
}
mkuheader(uh, size1, size2);
} else if (mode == MODE_UIMAGE) {
craftcrc(ntohl(uh->ih_dcrc), (void*)uh + sizeof(*uh),
sizeu - sizeof(*uh));
}
mkjcgheader(map, sizeu, version);
munmap(map, sizeo);
close(fdo);
return 0;
}
/branches/gl-inet/tools/firmware-utils/src/lzma2eva.c
@@ -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 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;
}
/branches/gl-inet/tools/firmware-utils/src/makeamitbin.c
@@ -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;
}
/branches/gl-inet/tools/firmware-utils/src/md5.c
@@ -0,0 +1,296 @@
/*
* This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
* MD5 Message-Digest Algorithm (RFC 1321).
*
* Homepage:
* http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
*
* Author:
* Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
*
* This software was written by Alexander Peslyak in 2001. No copyright is
* claimed, and the software is hereby placed in the public domain.
* In case this attempt to disclaim copyright and place the software in the
* public domain is deemed null and void, then the software is
* Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
* general public under the following terms:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* There's ABSOLUTELY NO WARRANTY, express or implied.
*
* (This is a heavily cut-down "BSD license".)
*
* This differs from Colin Plumb's older public domain implementation in that
* no exactly 32-bit integer data type is required (any 32-bit or wider
* unsigned integer data type will do), there's no compile-time endianness
* configuration, and the function prototypes match OpenSSL's. No code from
* Colin Plumb's implementation has been reused; this comment merely compares
* the properties of the two independent implementations.
*
* The primary goals of this implementation are portability and ease of use.
* It is meant to be fast, but not as fast as possible. Some known
* optimizations are not included to reduce source code size and avoid
* compile-time configuration.
*/
 
#ifndef HAVE_OPENSSL
 
#include <string.h>
 
#include "md5.h"
 
/*
* The basic MD5 functions.
*
* F and G are optimized compared to their RFC 1321 definitions for
* architectures that lack an AND-NOT instruction, just like in Colin Plumb's
* implementation.
*/
#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
#define H(x, y, z) (((x) ^ (y)) ^ (z))
#define H2(x, y, z) ((x) ^ ((y) ^ (z)))
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
 
/*
* The MD5 transformation for all four rounds.
*/
#define STEP(f, a, b, c, d, x, t, s) \
(a) += f((b), (c), (d)) + (x) + (t); \
(a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
(a) += (b);
 
/*
* SET reads 4 input bytes in little-endian byte order and stores them
* in a properly aligned word in host byte order.
*
* The check for little-endian architectures that tolerate unaligned
* memory accesses is just an optimization. Nothing will break if it
* doesn't work.
*/
#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
#define SET(n) \
(*(MD5_u32plus *)&ptr[(n) * 4])
#define GET(n) \
SET(n)
#else
#define SET(n) \
(ctx->block[(n)] = \
(MD5_u32plus)ptr[(n) * 4] | \
((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \
((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \
((MD5_u32plus)ptr[(n) * 4 + 3] << 24))
#define GET(n) \
(ctx->block[(n)])
#endif
 
/*
* This processes one or more 64-byte data blocks, but does NOT update
* the bit counters. There are no alignment requirements.
*/
static const void *body(MD5_CTX *ctx, const void *data, unsigned long size)
{
const unsigned char *ptr;
MD5_u32plus a, b, c, d;
MD5_u32plus saved_a, saved_b, saved_c, saved_d;
 
ptr = (const unsigned char *)data;
 
a = ctx->a;
b = ctx->b;
c = ctx->c;
d = ctx->d;
 
do {
saved_a = a;
saved_b = b;
saved_c = c;
saved_d = d;
 
/* Round 1 */
STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
 
/* Round 2 */
STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
 
/* Round 3 */
STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11)
STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23)
STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11)
STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23)
STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11)
STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23)
STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11)
STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23)
 
/* Round 4 */
STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
 
a += saved_a;
b += saved_b;
c += saved_c;
d += saved_d;
 
ptr += 64;
} while (size -= 64);
 
ctx->a = a;
ctx->b = b;
ctx->c = c;
ctx->d = d;
 
return ptr;
}
 
void MD5_Init(MD5_CTX *ctx)
{
ctx->a = 0x67452301;
ctx->b = 0xefcdab89;
ctx->c = 0x98badcfe;
ctx->d = 0x10325476;
 
ctx->lo = 0;
ctx->hi = 0;
}
 
void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size)
{
MD5_u32plus saved_lo;
unsigned long used, available;
 
saved_lo = ctx->lo;
if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
ctx->hi++;
ctx->hi += size >> 29;
 
used = saved_lo & 0x3f;
 
if (used) {
available = 64 - used;
 
if (size < available) {
memcpy(&ctx->buffer[used], data, size);
return;
}
 
memcpy(&ctx->buffer[used], data, available);
data = (const unsigned char *)data + available;
size -= available;
body(ctx, ctx->buffer, 64);
}
 
if (size >= 64) {
data = body(ctx, data, size & ~(unsigned long)0x3f);
size &= 0x3f;
}
 
memcpy(ctx->buffer, data, size);
}
 
void MD5_Final(unsigned char *result, MD5_CTX *ctx)
{
unsigned long used, available;
 
used = ctx->lo & 0x3f;
 
ctx->buffer[used++] = 0x80;
 
available = 64 - used;
 
if (available < 8) {
memset(&ctx->buffer[used], 0, available);
body(ctx, ctx->buffer, 64);
used = 0;
available = 64;
}
 
memset(&ctx->buffer[used], 0, available - 8);
 
ctx->lo <<= 3;
ctx->buffer[56] = ctx->lo;
ctx->buffer[57] = ctx->lo >> 8;
ctx->buffer[58] = ctx->lo >> 16;
ctx->buffer[59] = ctx->lo >> 24;
ctx->buffer[60] = ctx->hi;
ctx->buffer[61] = ctx->hi >> 8;
ctx->buffer[62] = ctx->hi >> 16;
ctx->buffer[63] = ctx->hi >> 24;
 
body(ctx, ctx->buffer, 64);
 
result[0] = ctx->a;
result[1] = ctx->a >> 8;
result[2] = ctx->a >> 16;
result[3] = ctx->a >> 24;
result[4] = ctx->b;
result[5] = ctx->b >> 8;
result[6] = ctx->b >> 16;
result[7] = ctx->b >> 24;
result[8] = ctx->c;
result[9] = ctx->c >> 8;
result[10] = ctx->c >> 16;
result[11] = ctx->c >> 24;
result[12] = ctx->d;
result[13] = ctx->d >> 8;
result[14] = ctx->d >> 16;
result[15] = ctx->d >> 24;
 
memset(ctx, 0, sizeof(*ctx));
}
 
#endif
/branches/gl-inet/tools/firmware-utils/src/md5.h
@@ -0,0 +1,45 @@
/*
* This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
* MD5 Message-Digest Algorithm (RFC 1321).
*
* Homepage:
* http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
*
* Author:
* Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
*
* This software was written by Alexander Peslyak in 2001. No copyright is
* claimed, and the software is hereby placed in the public domain.
* In case this attempt to disclaim copyright and place the software in the
* public domain is deemed null and void, then the software is
* Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
* general public under the following terms:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* There's ABSOLUTELY NO WARRANTY, express or implied.
*
* See md5.c for more information.
*/
 
#ifdef HAVE_OPENSSL
#include <openssl/md5.h>
#elif !defined(_MD5_H)
#define _MD5_H
 
/* Any 32-bit or wider unsigned integer data type will do */
typedef unsigned int MD5_u32plus;
 
typedef struct {
MD5_u32plus lo, hi;
MD5_u32plus a, b, c, d;
unsigned char buffer[64];
MD5_u32plus block[16];
} MD5_CTX;
 
extern void MD5_Init(MD5_CTX *ctx);
extern void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size);
extern void MD5_Final(unsigned char *result, MD5_CTX *ctx);
 
#endif
/branches/gl-inet/tools/firmware-utils/src/mkbrncmdline.c
@@ -0,0 +1,168 @@
/*
* mkbrncmdline.c - partially based on OpenWrt's wndr3700.c
*
* Copyright (C) 2011 Tobias Diedrich <ranma+openwrt@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;
}
/branches/gl-inet/tools/firmware-utils/src/mkbrnimg.c
@@ -0,0 +1,189 @@
/*
* mkbrnimg.c - partially based on OpenWrt's wndr3700.c
*
* Copyright (C) 2011 Tobias Diedrich <ranma+openwrt@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 char *output_file = "default-brnImage";
static uint32_t magic = 0x12345678;
static char *signature = "BRNDTW502";
static uint32_t crc32_poly = 0x2083b8ed;
 
static void init_crc32()
{
const uint32_t poly = ntohl(crc32_poly);
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] [-p crc32 poly] kernel_file [additional files]\n");
fprintf(stderr, "\n");
exit(1);
}
 
static void parseopts(int *argc, char ***argv)
{
char *endptr;
int res;
 
while ((res = getopt(*argc, *argv, "o:m:s:p:")) != -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;
case 'p':
crc32_poly = strtoul(optarg, &endptr, 0);
if (endptr == optarg || *endptr != 0)
usage("'crc32 poly' must be a decimal or hexadecimal 32-bit value");
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=%08zx padded_len=%08zx\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;
}
/branches/gl-inet/tools/firmware-utils/src/mkbuffaloimg.c
@@ -0,0 +1,223 @@
/*
* Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
* Copyright (C) 2016 FUKAUMI Naoki <naobsd@gmail.com>
*
* Based on mkdniimg.c
*
* 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 = "0.00_0.00";
static char *region = "JP";
static char *rootfs_size;
static char *kernel_size;
 
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 ": %s\n", \
progname, ## __VA_ARGS__, strerror(save)); \
} while (0)
 
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"
" -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"
" -R <rootfs_size> set RootfsSize to <rootfs_size>\n"
" -K <kernel_size> set KernelSize to <kernel_size>\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 i;
uint8_t csum;
 
FILE *outfile, *infile;
 
progname = basename(argv[0]);
 
while ( 1 ) {
int c;
 
c = getopt(argc, argv, "B:i:o:v:r:R:K: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 'R':
rootfs_size = optarg;
break;
case 'K':
kernel_size = optarg;
break;
case 'h':
usage(EXIT_SUCCESS);
break;
default:
usage(EXIT_FAILURE);
break;
}
}
 
if (board_id == NULL) {
ERR("no board specified");
goto err;
}
 
if (rootfs_size == NULL) {
ERR("no rootfs_size specified");
goto err;
}
 
if (kernel_size == NULL) {
ERR("no kernel_size 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);
snprintf(buf, DNI_HDR_LEN, "device:%s\nversion:%s\nregion:%s\n"
"RootfsSize:%s\nKernelSize:%s\nInfoHeadSize:128\n",
board_id, version, region, rootfs_size, kernel_size);
buf[DNI_HDR_LEN - 2] = 0x12;
buf[DNI_HDR_LEN - 1] = 0x32;
 
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;
 
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;
}
/branches/gl-inet/tools/firmware-utils/src/mkcameofw.c
@@ -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;
}
 
/branches/gl-inet/tools/firmware-utils/src/mkcasfw.c
@@ -0,0 +1,1030 @@
/*
*
* Copyright (C) 2007 OpenWrt.org
* Copyright (C) 2007 Gabor Juhos <juhosg at 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 <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 ": %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
 
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=%zu", 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 \"%s\" disabled", ofname);
goto out;
}
 
WARN("generating invalid image: \"%s\"", 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;
}
/branches/gl-inet/tools/firmware-utils/src/mkchkimg.c
@@ -0,0 +1,341 @@
/*
* 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)
 
/*
* Note on the reserved field of the chk_header:
* OFW naming scheme is typically: DEVICENAME-VA.B.C.D_E.F.G.chk, with A-G
* between 0 and 255. For instance: EX3700_EX3800-V1.0.0.58_1.0.38.chk
* The reserved field works like this:
* reserved[0]: region code. 1 for WW (WorldWide) and 2 for NA (North America)
* reserved[1]: A
* reserved[2]: B
* reserved[3]: C
* reserved[4]: D
* reserved[5]: E
* reserved[6]: F
* reserved[7]: G
*/
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;
hdr->reserved[5] = 0;
hdr->reserved[6] = 0;
hdr->reserved[7] = 0;
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;
}
 
/branches/gl-inet/tools/firmware-utils/src/mkcsysimg.c
@@ -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 ": %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
 
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=%zu", 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 \"%s\" disabled", ofname);
goto out;
}
 
WARN("generating invalid image: \"%s\"", 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;
}
/branches/gl-inet/tools/firmware-utils/src/mkdapimg.c
@@ -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);
}
/branches/gl-inet/tools/firmware-utils/src/mkdapimg2.c
@@ -0,0 +1,204 @@
/*
* 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) Nicolò Veronese <nicveronese@gmail.com>
*/
 
#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: mkdapimg2 -s signature [-v version] [-r region]
// [-k uImage block size] -i <input> -o <output>
//
// NOTE: The kernel block size is used to know the offset of the rootfs
// in the image file.
//
// The system writes in the uImage partition until the end of uImage
// is reached, after that, the system jumps to the offset specified with the -k
// parameter and begin writing at the beginning of the rootfs MTD partition.
//
// If the -k parameter is the size of the original uImage partition, the system
// continue writing in the rootfs partition starting from the last block
// that has been wrote. (This is useful if the new kernel size is
// different from the original one)
//
// Example:
// ------------------------------------------
// Creating 7 MTD partitions on "ath-nor0":
// 0x000000000000-0x000000010000 : "u-boot"
// 0x000000010000-0x000000020000 : "ART"
// 0x000000020000-0x000000030000 : "MP"
// 0x000000030000-0x000000040000 : "config"
// 0x000000040000-0x000000120000 : "uImage"
// 0x000000120000-0x000000800000 : "rootfs"
// 0x000000040000-0x000000800000 : "firmware"
// ------------------------------------------
//
// 0x000000120000-0x000000040000 = 0xE0000 -> 917504
//
// e.g.: mkdapimg2 -s HONEYBEE-FIRMWARE-DAP-1330 -v 1.00.21 -r Default
// -k 917504 -i sysupgarde.bin -o factory.bin
//
//
// The img_hdr_struct was taken from the D-Link SDK:
// DAP-1330_OSS-firmware_1.00b21/DAP-1330_OSS-firmware_1.00b21/uboot/uboot.patch
 
#define MAX_SIGN_LEN 32
#define MAX_FW_VER_LEN 16
#define MAX_REG_LEN 8
 
struct img_hdr_struct {
uint32_t hdr_len;
uint32_t checksum;
uint32_t total_size;
uint32_t kernel_size;
char signature[MAX_SIGN_LEN];
char fw_ver[MAX_FW_VER_LEN];
char fw_reg[MAX_REG_LEN];
} 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 -s signature [-v version] [-r region] [-k uImage part size] -i <input> -o <output>\n", progname);
exit(1);
}
 
int
main(int ac, char *av[])
{
char signature[MAX_SIGN_LEN];
char version[MAX_FW_VER_LEN];
char region[MAX_REG_LEN];
int kernel = 0;
 
FILE *ifile, *ofile;
int c;
 
uint32_t cksum;
uint32_t bcnt;
 
progname = basename(av[0]);
 
memset(signature, 0, sizeof(signature));
memset(version, 0, sizeof(version));
memset(region, 0, sizeof(region));
 
while ( 1 ) {
char *ptr;
int c;
 
c = getopt(ac, av, "s:v:r:k:i:o:");
if (c == -1)
break;
 
switch (c) {
case 's':
if (strlen(optarg) > MAX_SIGN_LEN + 1) {
fprintf(stderr, "%s: signature exceeds %d chars\n",
progname, MAX_SIGN_LEN);
exit(1);
}
strcpy(signature, optarg);
break;
case 'v':
if (strlen(optarg) > MAX_FW_VER_LEN + 1) {
fprintf(stderr, "%s: version exceeds %d chars\n",
progname, MAX_FW_VER_LEN);
exit(1);
}
strcpy(version, optarg);
break;
case 'r':
if (strlen(optarg) > MAX_REG_LEN + 1) {
fprintf(stderr, "%s: region exceeds %d chars\n",
progname, MAX_REG_LEN);
exit(1);
}
strcpy(region, optarg);
break;
case 'k':
kernel = strtoul(optarg, &ptr, 0);
if(ptr[0] == 'k'){
kernel *= 1000;
}
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();
exit(1);
}
 
for (bcnt = 0, cksum = 0 ; (c = fgetc(ifile)) != EOF ; bcnt++)
cksum += c & 0xff;
 
if (fseek(ifile, 0, SEEK_SET) < 0)
perrexit(2, "fseek on input");
 
// Fill in the header
memset(&imghdr, 0, sizeof(imghdr));
imghdr.hdr_len = sizeof(imghdr);
imghdr.checksum = htonl(cksum);
imghdr.total_size = htonl(bcnt);
imghdr.kernel_size = htonl(kernel);
 
strncpy(imghdr.signature, signature, MAX_SIGN_LEN);
strncpy(imghdr.fw_ver, version, MAX_FW_VER_LEN);
strncpy(imghdr.fw_reg, region, MAX_REG_LEN);
 
if (fwrite(&imghdr, sizeof(imghdr), 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);
 
fprintf(stderr, "imgHdr.hdr_len = %lu\n", sizeof(imghdr));
fprintf(stderr, "imgHdr.checksum = 0x%08x\n", cksum);
fprintf(stderr, "imgHdr.total_size = 0x%08x\n", bcnt);
fprintf(stderr, "imgHdr.kernel_size = 0x%08x\n", kernel);
fprintf(stderr, "imgHdr.header = %s\n", signature);
fprintf(stderr, "imgHdr.fw_ver = %s\n", version);
fprintf(stderr, "imgHdr.fw_reg = %s\n", region);
 
return 0;
}
/branches/gl-inet/tools/firmware-utils/src/mkdcs932.c
@@ -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;
}
/branches/gl-inet/tools/firmware-utils/src/mkdhpimg.c
@@ -0,0 +1,85 @@
/*
* Copyright (c) 2016 FUKAUMI Naoki <naobsd@gmail.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 <sys/stat.h>
#include <err.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
 
#include "buffalo-lib.h"
 
#define DHP_HEADER_SIZE 20
 
static char *progname;
 
static void
usage(void)
{
 
fprintf(stderr, "usage: %s <in> <out>\n", progname);
exit(EXIT_FAILURE);
}
 
int
main(int argc, char *argv[])
{
struct stat in_st;
size_t size;
uint32_t crc;
int in, out;
uint8_t *buf;
 
progname = argv[0];
 
if (argc != 3)
usage();
 
if ((in = open(argv[1], O_RDONLY)) == -1)
err(EXIT_FAILURE, "%s", argv[1]);
 
if (fstat(in, &in_st) == -1)
err(EXIT_FAILURE, "%s", argv[1]);
 
size = DHP_HEADER_SIZE + in_st.st_size;
 
if ((buf = malloc(size)) == NULL)
err(EXIT_FAILURE, "malloc");
 
memset(buf, 0, DHP_HEADER_SIZE);
buf[0x0] = 0x62;
buf[0x1] = 0x67;
buf[0x2] = 0x6e;
buf[0xb] = 0xb1;
buf[0xc] = (size >> 24) & 0xff;
buf[0xd] = (size >> 16) & 0xff;
buf[0xe] = (size >> 8) & 0xff;
buf[0xf] = size & 0xff;
 
read(in, &buf[DHP_HEADER_SIZE], in_st.st_size);
close(in);
 
crc = buffalo_crc(buf, size);
buf[0x10] = (crc >> 24) & 0xff;
buf[0x11] = (crc >> 16) & 0xff;
buf[0x12] = (crc >> 8) & 0xff;
buf[0x13] = crc & 0xff;
 
if ((out = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0644)) == -1)
err(EXIT_FAILURE, "%s", argv[2]);
write(out, buf, size);
close(out);
 
free(buf);
 
return EXIT_SUCCESS;
}
/branches/gl-inet/tools/firmware-utils/src/mkdlinkfw-lib.c
@@ -0,0 +1,172 @@
/*
* mkdlinkfw
*
* Copyright (C) 2018 Paweł Dembicki <paweldembicki@gmail.com>
*
* This tool is based on mktplinkfw.
* Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
* 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 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 <stdint.h>
#include <string.h>
#include <unistd.h> /* for unlink() */
#include <libgen.h>
#include <getopt.h> /* for getopt() */
#include <stdarg.h>
#include <stdbool.h>
#include <endian.h>
#include <errno.h>
#include <time.h>
#include <sys/stat.h>
#include <zlib.h> /*for crc32 */
 
#include "mkdlinkfw-lib.h"
 
extern char *progname;
 
static unsigned char jffs2_eof_mark[4] = { 0xde, 0xad, 0xc0, 0xde };
 
uint32_t jboot_timestamp(void)
{
time_t rawtime;
time(&rawtime);
return (((uint32_t) rawtime) - TIMESTAMP_MAGIC) >> 2;
}
 
uint16_t jboot_checksum(uint16_t start_val, uint16_t *data, int size)
{
uint32_t counter = start_val;
uint16_t *ptr = data;
 
while (size > 1) {
counter += *ptr;
++ptr;
while (counter >> 16)
counter = (uint16_t) counter + (counter >> 16);
size -= 2;
}
if (size > 0) {
counter += *(uint8_t *) ptr;
counter -= 0xFF;
}
while (counter >> 16)
counter = (uint16_t) counter + (counter >> 16);
return counter;
}
 
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;
}
 
int read_to_buf(const 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;
}
 
int pad_jffs2(char *buf, int currlen, int maxlen)
{
int len;
uint32_t pad_mask;
 
len = currlen;
pad_mask = (4 * 1024) | (64 * 1024); /* EOF at 4KB and at 64KB */
while ((len < maxlen) && (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;
}
 
int write_fw(const char *ofname, const 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;
}
/branches/gl-inet/tools/firmware-utils/src/mkdlinkfw-lib.h
@@ -0,0 +1,83 @@
/*
* mkdlinkfw
*
* Copyright (C) 2018 Paweł Dembicki <paweldembicki@gmail.com>
*
* This tool is based on mktplinkfw.
* Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
* 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 as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*/
 
#ifndef mkdlinkfw_lib_h
#define mkdlinkfw_lib_h
 
#define AUH_MAGIC "DLK"
#define AUH_SIZE 80
#define AUH_LVPS 0x01
#define AUH_HDR_ID 0x4842
#define AUH_HDR_VER 0x02
#define AUH_SEC_ID 0x04
#define AUH_INFO_TYPE 0x04
 
#define STAG_SIZE 16
#define STAG_ID 0x04
#define STAG_MAGIC 0x2B24
#define STAG_CMARK_FACTORY 0xFF
 
#define SCH2_SIZE 40
#define SCH2_MAGIC 0x2124
#define SCH2_VER 0x02
 
#define FLAT 0
#define JZ 1
#define GZIP 2
#define LZMA 3
 
#define RAM_ENTRY_ADDR 0x80000000
#define RAM_LOAD_ADDR 0x80000000
#define JBOOT_SIZE 0x10000
 
#define ALL_HEADERS_SIZE (AUH_SIZE + STAG_SIZE + SCH2_SIZE)
#define MAX_HEADER_COUNTER 10
#define TIMESTAMP_MAGIC 0x35016f00L
 
#define FACTORY 0
#define SYSUPGRADE 1
 
#define ALIGN(x, a) ({ typeof(a) __a = (a); (((x) + __a - 1) & ~(__a - 1)); })
 
#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)
 
struct file_info {
char *file_name; /* name of the file */
uint32_t file_size; /* length of the file */
};
 
uint32_t jboot_timestamp(void);
uint16_t jboot_checksum(uint16_t start_val, uint16_t *data, int size);
int get_file_stat(struct file_info *fdata);
int read_to_buf(const struct file_info *fdata, char *buf);
int pad_jffs2(char *buf, int currlen, int maxlen);
int write_fw(const char *ofname, const char *data, int len);
 
#endif /* mkdlinkfw_lib_h */
/branches/gl-inet/tools/firmware-utils/src/mkdlinkfw.c
@@ -0,0 +1,665 @@
/*
* mkdlinkfw
*
* Copyright (C) 2018 Paweł Dembicki <paweldembicki@gmail.com>
*
* This tool is based on mktplinkfw.
* Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
* 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 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 <stdint.h>
#include <string.h>
#include <unistd.h> /* for unlink() */
#include <libgen.h>
#include <getopt.h> /* for getopt() */
#include <stdarg.h>
#include <stdbool.h>
#include <endian.h>
#include <errno.h>
#include <sys/stat.h>
#include <zlib.h> /*for crc32 */
 
#include "mkdlinkfw-lib.h"
 
/* ARM update header 2.0
* used only in factory images to erase and flash selected area
*/
struct auh_header {
uint8_t rom_id[12]; /* 12-bit rom-id unique per router type */
uint16_t derange; /* used for scramble header */
uint16_t image_checksum; /* jboot_checksum of flashed data */
 
uint32_t space1; /* zeros */
uint32_t space2; /* zeros */
uint16_t space3; /* zerosu */
uint8_t lpvs; /* must be 0x01 */
uint8_t mbz; /* bust be 0 */
uint32_t time_stamp; /* timestamp calculated in jboot way */
 
uint32_t erase_start; /* erase start address */
uint32_t erase_length; /* erase length address */
uint32_t data_offset; /* data start address */
uint32_t data_length; /* data length address */
 
uint32_t space4; /* zeros */
uint32_t space5; /* zeros */
uint32_t space6; /* zeros */
uint32_t space7; /* zeros */
 
uint16_t header_id; /* magic 0x4842 */
uint16_t header_version; /* 0x02 for 2.0 */
uint16_t space8; /* zeros */
uint8_t section_id; /* section id */
uint8_t image_info_type; /* (?) 0x04 in factory images */
uint32_t image_info_offset; /* (?) zeros in factory images */
uint16_t family_member; /* unique per router type */
uint16_t header_checksum; /* negated jboot_checksum of header data */
};
 
struct stag_header { /* used only of sch2 wrapped kernel data */
uint8_t cmark; /* in factory 0xFF ,in sysuograde must be the same as id */
uint8_t id; /* 0x04 */
uint16_t magic; /* magic 0x2B24 */
uint32_t time_stamp; /* timestamp calculated in jboot way */
uint32_t image_length; /* lentgh of kernel + sch2 header */
uint16_t image_checksum; /* negated jboot_checksum of sch2 + kernel */
uint16_t tag_checksum; /* negated jboot_checksum of stag header data */
};
 
struct sch2_header { /* used only in kernel partitions */
uint16_t magic; /* magic 0x2124 */
uint8_t cp_type; /* 0x00 for flat, 0x01 for jz, 0x02 for gzip, 0x03 for lzma */
uint8_t version; /* 0x02 for sch2 */
uint32_t ram_addr; /* ram entry address */
uint32_t image_len; /* kernel image length */
uint32_t image_crc32; /* kernel image crc */
uint32_t start_addr; /* ram start address */
uint32_t rootfs_addr; /* rootfs flash address */
uint32_t rootfs_len; /* rootfls length */
uint32_t rootfs_crc32; /* rootfs crc32 */
uint32_t header_crc32; /* sch2 header crc32, durring calculation this area is replaced by zero */
uint16_t header_length; /* sch2 header length: 0x28 */
uint16_t cmd_line_length; /* cmd line length, known zeros */
};
 
/* globals */
static struct file_info inspect_info;
struct file_info kernel_info;
struct file_info rootfs_info;
struct file_info image_info;
 
char *ofname;
char *progname;
uint32_t firmware_size;
uint16_t family_member;
char *rom_id[12] = { 0 };
 
char image_type;
int add_jffs2_eof;
 
static void usage(int status)
{
fprintf(stderr, "Usage: %s [OPTIONS...]\n", progname);
fprintf(stderr,
"\n"
"Options:\n"
" -i <file> inspect given firmware file <file>\n"
" -f set family member id (hexval prefixed with 0x)\n"
" -F <file> read image and convert it to FACTORY\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"
" -s <size> set firmware partition size\n"
" -m <version> set rom id to <version> (12-bit string val: \"DLK*********\")\n"
" -h show this screen\n");
 
exit(status);
}
 
void print_auh_header(struct auh_header *printed_header)
{
printf("\trom_id: %s\n"
"\tderange: 0x%04X\n"
"\timage_checksum: 0x%04X\n"
"\tspace1: 0x%08X\n"
"\tspace2: 0x%08X\n"
"\tspace3: 0x%04X\n"
"\tlpvs: 0x%02X\n"
"\tmbz: 0x%02X\n"
"\ttime_stamp: 0x%08X\n"
"\terase_start: 0x%08X\n"
"\terase_length: 0x%08X\n"
"\tdata_offset: 0x%08X\n"
"\tdata_length: 0x%08X\n"
"\tspace4: 0x%08X\n"
"\tspace5: 0x%08X\n"
"\tspace6: 0x%08X\n"
"\tspace7: 0x%08X\n"
"\theader_id: 0x%04X\n"
"\theader_version: 0x%02X\n"
"\tspace8: 0x%04X\n"
"\tsection_id: 0x%02X\n"
"\timage_info_type: 0x%02X\n"
"\timage_info_offset 0x%08X\n"
"\tfamily_member: 0x%04X\n"
"\theader_checksum: 0x%04X\n",
printed_header->rom_id,
printed_header->derange,
printed_header->image_checksum,
printed_header->space1,
printed_header->space2,
printed_header->space3,
printed_header->lpvs,
printed_header->mbz,
printed_header->time_stamp,
printed_header->erase_start,
printed_header->erase_length,
printed_header->data_offset,
printed_header->data_length,
printed_header->space4,
printed_header->space5,
printed_header->space6,
printed_header->space7,
printed_header->header_id,
printed_header->header_version,
printed_header->space8,
printed_header->section_id,
printed_header->image_info_type,
printed_header->image_info_offset,
printed_header->family_member, printed_header->header_checksum);
}
 
void print_stag_header(struct stag_header *printed_header)
{
printf("\tcmark: 0x%02X\n"
"\tid: 0x%02X\n"
"\tmagic: 0x%04X\n"
"\ttime_stamp: 0x%08X\n"
"\timage_length: 0x%04X\n"
"\timage_checksum: 0x%04X\n"
"\ttag_checksum: 0x%04X\n",
printed_header->cmark,
printed_header->id,
printed_header->magic,
printed_header->time_stamp,
printed_header->image_length,
printed_header->image_checksum, printed_header->tag_checksum);
}
 
void print_sch2_header(struct sch2_header *printed_header)
{
printf("\tmagic: 0x%04X\n"
"\tcp_type: 0x%02X\n"
"\tversion: 0x%02X\n"
"\tram_addr: 0x%08X\n"
"\timage_len: 0x%08X\n"
"\timage_crc32: 0x%08X\n"
"\tstart_addr: 0x%08X\n"
"\trootfs_addr: 0x%08X\n"
"\trootfs_len: 0x%08X\n"
"\trootfs_crc32: 0x%08X\n"
"\theader_crc32: 0x%08X\n"
"\theader_length: 0x%04X\n"
"\tcmd_line_length: 0x%04X\n",
printed_header->magic,
printed_header->cp_type,
printed_header->version,
printed_header->ram_addr,
printed_header->image_len,
printed_header->image_crc32,
printed_header->start_addr,
printed_header->rootfs_addr,
printed_header->rootfs_len,
printed_header->rootfs_crc32,
printed_header->header_crc32,
printed_header->header_length, printed_header->cmd_line_length);
}
 
static int find_auh_headers(char *buf)
{
char *tmp_buf = buf;
struct auh_header *tmp_header[MAX_HEADER_COUNTER];
int header_counter = 0;
 
int ret = EXIT_FAILURE;
 
while (tmp_buf - buf <= inspect_info.file_size - AUH_SIZE) {
if (!memcmp(tmp_buf, AUH_MAGIC, 3)) {
if (((struct auh_header *)tmp_buf)->header_checksum ==
(uint16_t) ~jboot_checksum(0, (uint16_t *) tmp_buf,
AUH_SIZE - 2)) {
uint16_t checksum = 0;
printf("Find proper AUH header at: 0x%lX!\n",
tmp_buf - buf);
tmp_header[header_counter] =
(struct auh_header *)tmp_buf;
checksum =
jboot_checksum(0, (uint16_t *) ((char *)
tmp_header
[header_counter]
+ AUH_SIZE),
tmp_header
[header_counter]->data_length);
if (tmp_header[header_counter]->image_checksum
== checksum)
printf("Image checksum ok.\n");
else
ERR("Image checksum incorrect! Stored: 0x%X Calculated: 0x%X\n", tmp_header[header_counter]->image_checksum, checksum);
header_counter++;
if (header_counter > MAX_HEADER_COUNTER)
break;
}
}
tmp_buf++;
}
 
if (header_counter == 0)
ERR("Can't find proper AUH header!\n");
else if (header_counter > MAX_HEADER_COUNTER)
ERR("To many AUH headers!\n");
else {
for (int i = 0; i < header_counter; i++) {
printf("AUH %d:\n", i);
print_auh_header(tmp_header[i]);
}
 
ret = EXIT_SUCCESS;
}
 
return ret;
}
 
static int check_stag_header(char *buf, struct stag_header *header)
{
 
int ret = EXIT_FAILURE;
 
uint8_t cmark_tmp = header->cmark;
header->cmark = header->id;
 
if (header->tag_checksum ==
(uint16_t) ~jboot_checksum(0, (uint16_t *) header,
STAG_SIZE - 2)) {
uint16_t checksum = 0;
printf("Find proper STAG header at: 0x%lX!\n",
(char *)header - buf);
checksum =
jboot_checksum(0, (uint16_t *) ((char *)header + STAG_SIZE),
header->image_length);
if (header->image_checksum == checksum) {
printf("Image checksum ok.\n");
header->cmark = cmark_tmp;
print_stag_header(header);
ret = EXIT_SUCCESS;
} else
ERR("Image checksum incorrect! Stored: 0x%X Calculated: 0x%X\n", header->image_checksum, checksum);
} else
ERR("STAG header checksum incorrect!");
 
header->cmark = cmark_tmp;
return ret;
}
 
static int check_sch2_header(char *buf, struct sch2_header *header)
{
 
int ret = EXIT_FAILURE;
 
uint32_t crc32_tmp = header->header_crc32;
header->header_crc32 = 0;
 
if (crc32_tmp == crc32(0, (uint8_t *) header, header->header_length)) {
uint32_t crc32_val;
printf("Find proper SCH2 header at: 0x%lX!\n",
(char *)header - buf);
 
crc32_val =
crc32(0, (uint8_t *) header + header->header_length,
header->image_len);
if (header->image_crc32 == crc32_val) {
printf("Kernel checksum ok.\n");
 
header->header_crc32 = crc32_tmp;
print_sch2_header(header);
ret = EXIT_SUCCESS;
} else
ERR("Kernel checksum incorrect! Stored: 0x%X Calculated: 0x%X\n", header->image_crc32, crc32_val);
 
} else
ERR("SCH2 header checksum incorrect!");
 
header->header_crc32 = crc32_tmp;
return ret;
}
 
static int inspect_fw(void)
{
char *buf;
struct stag_header *stag_header_kernel;
struct sch2_header *sch2_header_kernel;
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;
 
ret = find_auh_headers(buf);
if (ret)
goto out_free_buf;
 
stag_header_kernel = (struct stag_header *)(buf + AUH_SIZE);
 
ret = check_stag_header(buf, stag_header_kernel);
if (ret)
goto out_free_buf;
 
sch2_header_kernel = (struct sch2_header *)(buf + AUH_SIZE + STAG_SIZE);
 
ret = check_sch2_header(buf, sch2_header_kernel);
if (ret)
goto out_free_buf;
 
out_free_buf:
free(buf);
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;
}
 
return 0;
}
 
int fill_sch2(struct sch2_header *header, char *kernel_ptr, char *rootfs_ptr)
{
 
header->magic = SCH2_MAGIC;
header->cp_type = LZMA;
header->version = SCH2_VER;
header->ram_addr = RAM_LOAD_ADDR;
header->image_len = kernel_info.file_size;
header->image_crc32 = crc32(0, (uint8_t *) kernel_ptr, kernel_info.file_size);
header->start_addr = RAM_ENTRY_ADDR;
header->rootfs_addr =
JBOOT_SIZE + STAG_SIZE + SCH2_SIZE + kernel_info.file_size;
header->rootfs_len = rootfs_info.file_size;
header->rootfs_crc32 = crc32(0, (uint8_t *) rootfs_ptr, rootfs_info.file_size);
header->header_crc32 = 0;
header->header_length = SCH2_SIZE;
header->cmd_line_length = 0;
 
header->header_crc32 = crc32(0, (uint8_t *) header, header->header_length);
 
return EXIT_SUCCESS;
}
 
int fill_stag(struct stag_header *header, uint32_t length)
{
header->cmark = STAG_ID;
header->id = STAG_ID;
header->magic = STAG_MAGIC;
header->time_stamp = jboot_timestamp();
header->image_length = length + SCH2_SIZE;
header->image_checksum =
jboot_checksum(0, (uint16_t *) ((char *)header + STAG_SIZE),
header->image_length);
header->tag_checksum =
~jboot_checksum(0, (uint16_t *) header, STAG_SIZE - 2);
 
if (image_type == FACTORY)
header->cmark = STAG_CMARK_FACTORY;
 
return EXIT_SUCCESS;
};
 
int fill_auh(struct auh_header *header, uint32_t length)
{
memcpy(header->rom_id, rom_id, 12);
header->derange = 0;
header->image_checksum =
jboot_checksum(0, (uint16_t *) ((char *)header + AUH_SIZE), length);
header->space1 = 0;
header->space2 = 0;
header->space3 = 0;
header->lpvs = AUH_LVPS;
header->mbz = 0;
header->time_stamp = jboot_timestamp();
header->erase_start = JBOOT_SIZE;
header->erase_length = firmware_size;
header->data_offset = JBOOT_SIZE;
header->data_length = length;
header->space4 = 0;
header->space5 = 0;
header->space6 = 0;
header->space7 = 0;
header->header_id = AUH_HDR_ID;
header->header_version = AUH_HDR_VER;
header->space8 = 0;
header->section_id = AUH_SEC_ID;
header->image_info_type = AUH_INFO_TYPE;
header->image_info_offset = 0;
header->family_member = family_member;
header->header_checksum =
~jboot_checksum(0, (uint16_t *) header, AUH_SIZE - 2);
 
return EXIT_SUCCESS;
}
 
int build_fw(void)
{
char *buf;
char *kernel_ptr;
char *rootfs_ptr;
int ret = EXIT_FAILURE;
int writelen;
 
struct stag_header *stag_header_kernel;
struct sch2_header *sch2_header_kernel;
 
if (!kernel_info.file_name | !rootfs_info.file_name)
goto out;
 
ret = get_file_stat(&kernel_info);
if (ret)
goto out;
ret = get_file_stat(&rootfs_info);
if (ret)
goto out;
 
buf = malloc(firmware_size);
if (!buf) {
ERR("no memory for buffer\n");
goto out;
}
 
if (rootfs_info.file_size + kernel_info.file_size + ALL_HEADERS_SIZE >
firmware_size) {
ERR("data is bigger than firmware_size!\n");
goto out;
}
 
memset(buf, 0xff, firmware_size);
 
stag_header_kernel = (struct stag_header *)buf;
 
sch2_header_kernel =
(struct sch2_header *)((char *)stag_header_kernel + STAG_SIZE);
kernel_ptr = (char *)sch2_header_kernel + SCH2_SIZE;
 
ret = read_to_buf(&kernel_info, kernel_ptr);
if (ret)
goto out_free_buf;
 
rootfs_ptr = kernel_ptr + kernel_info.file_size;
 
ret = read_to_buf(&rootfs_info, rootfs_ptr);
if (ret)
goto out_free_buf;
 
writelen = rootfs_ptr + rootfs_info.file_size - buf;
 
fill_sch2(sch2_header_kernel, kernel_ptr, rootfs_ptr);
fill_stag(stag_header_kernel, kernel_info.file_size);
 
ret = write_fw(ofname, buf, writelen);
if (ret)
goto out_free_buf;
 
ret = EXIT_SUCCESS;
 
out_free_buf:
free(buf);
out:
return ret;
}
 
int wrap_fw(void)
{
char *buf;
char *image_ptr;
int ret = EXIT_FAILURE;
int writelen;
 
struct auh_header *auh_header_kernel;
 
if (!image_info.file_name)
goto out;
 
ret = get_file_stat(&image_info);
if (ret)
goto out;
 
buf = malloc(firmware_size);
if (!buf) {
ERR("no memory for buffer\n");
goto out;
}
 
if (image_info.file_size + AUH_SIZE >
firmware_size) {
ERR("data is bigger than firmware_size!\n");
goto out;
}
if (!family_member) {
ERR("No family_member!\n");
goto out;
}
if (!(rom_id[0])) {
ERR("No rom_id!\n");
goto out;
}
memset(buf, 0xff, firmware_size);
 
image_ptr = (char *)(buf + AUH_SIZE);
 
ret = read_to_buf(&image_info, image_ptr);
if (ret)
goto out_free_buf;
 
writelen = image_ptr + image_info.file_size - buf;
 
auh_header_kernel = (struct auh_header *)buf;
fill_auh(auh_header_kernel, writelen - AUH_SIZE);
 
ret = write_fw(ofname, buf, writelen);
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]);
image_type = SYSUPGRADE;
family_member = 0;
firmware_size = 0;
 
while (1) {
int c;
 
c = getopt(argc, argv, "f:F:i:hk:m:o:r:s:");
if (c == -1)
break;
 
switch (c) {
case 'f':
sscanf(optarg, "0x%hx", &family_member);
break;
case 'F':
image_info.file_name = optarg;
image_type = FACTORY;
break;
case 'i':
inspect_info.file_name = optarg;
break;
case 'k':
kernel_info.file_name = optarg;
break;
case 'm':
if (strlen(optarg) == 12)
memcpy(rom_id, optarg, 12);
break;
case 'r':
rootfs_info.file_name = optarg;
break;
case 'o':
ofname = optarg;
break;
case 's':
sscanf(optarg, "0x%x", &firmware_size);
break;
default:
usage(EXIT_FAILURE);
break;
}
}
 
ret = check_options();
if (ret)
goto out;
 
if (!inspect_info.file_name) {
if (image_type == FACTORY)
ret = wrap_fw();
else
ret = build_fw();
}
else
ret = inspect_fw();
 
out:
return ret;
 
}
/branches/gl-inet/tools/firmware-utils/src/mkdniimg.c
@@ -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 ": %s\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;
}
/branches/gl-inet/tools/firmware-utils/src/mkedimaximg.c
@@ -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;
}
/branches/gl-inet/tools/firmware-utils/src/mkfwimage.c
@@ -0,0 +1,471 @@
/*
* 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= 0x00760000,
},
{
.name = "UBDEV01",
.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:"
 
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 (*p->name && (strcmp(p->name, board_name) != 0))
p++;
if (!*p->name) {
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)) == (u_int32_t)-1) 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;
}
/branches/gl-inet/tools/firmware-utils/src/mkfwimage2.c
@@ -0,0 +1,451 @@
/*
* 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-OpenWrt.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;
}
 
#ifndef STRINGIFY
#define STRINGIFY2(X) #X
#define STRINGIFY(X) STRINGIFY2(X)
#endif
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]:%"STRINGIFY(PATH_MAX)"s",
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;
}
/branches/gl-inet/tools/firmware-utils/src/mkheader_gemtek.c
@@ -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);
}
/branches/gl-inet/tools/firmware-utils/src/mkhilinkfw.c
@@ -0,0 +1,323 @@
/*
* 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 <arpa/inet.h>
#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++;
}
}
/branches/gl-inet/tools/firmware-utils/src/mkmerakifw-old.c
@@ -0,0 +1,369 @@
/*
* Copyright (C) 2015 Thomas Hebb <tommyhebb@gmail.com>
* Copyright (C) 2016 Christian Lamparter <chunkeey@googlemail.com>
*
* The format of the header this tool generates was first documented by
* Chris Blake <chrisrblake93 (at) gmail.com> in a shell script of the
* same purpose. I have created this reimplementation at his request. The
* original script can be found at:
* <https://github.com/riptidewave93/meraki-partbuilder>
*
* Support for the old header format, which is used by the Cisco Z1 AP
* has been reverse engineered from the nandloader's nand_load_bk function.
* The original code is part of Cisco's GPL code and can be found at:
* <https://github.com/riptidewave93/meraki-linux>
*
* 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 <stdbool.h>
#include <string.h>
#include <libgen.h>
#include <endian.h>
#include <getopt.h>
#include <errno.h>
#include <arpa/inet.h>
 
#define PADDING_BYTE 0xff
 
#define HDR_LENGTH 0x00000020
#define HDR_OFF_MAGIC1 0
#define HDR_OFF_LOAD_ADDR 4
#define HDR_OFF_IMAGELEN 8
#define HDR_OFF_ENTRY 12
#define HDR_OFF_CHECKSUM 16
#define HDR_OFF_FILLER0 20
#define HDR_OFF_FILLER1 24
#define HDR_OFF_FILLER2 28
 
struct board_info {
char *id;
char *description;
uint32_t magic;
uint32_t imagelen;
uint32_t load_addr;
uint32_t entry;
};
 
/*
* Globals
*/
static char *progname;
static bool strip_padding;
 
static char *board_id;
static const struct board_info *board;
 
static const struct board_info boards[] = {
{
.id = "z1",
.description = "Meraki Z1 Access Point",
.magic = 0x4d495053,
.imagelen = 0x007e0000,
.load_addr = 0x80060000,
.entry = 0x80060000
}, {
/* 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 const struct board_info *find_board(const char *id)
{
const struct board_info *ret;
const 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;
const 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 kernel image from the file <file>\n"
" -o <file> write output to the file <file>\n"
" -s strip padding from the end of the image\n"
" -h show this screen\n"
);
 
fprintf(stream, "\nBoards:\n");
for (board = boards; board->id != NULL; board++)
fprintf(stream, " %-16s%s\n", board->id, board->description);
 
exit(status);
}
 
static void writel(unsigned char *buf, size_t offset, uint32_t value)
{
value = htonl(value);
memcpy(buf + offset, &value, sizeof(uint32_t));
}
 
static const uint32_t crc32_table[] = {
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 inline uint32_t crc32_accumulate_8(const uint32_t crc, const uint8_t ch)
{
return crc32_table[(crc ^ ch) & 0xff] ^ (crc >> 8);
}
 
static void crc32_csum(uint8_t *buf, const size_t len)
{
uint32_t crc;
size_t i;
 
crc = ~0;
for (i = 0; i < len; i += 4) {
crc = crc32_accumulate_8(crc, buf[i + 3]);
crc = crc32_accumulate_8(crc, buf[i + 2]);
crc = crc32_accumulate_8(crc, buf[i + 1]);
crc = crc32_accumulate_8(crc, buf[i]);
}
crc = ~crc;
 
writel(buf, HDR_OFF_CHECKSUM, crc);
}
 
 
static int meraki_build_hdr(const struct board_info *board, const size_t klen,
FILE *out, FILE *in)
{
unsigned char *kernel;
unsigned char *buf;
size_t buflen;
size_t kspace;
 
size_t rc;
buflen = board->imagelen;
kspace = buflen - HDR_LENGTH;
 
if (klen > kspace) {
ERR("kernel file is too big - max size: 0x%08lX\n", kspace);
return EXIT_FAILURE;
}
 
/* If requested, resize buffer to remove padding */
if (strip_padding)
buflen = klen + HDR_LENGTH;
 
/* Allocate and initialize buffer for final image */
buf = malloc(buflen);
if (buf == NULL) {
ERRS("no memory for buffer: %s\n");
return EXIT_FAILURE;
}
memset(buf, PADDING_BYTE, buflen);
 
/* Load kernel */
kernel = buf + HDR_LENGTH;
fread(kernel, klen, 1, in);
 
/* Write magic values and filler */
writel(buf, HDR_OFF_MAGIC1, board->magic);
writel(buf, HDR_OFF_FILLER0, 0);
writel(buf, HDR_OFF_FILLER1, 0);
writel(buf, HDR_OFF_FILLER2, 0);
 
/* Write load and kernel entry point address */
writel(buf, HDR_OFF_LOAD_ADDR, board->load_addr);
writel(buf, HDR_OFF_ENTRY, board->entry);
 
/* Write header and image length */
writel(buf, HDR_OFF_IMAGELEN, klen);
 
/* this gets replaced later, after the checksum has been calculated */
writel(buf, HDR_OFF_CHECKSUM, 0);
 
/* Write checksum */
crc32_csum(buf, klen + HDR_LENGTH);
 
rc = fwrite(buf, buflen, 1, out);
 
free(buf);
 
return rc == 1 ? EXIT_SUCCESS : EXIT_FAILURE;
}
 
int main(int argc, char *argv[])
{
int ret = EXIT_FAILURE;
char *ofname = NULL, *ifname = NULL;
FILE *out, *in;
size_t klen;
 
progname = basename(argv[0]);
 
while (1) {
int c;
 
c = getopt(argc, argv, "B:i:o:sh");
if (c == -1)
break;
 
switch (c) {
case 'B':
board_id = optarg;
break;
case 'i':
ifname = optarg;
break;
case 'o':
ofname = optarg;
break;
case 's':
strip_padding = true;
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;
}
 
in = fopen(ifname, "r");
if (in == NULL) {
ERRS("could not open \"%s\" for reading: %s", ifname);
goto err;
}
 
/* Get kernel length */
fseek(in, 0, SEEK_END);
klen = ftell(in);
rewind(in);
 
out = fopen(ofname, "w");
if (out == NULL) {
ERRS("could not open \"%s\" for writing: %s", ofname);
goto err_close_in;
}
 
ret = meraki_build_hdr(board, klen, out, in);
fclose(out);
 
err_close_in:
fclose(in);
 
err:
return ret;
}
/branches/gl-inet/tools/firmware-utils/src/mkmerakifw.c
@@ -0,0 +1,320 @@
/*
* Copyright (C) 2015 Thomas Hebb <tommyhebb@gmail.com>
*
* The format of the header this tool generates was first documented by
* Chris Blake <chrisrblake93 (at) gmail.com> in a shell script of the
* same purpose. I have created this reimplementation at his request. The
* original script can be found at:
* <https://github.com/riptidewave93/meraki-partbuilder>
*
* 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 <stdbool.h>
#include <string.h>
#include <libgen.h>
#include <getopt.h>
#include <errno.h>
#include <arpa/inet.h>
 
#include "sha1.h"
 
#define PADDING_BYTE 0xff
 
#define HDR_LENGTH 0x00000400
#define HDR_OFF_MAGIC1 0
#define HDR_OFF_HDRLEN 4
#define HDR_OFF_IMAGELEN 8
#define HDR_OFF_CHECKSUM 12
#define HDR_OFF_MAGIC2 32
#define HDR_OFF_MAGIC3 36
#define HDR_OFF_STATICHASH 40
#define HDR_OFF_KERNEL_OFFSET 40
#define HDR_OFF_RAMDISK_OFFSET 44
#define HDR_OFF_FDT_OFFSET 48
#define HDR_OFF_UNKNOWN_OFFSET 52
 
struct board_info {
uint32_t magic1;
uint32_t magic2;
uint32_t magic3;
uint32_t imagelen;
union {
unsigned char statichash[20];
struct {
uint32_t kernel_offset;
uint32_t ramdisk_offset;
uint32_t fdt_offset;
uint32_t unknown_offset;
} mx60;
} u;
char *id;
char *description;
};
 
/*
* Globals
*/
static char *progname;
 
static char *board_id;
static const struct board_info *board;
 
static const struct board_info boards[] = {
{
.id = "mr18",
.description = "Meraki MR18 Access Point",
.magic1 = 0x8e73ed8a,
.magic2 = 0x8e73ed8a,
.imagelen = 0x00800000,
.u.statichash = {0xda, 0x39, 0xa3, 0xee, 0x5e,
0x6b, 0x4b, 0x0d, 0x32, 0x55,
0xbf, 0xef, 0x95, 0x60, 0x18,
0x90, 0xaf, 0xd8, 0x07, 0x09},
}, {
.id = "mr24",
.description = "Meraki MR24 Access Point",
.magic1 = 0x8e73ed8a,
.magic2 = 0x8e73ed8a,
.imagelen = 0x00800000,
.u.statichash = {0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff},
}, {
.id = "mx60",
.description = "Meraki MX60/MX60W Security Appliance",
.magic1 = 0x8e73ed8a,
.magic2 = 0xa1f0beef, /* Enables use of load addr in statichash */
.magic3 = 0x00060001, /* This goes along with magic2 */
.imagelen = 0x3fd00000,
/* The static hash below does the following:
* 1st Row: Kernel Offset
* 2nd Row: Ramdisk Offset
* 3rd Row: FDT Offset
* 4th Row: ? Unused/Unknown ?
* 5th Row: ? Unused/Unknown ?
*/
.u.mx60 = {
.kernel_offset = 0x10000,
.ramdisk_offset = 0x3FFC00,
.fdt_offset = 0x0400,
.unknown_offset = 0x0400,
},
}, {
/* 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 const struct board_info *find_board(const char *id)
{
const struct board_info *ret;
const 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;
const 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 kernel image from the file <file>\n"
" -o <file> write output to the file <file>\n"
" -s strip padding from the end of the image\n"
" -h show this screen\n"
);
 
fprintf(stream, "\nBoards:\n");
for (board = boards; board->id != NULL; board++)
fprintf(stream, " %-16s%s\n", board->id, board->description);
 
exit(status);
}
 
void writel(unsigned char *buf, size_t offset, uint32_t value)
{
value = htonl(value);
memcpy(buf + offset, &value, sizeof(uint32_t));
}
 
int main(int argc, char *argv[])
{
int ret = EXIT_FAILURE;
long klen;
size_t kspace;
unsigned char *kernel;
size_t buflen;
unsigned char *buf;
bool strip_padding = false;
char *ofname = NULL, *ifname = NULL;
FILE *out, *in;
 
progname = basename(argv[0]);
 
while (1) {
int c;
 
c = getopt(argc, argv, "B:i:o:sh");
if (c == -1)
break;
 
switch (c) {
case 'B':
board_id = optarg;
break;
case 'i':
ifname = optarg;
break;
case 'o':
ofname = optarg;
break;
case 's':
strip_padding = true;
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;
}
 
in = fopen(ifname, "r");
if (in == NULL) {
ERRS("could not open \"%s\" for reading: %s", ifname);
goto err;
}
 
buflen = board->imagelen;
kspace = buflen - HDR_LENGTH;
 
/* Get kernel length */
fseek(in, 0, SEEK_END);
klen = ftell(in);
rewind(in);
 
if (klen > kspace) {
ERR("file \"%s\" is too big - max size: 0x%08lX\n",
ifname, kspace);
goto err_close_in;
}
 
/* If requested, resize buffer to remove padding */
if (strip_padding)
buflen = klen + HDR_LENGTH;
 
/* Allocate and initialize buffer for final image */
buf = malloc(buflen);
if (buf == NULL) {
ERRS("no memory for buffer: %s\n");
goto err_close_in;
}
memset(buf, PADDING_BYTE, buflen);
 
/* Load kernel */
kernel = buf + HDR_LENGTH;
fread(kernel, klen, 1, in);
 
/* Write magic values */
writel(buf, HDR_OFF_MAGIC1, board->magic1);
writel(buf, HDR_OFF_MAGIC2, board->magic2);
writel(buf, HDR_OFF_MAGIC3, board->magic3);
 
/* Write header and image length */
writel(buf, HDR_OFF_HDRLEN, HDR_LENGTH);
writel(buf, HDR_OFF_IMAGELEN, klen);
 
/* Write checksum and static hash */
sha1_csum(kernel, klen, buf + HDR_OFF_CHECKSUM);
 
switch (board->magic2) {
case 0xa1f0beef:
writel(buf, HDR_OFF_KERNEL_OFFSET, board->u.mx60.kernel_offset);
writel(buf, HDR_OFF_RAMDISK_OFFSET, board->u.mx60.ramdisk_offset);
writel(buf, HDR_OFF_FDT_OFFSET, board->u.mx60.fdt_offset),
writel(buf, HDR_OFF_UNKNOWN_OFFSET, board->u.mx60.unknown_offset);
break;
 
case 0x8e73ed8a:
memcpy(buf + HDR_OFF_STATICHASH, board->u.statichash, 20);
break;
}
 
/* Save finished image */
out = fopen(ofname, "w");
if (out == NULL) {
ERRS("could not open \"%s\" for writing: %s", ofname);
goto err_free;
}
fwrite(buf, buflen, 1, out);
 
ret = EXIT_SUCCESS;
 
fclose(out);
 
err_free:
free(buf);
 
err_close_in:
fclose(in);
 
err:
return ret;
}
/branches/gl-inet/tools/firmware-utils/src/mkmylofw.c
@@ -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;
}
/branches/gl-inet/tools/firmware-utils/src/mkplanexfw.c
@@ -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 ": %s\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;
}
 
/branches/gl-inet/tools/firmware-utils/src/mkporayfw.c
@@ -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("(== OpenWrt default)\n");
} else {
printf("(OpenWrt default: 0x%08x)\n", defval);
}
}
 
static inline void inspect_fw_phexexp(char *label,
uint32_t val, uint32_t expval)
{
printf("%-23s: 0x%08x ", label, val);
 
if (val == expval) {
printf("(ok)\n");
} else {
printf("(expected: 0x%08x)\n", expval);
}
}
 
static inline void inspect_fw_phexdec(char *label, uint32_t val)
{
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;
}
/branches/gl-inet/tools/firmware-utils/src/mkrtn56uimg.c
@@ -0,0 +1,293 @@
/*
*
* 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 <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;
}
 
/branches/gl-inet/tools/firmware-utils/src/mksenaofw.c
@@ -0,0 +1,420 @@
/*
*
* 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 (mode == NONE) {
fprintf(stderr, "A mode must be defined\n");
usage(progname, EXIT_FAILURE);
}
 
if (input_file == NULL || output_file == NULL) {
fprintf(stderr, "Input and output files must be defined\n");
usage(progname, EXIT_FAILURE);
}
 
if (mode == DECODE) {
if (decode_image(input_file, output_file) < 0)
return EXIT_FAILURE;
 
return EXIT_SUCCESS;
}
 
if (header.firmware_type == 0) {
fprintf(stderr, "Firmware type must be defined\n");
usage(progname, EXIT_FAILURE);
}
 
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);
}
 
if (encode_image(input_file, output_file, &header, pad ? block_size : 0) < 0)
return EXIT_FAILURE;
 
return EXIT_SUCCESS;
}
/branches/gl-inet/tools/firmware-utils/src/mktitanimg.c
@@ -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);
}
/branches/gl-inet/tools/firmware-utils/src/mktitanimg.h
@@ -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 */
/branches/gl-inet/tools/firmware-utils/src/mktplinkfw-lib.c
@@ -0,0 +1,265 @@
/*
* 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 <stdbool.h>
#include <endian.h>
#include <errno.h>
#include <sys/stat.h>
 
#include <arpa/inet.h>
#include <netinet/in.h>
 
#include "mktplinkfw-lib.h"
#include "md5.h"
 
extern char *ofname;
extern char *progname;
extern uint32_t kernel_len;
extern struct file_info kernel_info;
extern struct file_info rootfs_info;
extern struct flash_layout *layout;
extern uint32_t rootfs_ofs;
extern uint32_t rootfs_align;
extern int combined;
extern int strip_padding;
extern int add_jffs2_eof;
 
static unsigned char jffs2_eof_mark[4] = {0xde, 0xad, 0xc0, 0xde};
 
void fill_header(char *buf, int len);
 
struct flash_layout *find_layout(struct flash_layout *layouts, const 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;
}
 
void get_md5(const char *data, int size, uint8_t *md5)
{
MD5_CTX ctx;
 
MD5_Init(&ctx);
MD5_Update(&ctx, data, size);
MD5_Final(md5, &ctx);
}
 
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;
}
 
int read_to_buf(const 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 pad_jffs2(char *buf, int currlen, int maxlen)
{
int len;
uint32_t pad_mask;
 
len = currlen;
pad_mask = (4 * 1024) | (64 * 1024); /* EOF at 4KB and at 64KB */
while ((len < maxlen) && (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;
}
 
int write_fw(const char *ofname, const 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;
}
 
/* Helper functions to inspect_fw() representing different output formats */
inline void inspect_fw_pstr(const char *label, const char *str)
{
printf("%-23s: %s\n", label, str);
}
 
inline void inspect_fw_phex(const char *label, uint32_t val)
{
printf("%-23s: 0x%08x\n", label, val);
}
 
inline void inspect_fw_phexdec(const char *label, uint32_t val)
{
printf("%-23s: 0x%08x / %8u bytes\n", label, val, val);
}
 
inline void inspect_fw_pmd5sum(const char *label, const uint8_t *val, const char *text)
{
int i;
 
printf("%-23s:", label);
for (i=0; i<MD5SUM_LEN; i++)
printf(" %02x", val[i]);
printf(" %s\n", text);
}
 
// header_size = sizeof(struct fw_header)
int build_fw(size_t header_size)
{
int buflen;
char *buf;
char *p;
int ret = EXIT_FAILURE;
int writelen = 0;
 
writelen = header_size + kernel_len;
 
if (combined)
buflen = writelen;
else
buflen = layout->fw_max_len;
 
buf = malloc(buflen);
if (!buf) {
ERR("no memory for buffer\n");
goto out;
}
 
memset(buf, 0xff, buflen);
p = buf + header_size;
ret = read_to_buf(&kernel_info, p);
if (ret)
goto out_free_buf;
 
if (!combined) {
p = buf + rootfs_ofs;
 
ret = read_to_buf(&rootfs_info, p);
if (ret)
goto out_free_buf;
 
writelen = rootfs_ofs + rootfs_info.file_size;
 
if (add_jffs2_eof)
writelen = pad_jffs2(buf, writelen, layout->fw_max_len);
}
 
if (!strip_padding)
writelen = buflen;
 
fill_header(buf, writelen);
ret = write_fw(ofname, buf, writelen);
if (ret)
goto out_free_buf;
 
ret = EXIT_SUCCESS;
 
out_free_buf:
free(buf);
out:
return ret;
}
/branches/gl-inet/tools/firmware-utils/src/mktplinkfw-lib.h
@@ -0,0 +1,68 @@
/*
* 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.
*
*/
 
 
#ifndef mktplinkfw_lib_h
#define mktplinkfw_lib_h
 
#define ALIGN(x,a) ({ typeof(a) __a = (a); (((x) + __a - 1) & ~(__a - 1)); })
#define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0]))
 
#define MD5SUM_LEN 16
 
/*
* 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)
 
 
struct file_info {
char *file_name; /* name of the file */
uint32_t file_size; /* length of the file */
};
 
struct flash_layout {
char *id;
uint32_t fw_max_len;
uint32_t kernel_la;
uint32_t kernel_ep;
uint32_t rootfs_ofs;
};
 
struct flash_layout *find_layout(struct flash_layout *layouts, const char *id);
void get_md5(const char *data, int size, uint8_t *md5);
int get_file_stat(struct file_info *fdata);
int read_to_buf(const struct file_info *fdata, char *buf);
int write_fw(const char *ofname, const char *data, int len);
inline void inspect_fw_pstr(const char *label, const char *str);
inline void inspect_fw_phex(const char *label, uint32_t val);
inline void inspect_fw_phexdec(const char *label, uint32_t val);
inline void inspect_fw_pmd5sum(const char *label, const uint8_t *val, const char *text);
int build_fw(size_t header_size);
 
#endif /* mktplinkfw_lib_h */
/branches/gl-inet/tools/firmware-utils/src/mktplinkfw.c
@@ -0,0 +1,633 @@
/*
* 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 <stdbool.h>
#include <endian.h>
#include <errno.h>
#include <sys/stat.h>
 
#include <arpa/inet.h>
#include <netinet/in.h>
 
#include "md5.h"
#include "mktplinkfw-lib.h"
 
#define HEADER_VERSION_V1 0x01000000
#define HEADER_VERSION_V2 0x02000000
 
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 region_code; /* region code */
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[130];
char region_str1[32];
char region_str2[32];
uint8_t pad2[160];
} __attribute__ ((packed));
 
struct fw_region {
char name[4];
uint32_t code;
};
 
 
/*
* Globals
*/
char *ofname;
char *progname;
static char *vendor = "TP-LINK Technologies";
static char *version = "ver. 1.0";
static char *fw_ver = "0.0.0";
static uint32_t hdr_ver = HEADER_VERSION_V1;
 
static char *layout_id;
struct flash_layout *layout;
static char *opt_hw_id;
static uint32_t hw_id;
static char *opt_hw_rev;
static uint32_t hw_rev;
static uint32_t opt_hdr_ver = 1;
static char *country;
static const struct fw_region *region;
static int fw_ver_lo;
static int fw_ver_mid;
static int fw_ver_hi;
struct file_info kernel_info;
static uint32_t kernel_la = 0;
static uint32_t kernel_ep = 0;
uint32_t kernel_len = 0;
struct file_info rootfs_info;
uint32_t rootfs_ofs = 0;
uint32_t rootfs_align;
static struct file_info boot_info;
int combined;
int strip_padding;
int add_jffs2_eof;
static uint32_t fw_max_len;
static uint32_t reserved_space;
 
static struct file_info inspect_info;
static int extract = 0;
static bool endian_swap = false;
 
static const char md5salt_normal[MD5SUM_LEN] = {
0xdc, 0xd7, 0x3a, 0xa5, 0xc3, 0x95, 0x98, 0xfb,
0xdd, 0xf9, 0xe7, 0xf4, 0x0e, 0xae, 0x47, 0x38,
};
 
static const 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 const struct fw_region regions[] = {
/* Default region (universal) uses code 0 as well */
{"US", 1},
{"EU", 0},
{"BR", 0},
};
 
static const struct fw_region * find_region(const char *country) {
size_t i;
 
for (i = 0; i < ARRAY_SIZE(regions); i++) {
if (strcasecmp(regions[i].name, country) == 0)
return &regions[i];
}
 
return NULL;
}
 
static void usage(int status)
{
fprintf(stderr, "Usage: %s [OPTIONS...]\n", progname);
fprintf(stderr,
"\n"
"Options:\n"
" -c use combined kernel image\n"
" -e swap endianness in kernel load address and entry point\n"
" -E <ep> overwrite kernel entry point with <ep> (hexval prefixed with 0x)\n"
" -L <la> overwrite kernel load address with <la> (hexval prefixed with 0x)\n"
" -H <hwid> use hardware id specified with <hwid>\n"
" -W <hwrev> use hardware revision specified with <hwrev>\n"
" -C <country> set region code to <country>\n"
" -F <id> use flash layout specified with <id>\n"
" -k <file> read kernel image from the file <file>\n"
" -r <file> read rootfs image from the file <file>\n"
" -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"
" -m <version> set header version to <version>\n"
" -i <file> inspect given firmware file <file>\n"
" -x extract kernel and rootfs while inspecting (requires -i)\n"
" -X <size> reserve <size> bytes in the firmware image (hexval prefixed with 0x)\n"
" -h show this screen\n"
);
 
exit(status);
}
 
static int check_options(void)
{
int ret;
int exceed_bytes;
 
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 (opt_hw_id == NULL) {
ERR("hardware id not specified");
return -1;
}
hw_id = strtoul(opt_hw_id, NULL, 0);
 
if (!combined && layout_id == NULL) {
ERR("flash layout is not specified");
return -1;
}
 
if (opt_hw_rev)
hw_rev = strtoul(opt_hw_rev, NULL, 0);
else
hw_rev = 1;
 
if (country) {
region = find_region(country);
if (!region) {
ERR("unknown region code \"%s\"", country);
return -1;
}
}
 
if (combined) {
if (!kernel_la || !kernel_ep) {
ERR("kernel loading address and entry point must be specified for combined image");
return -1;
}
} else {
layout = find_layout(layouts, 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;
}
}
 
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) {
fw_max_len = layout->fw_max_len - reserved_space;
 
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);
rootfs_ofs = ALIGN(kernel_len, rootfs_align);
kernel_len -= sizeof(struct fw_header);
 
DBG("rootfs offset aligned to 0x%u", rootfs_ofs);
 
exceed_bytes = kernel_len + rootfs_info.file_size - (fw_max_len - sizeof(struct fw_header));
if (exceed_bytes > 0) {
ERR("images are too big by %i bytes", exceed_bytes);
return -1;
}
} else {
exceed_bytes = kernel_info.file_size - (rootfs_ofs - sizeof(struct fw_header));
if (exceed_bytes > 0) {
ERR("kernel image is too big by %i bytes", exceed_bytes);
return -1;
}
 
exceed_bytes = rootfs_info.file_size - (fw_max_len - rootfs_ofs);
if (exceed_bytes > 0) {
ERR("rootfs image is too big by %i bytes", exceed_bytes);
return -1;
}
}
}
 
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;
}
 
if (opt_hdr_ver == 1) {
hdr_ver = HEADER_VERSION_V1;
} else if (opt_hdr_ver == 2) {
hdr_ver = HEADER_VERSION_V2;
} else {
ERR("invalid header version '%u'", opt_hdr_ver);
return -1;
}
 
return 0;
}
 
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(hdr_ver);
strncpy(hdr->vendor_name, vendor, sizeof(hdr->vendor_name));
strncpy(hdr->fw_version, version, sizeof(hdr->fw_version));
hdr->hw_id = htonl(hw_id);
hdr->hw_rev = htonl(hw_rev);
 
hdr->kernel_la = htonl(kernel_la);
hdr->kernel_ep = htonl(kernel_ep);
hdr->kernel_ofs = htonl(sizeof(struct fw_header));
hdr->kernel_len = htonl(kernel_len);
 
if (!combined) {
if (boot_info.file_size == 0)
memcpy(hdr->md5sum1, md5salt_normal, sizeof(hdr->md5sum1));
else
memcpy(hdr->md5sum1, md5salt_boot, sizeof(hdr->md5sum1));
 
hdr->fw_length = htonl(layout->fw_max_len);
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);
 
if (region) {
hdr->region_code = htonl(region->code);
snprintf(
hdr->region_str1, sizeof(hdr->region_str1), "00000000;%02X%02X%02X%02X;",
region->name[0], region->name[1], region->name[2], region->name[3]
);
snprintf(
hdr->region_str2, sizeof(hdr->region_str2), "%02X%02X%02X%02X",
region->name[0], region->name[1], region->name[2], region->name[3]
);
}
 
if (endian_swap) {
hdr->kernel_la = bswap_32(hdr->kernel_la);
hdr->kernel_ep = bswap_32(hdr->kernel_ep);
}
 
if (!combined)
get_md5(buf, len, hdr->md5sum1);
}
 
static int inspect_fw(void)
{
char *buf;
struct fw_header *hdr;
uint8_t md5sum[MD5SUM_LEN];
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) &&
(ntohl(hdr->version) != HEADER_VERSION_V2)) {
ERR("file does not seem to have V1/V2 header!\n");
goto out_free_buf;
}
 
inspect_fw_phexdec("Version 1 Header size", sizeof(struct fw_header));
 
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);
inspect_fw_phex("Hardware ID", ntohl(hdr->hw_id));
inspect_fw_phex("Hardware Revision", ntohl(hdr->hw_rev));
inspect_fw_phex("Region code", ntohl(hdr->region_code));
 
printf("\n");
 
inspect_fw_phexdec("Kernel data offset",
ntohl(hdr->kernel_ofs));
inspect_fw_phexdec("Kernel data length",
ntohl(hdr->kernel_len));
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;
 
progname = basename(argv[0]);
 
while ( 1 ) {
int c;
 
c = getopt(argc, argv, "a:H:E:F:L:m:V:N:W:C:ci:k:r:R:o:xX:ehsjv:");
if (c == -1)
break;
 
switch (c) {
case 'a':
sscanf(optarg, "0x%x", &rootfs_align);
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 'C':
country = optarg;
break;
case 'L':
sscanf(optarg, "0x%x", &kernel_la);
break;
case 'm':
sscanf(optarg, "%u", &opt_hdr_ver);
break;
case 'V':
version = optarg;
break;
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 'e':
endian_swap = true;
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(sizeof(struct fw_header));
else
ret = inspect_fw();
 
out:
return ret;
}
/branches/gl-inet/tools/firmware-utils/src/mktplinkfw2.c
@@ -0,0 +1,628 @@
/*
* 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"
#include "mktplinkfw-lib.h"
 
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 hw_ver_add; /* 0x3c: additional hardware version */
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: bootloader offset */
uint32_t boot_len; /* 0x88: bootloader length */
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));
 
#define FLAG_LE_KERNEL_LA_EP 0x00000001 /* Little-endian used for kernel load address & entry point */
 
struct board_info {
char *id;
uint32_t hw_id;
uint32_t hw_rev;
uint32_t hw_ver_add;
char *layout_id;
uint32_t hdr_ver;
uint32_t flags;
};
 
/*
* Globals
*/
char *ofname;
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 struct board_info custom_board;
 
static struct board_info *board;
static char *layout_id;
struct flash_layout *layout;
static char *opt_hw_id;
static char *opt_hw_rev;
static char *opt_hw_ver_add;
static int fw_ver_lo;
static int fw_ver_mid;
static int fw_ver_hi;
static int sver_lo;
static int sver_hi;
struct file_info kernel_info;
static uint32_t kernel_la = 0;
static uint32_t kernel_ep = 0;
uint32_t kernel_len = 0;
struct file_info rootfs_info;
uint32_t rootfs_ofs = 0;
uint32_t rootfs_align;
static struct file_info boot_info;
int combined;
int strip_padding;
int add_jffs2_eof;
 
static struct file_info inspect_info;
static int extract = 0;
 
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, 0x5f, 0xd5, 0xc5, 0xce, 0xfa,
0xac, 0x9c, 0x28, 0xda, 0xb2, 0xe9, 0x0f, 0x42,
};
 
static struct flash_layout layouts[] = {
{
.id = "4Mmtk",
.fw_max_len = 0x3d0000,
.kernel_la = 0x80000000,
.kernel_ep = 0x80000000,
.rootfs_ofs = 0x140000,
}, {
.id = "8Mltq",
.fw_max_len = 0x7a0000,
.kernel_la = 0x80002000,
.kernel_ep = 0x80002000,
.rootfs_ofs = 0x140000,
}, {
.id = "16Mltq",
.fw_max_len = 0xf90000,
.kernel_la = 0x80002000,
.kernel_ep = 0x800061b0,
.rootfs_ofs = 0x140000,
}, {
.id = "8Mmtk",
.fw_max_len = 0x7a0000,
.kernel_la = 0x80000000,
.kernel_ep = 0x80000000,
.rootfs_ofs = 0x140000,
}, {
.id = "8MLmtk",
.fw_max_len = 0x7b0000,
.kernel_la = 0x80000000,
.kernel_ep = 0x80000000,
.rootfs_ofs = 0x140000,
}, {
/* terminating entry */
}
};
 
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"
" -c use combined kernel image\n"
" -e swap endianness in kernel load address and entry point\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"
" -w <hwveradd> use additional hardware version specified with <hwveradd>\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"
" -T <version> set header version to <version>\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 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 (opt_hw_id == NULL) {
ERR("hardware id must be specified");
return -1;
}
 
board = &custom_board;
 
if (layout_id == NULL) {
ERR("flash layout is not specified");
return -1;
}
 
board->hw_id = strtoul(opt_hw_id, NULL, 0);
 
board->hw_rev = 1;
board->hw_ver_add = 0;
 
if (opt_hw_rev)
board->hw_rev = strtoul(opt_hw_rev, NULL, 0);
if (opt_hw_ver_add)
board->hw_ver_add = strtoul(opt_hw_ver_add, NULL, 0);
 
layout = find_layout(layouts, 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);
rootfs_ofs = ALIGN(kernel_len, rootfs_align);
kernel_len -= sizeof(struct fw_header);
 
DBG("rootfs offset aligned to 0x%u", rootfs_ofs);
 
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;
}
 
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(board->hw_id);
hdr->hw_rev = htonl(board->hw_rev);
hdr->hw_ver_add = htonl(board->hw_ver_add);
 
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->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 (board->flags & FLAG_LE_KERNEL_LA_EP) {
hdr->kernel_la = bswap_32(hdr->kernel_la);
hdr->kernel_ep = bswap_32(hdr->kernel_ep);
}
 
get_md5(buf, len, hdr->md5sum1);
}
 
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;
 
board = &custom_board;
 
if (board->flags & FLAG_LE_KERNEL_LA_EP) {
hdr->kernel_la = bswap_32(hdr->kernel_la);
hdr->kernel_ep = bswap_32(hdr->kernel_ep);
}
 
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));
 
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);
inspect_fw_phex("Hardware ID", ntohl(hdr->hw_id));
inspect_fw_phex("Hardware Revision",
ntohl(hdr->hw_rev));
inspect_fw_phex("Additional HW Version",
ntohl(hdr->hw_ver_add));
 
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));
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;
 
progname = basename(argv[0]);
 
while ( 1 ) {
int c;
 
c = getopt(argc, argv, "a:H:E:F:L:V:N:W: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 '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 'w':
opt_hw_ver_add = 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':
custom_board.flags = FLAG_LE_KERNEL_LA_EP;
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(sizeof(struct fw_header));
else
ret = inspect_fw();
 
out:
return ret;
}
 
/branches/gl-inet/tools/firmware-utils/src/mkwrggimg.c
@@ -0,0 +1,283 @@
/*
* Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
* Copyright (C) 2016 Stijn Tintel <stijn@linux-ipv6.be>
*
* 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.
*
*/
 
#define _ANSI_SOURCE
#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 WRGG03_MAGIC 0x20080321
 
struct wrgg03_header {
char signature[32];
uint32_t magic1;
uint32_t magic2;
char version[16];
char model[16];
uint32_t flag[2];
uint32_t reserve[2];
char buildno[16];
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 *version;
static char *model;
static uint32_t flag = 0;
static uint32_t reserve = 0;
static char *buildno;
static uint32_t offset;
static char *devname;
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"
" -B <buildno> build number\n"
" -i <file> read input from the file <file>\n"
" -d <name> set device name to <name>\n"
" -m <model> model 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, int swap)
{
unsigned char *p = data;
 
if (swap) {
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 wrgg03_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 wrgg03_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:m:o:s:v:B:O:h");
if (c == -1)
break;
 
switch (c) {
case 'b':
big_endian = 1;
break;
case 'B':
buildno = optarg;
break;
case 'd':
devname = optarg;
break;
case 'i':
ifname = optarg;
break;
case 'm':
model = optarg;
break;
case 'o':
ofname = optarg;
break;
case 's':
signature = optarg;
break;
case 'v':
version = 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 (devname == NULL) {
ERR("no device name specified");
goto err;
}
 
if (model == NULL) {
ERR("no model name specified");
goto err;
}
 
if (buildno == NULL) {
ERR("no build number specified");
goto err;
}
 
if (version == NULL) {
ERR("no version specified");
goto err;
}
 
err = stat(ifname, &st);
if (err){
ERRS("stat failed on %s", ifname);
goto err;
}
 
buflen = st.st_size + sizeof(struct wrgg03_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 wrgg03_header), st.st_size, 1, infile);
if (errno != 0) {
ERRS("unable to read from file %s", ifname);
goto close_in;
}
 
header = (struct wrgg03_header *) buf;
memset(header, '\0', sizeof(struct wrgg03_header));
 
strncpy(header->signature, signature, sizeof(header->signature));
put_u32(&header->magic1, WRGG03_MAGIC, 0);
put_u32(&header->magic2, WRGG03_MAGIC, 0);
strncpy(header->version, version, sizeof(header->version));
strncpy(header->model, model, sizeof(header->model));
put_u32(&header->flag, flag, 0);
put_u32(&header->reserve, reserve, 0);
strncpy(header->buildno, buildno, sizeof(header->buildno));
put_u32(&header->size, st.st_size, big_endian);
put_u32(&header->offset, offset, big_endian);
strncpy(header->devname, devname, sizeof(header->devname));
 
get_digest(header, buf + sizeof(struct wrgg03_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;
}
/branches/gl-inet/tools/firmware-utils/src/mkwrgimg.c
@@ -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;
}
/branches/gl-inet/tools/firmware-utils/src/mkzcfw.c
@@ -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 ": %s\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;
}
 
/branches/gl-inet/tools/firmware-utils/src/mkzynfw.c
@@ -0,0 +1,1131 @@
/*
*
* Copyright (C) 2007-2008 OpenWrt.org
* Copyright (C) 2007-2008 Gabor Juhos <juhosg at openwrt.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 <inttypes.h>
 
#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=%zu",
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 %" PRIu32,
*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;
}
/branches/gl-inet/tools/firmware-utils/src/motorola-bin.c
@@ -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 OpenWRT,
* 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;
}
/branches/gl-inet/tools/firmware-utils/src/myloader.h
@@ -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_*/
/branches/gl-inet/tools/firmware-utils/src/nand_ecc.c
@@ -0,0 +1,204 @@
/*
* calculate ecc code for nand flash
*
* Copyright (C) 2008 yajin <yajin@vm-kernel.org>
* Copyright (C) 2009 Felix Fietkau <nbd@nbd.name>
*
* 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;
}
 
/branches/gl-inet/tools/firmware-utils/src/osbridge-crc.c
@@ -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 ": %s\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;
}
 
/branches/gl-inet/tools/firmware-utils/src/oseama.c
@@ -0,0 +1,556 @@
/*
* oseama
*
* Copyright (C) 2016 Rafał Miłecki <zajec5@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.
*/
 
#include <byteswap.h>
#include <endian.h>
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
 
#include "md5.h"
 
#if !defined(__BYTE_ORDER)
#error "Unknown byte order"
#endif
 
#if __BYTE_ORDER == __BIG_ENDIAN
#define cpu_to_be32(x) (x)
#define be32_to_cpu(x) (x)
#define cpu_to_be16(x) (x)
#define be16_to_cpu(x) (x)
#elif __BYTE_ORDER == __LITTLE_ENDIAN
#define cpu_to_be32(x) bswap_32(x)
#define be32_to_cpu(x) bswap_32(x)
#define cpu_to_be16(x) bswap_16(x)
#define be16_to_cpu(x) bswap_16(x)
#else
#error "Unsupported endianness"
#endif
 
#define SEAMA_MAGIC 0x5ea3a417
 
struct seama_seal_header {
uint32_t magic;
uint16_t reserved;
uint16_t metasize;
uint32_t imagesize;
} __attribute__ ((packed));
 
struct seama_entity_header {
uint32_t magic;
uint16_t reserved;
uint16_t metasize;
uint32_t imagesize;
uint8_t md5[16];
} __attribute__ ((packed));
 
char *seama_path;
int entity_idx = -1;
char *out_path;
 
static inline size_t oseama_min(size_t x, size_t y) {
return x < y ? x : y;
}
 
/**************************************************
* Info
**************************************************/
 
static void oseama_info_parse_options(int argc, char **argv) {
int c;
 
while ((c = getopt(argc, argv, "e:")) != -1) {
switch (c) {
case 'e':
entity_idx = atoi(optarg);
break;
}
}
}
 
static int oseama_info_entities(FILE *seama) {
struct seama_entity_header hdr;
size_t bytes, metasize, imagesize;
uint8_t buf[1024];
char *end, *tmp;
int i = 0;
int err = 0;
 
while ((bytes = fread(&hdr, 1, sizeof(hdr), seama)) == sizeof(hdr)) {
if (be32_to_cpu(hdr.magic) != SEAMA_MAGIC) {
fprintf(stderr, "Invalid Seama magic: 0x%08x\n", be32_to_cpu(hdr.magic));
err = -EINVAL;
goto err_out;
}
metasize = be16_to_cpu(hdr.metasize);
imagesize = be32_to_cpu(hdr.imagesize);
 
if (entity_idx >= 0 && i != entity_idx) {
fseek(seama, metasize + imagesize, SEEK_CUR);
i++;
continue;
}
 
if (metasize >= sizeof(buf)) {
fprintf(stderr, "Too small buffer (%zu B) to read all meta info (%zd B)\n", sizeof(buf), metasize);
err = -EINVAL;
goto err_out;
}
 
if (entity_idx < 0)
printf("\n");
printf("Entity offset:\t%ld\n", ftell(seama) - sizeof(hdr));
printf("Entity size:\t%zd\n", sizeof(hdr) + metasize + imagesize);
printf("Meta size:\t%zd\n", metasize);
printf("Image size:\t%zd\n", imagesize);
 
bytes = fread(buf, 1, metasize, seama);
if (bytes != metasize) {
fprintf(stderr, "Couldn't read %zd B of meta\n", metasize);
err = -EIO;
goto err_out;
}
 
end = (char *)&buf[metasize - 1];
*end = '\0';
for (tmp = (char *)buf; tmp < end && strlen(tmp); tmp += strlen(tmp) + 1) {
printf("Meta entry:\t%s\n", tmp);
}
 
fseek(seama, imagesize, SEEK_CUR);
i++;
}
 
err_out:
return err;
}
 
static int oseama_info(int argc, char **argv) {
FILE *seama;
struct seama_seal_header hdr;
size_t bytes;
uint16_t metasize;
uint32_t imagesize;
uint8_t buf[1024];
int err = 0;
 
if (argc < 3) {
fprintf(stderr, "No Seama file passed\n");
err = -EINVAL;
goto out;
}
seama_path = argv[2];
 
optind = 3;
oseama_info_parse_options(argc, argv);
 
seama = fopen(seama_path, "r");
if (!seama) {
fprintf(stderr, "Couldn't open %s\n", seama_path);
err = -EACCES;
goto out;
}
 
bytes = fread(&hdr, 1, sizeof(hdr), seama);
if (bytes != sizeof(hdr)) {
fprintf(stderr, "Couldn't read %s header\n", seama_path);
err = -EIO;
goto err_close;
}
metasize = be16_to_cpu(hdr.metasize);
imagesize = be32_to_cpu(hdr.imagesize);
 
if (be32_to_cpu(hdr.magic) != SEAMA_MAGIC) {
fprintf(stderr, "Invalid Seama magic: 0x%08x\n", be32_to_cpu(hdr.magic));
err = -EINVAL;
goto err_close;
}
 
if (metasize >= sizeof(buf)) {
fprintf(stderr, "Too small buffer (%zu B) to read all meta info (%d B)\n", sizeof(buf), metasize);
err = -EINVAL;
goto err_close;
}
 
if (imagesize) {
fprintf(stderr, "Invalid Seama image size: 0x%08x (should be 0)\n", imagesize);
err = -EINVAL;
goto err_close;
}
 
bytes = fread(buf, 1, metasize, seama);
if (bytes != metasize) {
fprintf(stderr, "Couldn't read %d B of meta\n", metasize);
err = -EIO;
goto err_close;
}
 
if (entity_idx < 0) {
char *end, *tmp;
 
printf("Meta size:\t%d\n", metasize);
printf("Image size:\t%d\n", imagesize);
 
end = (char *)&buf[metasize - 1];
*end = '\0';
for (tmp = (char *)buf; tmp < end && strlen(tmp); tmp += strlen(tmp) + 1) {
printf("Meta entry:\t%s\n", tmp);
}
}
 
oseama_info_entities(seama);
 
err_close:
fclose(seama);
out:
return err;
}
 
/**************************************************
* Create
**************************************************/
 
static ssize_t oseama_entity_append_file(FILE *seama, const char *in_path) {
FILE *in;
size_t bytes;
ssize_t length = 0;
uint8_t buf[128];
 
in = fopen(in_path, "r");
if (!in) {
fprintf(stderr, "Couldn't open %s\n", in_path);
return -EACCES;
}
 
while ((bytes = fread(buf, 1, sizeof(buf), in)) > 0) {
if (fwrite(buf, 1, bytes, seama) != bytes) {
fprintf(stderr, "Couldn't write %zu B to %s\n", bytes, seama_path);
length = -EIO;
break;
}
length += bytes;
}
 
fclose(in);
 
return length;
}
 
static ssize_t oseama_entity_append_zeros(FILE *seama, size_t length) {
uint8_t *buf;
 
buf = malloc(length);
if (!buf)
return -ENOMEM;
memset(buf, 0, length);
 
if (fwrite(buf, 1, length, seama) != length) {
fprintf(stderr, "Couldn't write %zu B to %s\n", length, seama_path);
return -EIO;
}
 
return length;
}
 
static ssize_t oseama_entity_align(FILE *seama, size_t curr_offset, size_t alignment) {
if (curr_offset & (alignment - 1)) {
size_t length = alignment - (curr_offset % alignment);
 
return oseama_entity_append_zeros(seama, length);
}
 
return 0;
}
 
static int oseama_entity_write_hdr(FILE *seama, size_t metasize, size_t imagesize) {
struct seama_entity_header hdr = {};
uint8_t buf[128];
size_t length = imagesize;
size_t bytes;
MD5_CTX ctx;
 
fseek(seama, sizeof(hdr) + metasize, SEEK_SET);
MD5_Init(&ctx);
while ((bytes = fread(buf, 1, oseama_min(sizeof(buf), length), seama)) > 0) {
MD5_Update(&ctx, buf, bytes);
length -= bytes;
}
MD5_Final(hdr.md5, &ctx);
 
hdr.magic = cpu_to_be32(SEAMA_MAGIC);
hdr.metasize = cpu_to_be16(metasize);
hdr.imagesize = cpu_to_be32(imagesize);
 
fseek(seama, 0, SEEK_SET);
bytes = fwrite(&hdr, 1, sizeof(hdr), seama);
if (bytes != sizeof(hdr)) {
fprintf(stderr, "Couldn't write Seama entity header to %s\n", seama_path);
return -EIO;
}
 
return 0;
}
 
static int oseama_entity(int argc, char **argv) {
FILE *seama;
ssize_t sbytes;
size_t curr_offset = sizeof(struct seama_entity_header);
size_t metasize = 0, imagesize = 0;
int c;
int err = 0;
 
if (argc < 3) {
fprintf(stderr, "No Seama file passed\n");
err = -EINVAL;
goto out;
}
seama_path = argv[2];
 
seama = fopen(seama_path, "w+");
if (!seama) {
fprintf(stderr, "Couldn't open %s\n", seama_path);
err = -EACCES;
goto out;
}
fseek(seama, curr_offset, SEEK_SET);
 
optind = 3;
while ((c = getopt(argc, argv, "m:f:b:")) != -1) {
switch (c) {
case 'm':
sbytes = fwrite(optarg, 1, strlen(optarg) + 1, seama);
if (sbytes < 0) {
fprintf(stderr, "Failed to write meta %s\n", optarg);
} else {
curr_offset += sbytes;
metasize += sbytes;
}
 
sbytes = oseama_entity_align(seama, curr_offset, 4);
if (sbytes < 0) {
fprintf(stderr, "Failed to append zeros\n");
} else {
curr_offset += sbytes;
metasize += sbytes;
}
 
break;
case 'f':
case 'b':
break;
}
}
 
optind = 3;
while ((c = getopt(argc, argv, "m:f:b:")) != -1) {
switch (c) {
case 'm':
break;
case 'f':
sbytes = oseama_entity_append_file(seama, optarg);
if (sbytes < 0) {
fprintf(stderr, "Failed to append file %s\n", optarg);
} else {
curr_offset += sbytes;
imagesize += sbytes;
}
break;
case 'b':
sbytes = strtol(optarg, NULL, 0) - curr_offset;
if (sbytes < 0) {
fprintf(stderr, "Current Seama entity length is 0x%zx, can't pad it with zeros to 0x%lx\n", curr_offset, strtol(optarg, NULL, 0));
} else {
sbytes = oseama_entity_append_zeros(seama, sbytes);
if (sbytes < 0) {
fprintf(stderr, "Failed to append zeros\n");
} else {
curr_offset += sbytes;
imagesize += sbytes;
}
}
break;
}
if (err)
break;
}
 
oseama_entity_write_hdr(seama, metasize, imagesize);
 
fclose(seama);
out:
return err;
}
 
/**************************************************
* Extract
**************************************************/
 
static void oseama_extract_parse_options(int argc, char **argv) {
int c;
 
while ((c = getopt(argc, argv, "e:o:")) != -1) {
switch (c) {
case 'e':
entity_idx = atoi(optarg);
break;
case 'o':
out_path = optarg;
break;
}
}
}
 
static int oseama_extract_entity(FILE *seama, FILE *out) {
struct seama_entity_header hdr;
size_t bytes, metasize, imagesize, length;
uint8_t buf[1024];
int i = 0;
int err = 0;
 
while ((bytes = fread(&hdr, 1, sizeof(hdr), seama)) == sizeof(hdr)) {
if (be32_to_cpu(hdr.magic) != SEAMA_MAGIC) {
fprintf(stderr, "Invalid Seama magic: 0x%08x\n", be32_to_cpu(hdr.magic));
err = -EINVAL;
break;
}
metasize = be16_to_cpu(hdr.metasize);
imagesize = be32_to_cpu(hdr.imagesize);
 
if (i != entity_idx) {
fseek(seama, metasize + imagesize, SEEK_CUR);
i++;
continue;
}
 
fseek(seama, -sizeof(hdr), SEEK_CUR);
 
length = sizeof(hdr) + metasize + imagesize;
while ((bytes = fread(buf, 1, oseama_min(sizeof(buf), length), seama)) > 0) {
if (fwrite(buf, 1, bytes, out) != bytes) {
fprintf(stderr, "Couldn't write %zu B to %s\n", bytes, out_path);
err = -EIO;
break;
}
length -= bytes;
}
 
if (length) {
fprintf(stderr, "Couldn't extract whole entity %d from %s (%zu B left)\n", entity_idx, seama_path, length);
err = -EIO;
break;
}
 
break;
}
 
return err;
}
 
static int oseama_extract(int argc, char **argv) {
FILE *seama;
FILE *out;
struct seama_seal_header hdr;
size_t bytes;
uint16_t metasize;
int err = 0;
 
if (argc < 3) {
fprintf(stderr, "No Seama file passed\n");
err = -EINVAL;
goto out;
}
seama_path = argv[2];
 
optind = 3;
oseama_extract_parse_options(argc, argv);
if (entity_idx < 0) {
fprintf(stderr, "No entity specified\n");
err = -EINVAL;
goto out;
} else if (!out_path) {
fprintf(stderr, "No output file specified\n");
err = -EINVAL;
goto out;
}
 
seama = fopen(seama_path, "r");
if (!seama) {
fprintf(stderr, "Couldn't open %s\n", seama_path);
err = -EACCES;
goto out;
}
 
out = fopen(out_path, "w");
if (!out) {
fprintf(stderr, "Couldn't open %s\n", out_path);
err = -EACCES;
goto err_close_seama;
}
 
bytes = fread(&hdr, 1, sizeof(hdr), seama);
if (bytes != sizeof(hdr)) {
fprintf(stderr, "Couldn't read %s header\n", seama_path);
err = -EIO;
goto err_close_out;
}
metasize = be16_to_cpu(hdr.metasize);
 
fseek(seama, metasize, SEEK_CUR);
 
oseama_extract_entity(seama, out);
 
err_close_out:
fclose(out);
err_close_seama:
fclose(seama);
out:
return err;
}
 
/**************************************************
* Start
**************************************************/
 
static void usage() {
printf("Usage:\n");
printf("\n");
printf("Info about Seama seal (container):\n");
printf("\toseama info <file> [options]\n");
printf("\t-e\t\t\t\tprint info about specified entity only\n");
printf("\n");
printf("Create Seama entity:\n");
printf("\toseama entity <file> [options]\n");
printf("\t-m meta\t\t\t\tmeta into to put in header\n");
printf("\t-f file\t\t\t\tappend content from file\n");
printf("\t-b offset\t\t\tappend zeros till reaching absolute offset\n");
printf("\n");
printf("Extract from Seama seal (container):\n");
printf("\toseama extract <file> [options]\n");
printf("\t-e\t\t\t\tindex of entity to extract\n");
printf("\t-o file\t\t\t\toutput file\n");
}
 
int main(int argc, char **argv) {
if (argc > 1) {
if (!strcmp(argv[1], "info"))
return oseama_info(argc, argv);
else if (!strcmp(argv[1], "entity"))
return oseama_entity(argc, argv);
else if (!strcmp(argv[1], "extract"))
return oseama_extract(argc, argv);
}
 
usage();
return 0;
}
/branches/gl-inet/tools/firmware-utils/src/otrx.c
@@ -0,0 +1,592 @@
/*
* otrx
*
* Copyright (C) 2015-2017 Rafał Miłecki <zajec5@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.
*/
 
#include <byteswap.h>
#include <endian.h>
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
 
#if !defined(__BYTE_ORDER)
#error "Unknown byte order"
#endif
 
#if __BYTE_ORDER == __BIG_ENDIAN
#define cpu_to_le32(x) bswap_32(x)
#define le32_to_cpu(x) bswap_32(x)
#elif __BYTE_ORDER == __LITTLE_ENDIAN
#define cpu_to_le32(x) (x)
#define le32_to_cpu(x) (x)
#else
#error "Unsupported endianness"
#endif
 
#define TRX_MAGIC 0x30524448
#define TRX_FLAGS_OFFSET 12
#define TRX_MAX_PARTS 3
 
struct trx_header {
uint32_t magic;
uint32_t length;
uint32_t crc32;
uint16_t flags;
uint16_t version;
uint32_t offset[3];
};
 
char *trx_path;
size_t trx_offset = 0;
char *partition[TRX_MAX_PARTS] = {};
 
static inline size_t otrx_min(size_t x, size_t y) {
return x < y ? x : y;
}
 
/**************************************************
* CRC32
**************************************************/
 
static const uint32_t crc32_tbl[] = {
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 otrx_crc32(uint32_t crc, uint8_t *buf, size_t len) {
while (len) {
crc = crc32_tbl[(crc ^ *buf) & 0xff] ^ (crc >> 8);
buf++;
len--;
}
 
return crc;
}
 
/**************************************************
* Check
**************************************************/
 
static void otrx_check_parse_options(int argc, char **argv) {
int c;
 
while ((c = getopt(argc, argv, "o:")) != -1) {
switch (c) {
case 'o':
trx_offset = atoi(optarg);
break;
}
}
}
 
static int otrx_check(int argc, char **argv) {
FILE *trx;
struct trx_header hdr;
size_t bytes, length;
uint8_t buf[1024];
uint32_t crc32;
int err = 0;
 
if (argc < 3) {
fprintf(stderr, "No TRX file passed\n");
err = -EINVAL;
goto out;
}
trx_path = argv[2];
 
optind = 3;
otrx_check_parse_options(argc, argv);
 
trx = fopen(trx_path, "r");
if (!trx) {
fprintf(stderr, "Couldn't open %s\n", trx_path);
err = -EACCES;
goto out;
}
 
fseek(trx, trx_offset, SEEK_SET);
bytes = fread(&hdr, 1, sizeof(hdr), trx);
if (bytes != sizeof(hdr)) {
fprintf(stderr, "Couldn't read %s header\n", trx_path);
err = -EIO;
goto err_close;
}
 
if (le32_to_cpu(hdr.magic) != TRX_MAGIC) {
fprintf(stderr, "Invalid TRX magic: 0x%08x\n", le32_to_cpu(hdr.magic));
err = -EINVAL;
goto err_close;
}
 
length = le32_to_cpu(hdr.length);
if (length < sizeof(hdr)) {
fprintf(stderr, "Length read from TRX too low (%zu B)\n", length);
err = -EINVAL;
goto err_close;
}
 
crc32 = 0xffffffff;
fseek(trx, trx_offset + TRX_FLAGS_OFFSET, SEEK_SET);
length -= TRX_FLAGS_OFFSET;
while ((bytes = fread(buf, 1, otrx_min(sizeof(buf), length), trx)) > 0) {
crc32 = otrx_crc32(crc32, buf, bytes);
length -= bytes;
}
 
if (length) {
fprintf(stderr, "Couldn't read last %zd B of data from %s\n", length, trx_path);
err = -EIO;
goto err_close;
}
 
if (crc32 != le32_to_cpu(hdr.crc32)) {
fprintf(stderr, "Invalid data crc32: 0x%08x instead of 0x%08x\n", crc32, le32_to_cpu(hdr.crc32));
err = -EINVAL;
goto err_close;
}
 
printf("Found a valid TRX version %d\n", le32_to_cpu(hdr.version));
 
err_close:
fclose(trx);
out:
return err;
}
 
/**************************************************
* Create
**************************************************/
 
static ssize_t otrx_create_append_file(FILE *trx, const char *in_path) {
FILE *in;
size_t bytes;
ssize_t length = 0;
uint8_t buf[1024];
 
in = fopen(in_path, "r");
if (!in) {
fprintf(stderr, "Couldn't open %s\n", in_path);
return -EACCES;
}
 
while ((bytes = fread(buf, 1, sizeof(buf), in)) > 0) {
if (fwrite(buf, 1, bytes, trx) != bytes) {
fprintf(stderr, "Couldn't write %zu B to %s\n", bytes, trx_path);
length = -EIO;
break;
}
length += bytes;
}
 
fclose(in);
 
return length;
}
 
static ssize_t otrx_create_append_zeros(FILE *trx, size_t length) {
uint8_t *buf;
 
buf = malloc(length);
if (!buf)
return -ENOMEM;
memset(buf, 0, length);
 
if (fwrite(buf, 1, length, trx) != length) {
fprintf(stderr, "Couldn't write %zu B to %s\n", length, trx_path);
free(buf);
return -EIO;
}
 
free(buf);
 
return length;
}
 
static ssize_t otrx_create_align(FILE *trx, size_t curr_offset, size_t alignment) {
if (curr_offset & (alignment - 1)) {
size_t length = alignment - (curr_offset % alignment);
return otrx_create_append_zeros(trx, length);
}
 
return 0;
}
 
static int otrx_create_write_hdr(FILE *trx, struct trx_header *hdr) {
size_t bytes, length;
uint8_t buf[1024];
uint32_t crc32;
 
hdr->magic = cpu_to_le32(TRX_MAGIC);
hdr->version = 1;
 
fseek(trx, 0, SEEK_SET);
bytes = fwrite(hdr, 1, sizeof(struct trx_header), trx);
if (bytes != sizeof(struct trx_header)) {
fprintf(stderr, "Couldn't write TRX header to %s\n", trx_path);
return -EIO;
}
 
length = le32_to_cpu(hdr->length);
 
crc32 = 0xffffffff;
fseek(trx, TRX_FLAGS_OFFSET, SEEK_SET);
length -= TRX_FLAGS_OFFSET;
while ((bytes = fread(buf, 1, otrx_min(sizeof(buf), length), trx)) > 0) {
crc32 = otrx_crc32(crc32, buf, bytes);
length -= bytes;
}
hdr->crc32 = cpu_to_le32(crc32);
 
fseek(trx, 0, SEEK_SET);
bytes = fwrite(hdr, 1, sizeof(struct trx_header), trx);
if (bytes != sizeof(struct trx_header)) {
fprintf(stderr, "Couldn't write TRX header to %s\n", trx_path);
return -EIO;
}
 
return 0;
}
 
static int otrx_create(int argc, char **argv) {
FILE *trx;
struct trx_header hdr = {};
ssize_t sbytes;
size_t curr_idx = 0;
size_t curr_offset = sizeof(hdr);
int c;
int err = 0;
 
if (argc < 3) {
fprintf(stderr, "No TRX file passed\n");
err = -EINVAL;
goto out;
}
trx_path = argv[2];
 
trx = fopen(trx_path, "w+");
if (!trx) {
fprintf(stderr, "Couldn't open %s\n", trx_path);
err = -EACCES;
goto out;
}
fseek(trx, curr_offset, SEEK_SET);
 
optind = 3;
while ((c = getopt(argc, argv, "f:A:a:b:")) != -1) {
switch (c) {
case 'f':
if (curr_idx >= TRX_MAX_PARTS) {
err = -ENOSPC;
fprintf(stderr, "Reached TRX partitions limit, no place for %s\n", optarg);
goto err_close;
}
 
sbytes = otrx_create_append_file(trx, optarg);
if (sbytes < 0) {
fprintf(stderr, "Failed to append file %s\n", optarg);
} else {
hdr.offset[curr_idx++] = curr_offset;
curr_offset += sbytes;
}
 
sbytes = otrx_create_align(trx, curr_offset, 4);
if (sbytes < 0)
fprintf(stderr, "Failed to append zeros\n");
else
curr_offset += sbytes;
 
break;
case 'A':
sbytes = otrx_create_append_file(trx, optarg);
if (sbytes < 0) {
fprintf(stderr, "Failed to append file %s\n", optarg);
} else {
curr_offset += sbytes;
}
 
sbytes = otrx_create_align(trx, curr_offset, 4);
if (sbytes < 0)
fprintf(stderr, "Failed to append zeros\n");
else
curr_offset += sbytes;
break;
case 'a':
sbytes = otrx_create_align(trx, curr_offset, strtol(optarg, NULL, 0));
if (sbytes < 0)
fprintf(stderr, "Failed to append zeros\n");
else
curr_offset += sbytes;
break;
case 'b':
sbytes = strtol(optarg, NULL, 0) - curr_offset;
if (sbytes < 0) {
fprintf(stderr, "Current TRX length is 0x%zx, can't pad it with zeros to 0x%lx\n", curr_offset, strtol(optarg, NULL, 0));
} else {
sbytes = otrx_create_append_zeros(trx, sbytes);
if (sbytes < 0)
fprintf(stderr, "Failed to append zeros\n");
else
curr_offset += sbytes;
}
break;
}
if (err)
break;
}
 
sbytes = otrx_create_align(trx, curr_offset, 0x1000);
if (sbytes < 0)
fprintf(stderr, "Failed to append zeros\n");
else
curr_offset += sbytes;
 
hdr.length = curr_offset;
otrx_create_write_hdr(trx, &hdr);
err_close:
fclose(trx);
out:
return err;
}
 
/**************************************************
* Extract
**************************************************/
 
static void otrx_extract_parse_options(int argc, char **argv) {
int c;
 
while ((c = getopt(argc, argv, "c:e:o:1:2:3:")) != -1) {
switch (c) {
case 'o':
trx_offset = atoi(optarg);
break;
case '1':
partition[0] = optarg;
break;
case '2':
partition[1] = optarg;
break;
case '3':
partition[2] = optarg;
break;
}
}
}
 
static int otrx_extract_copy(FILE *trx, size_t offset, size_t length, char *out_path) {
FILE *out;
size_t bytes;
uint8_t *buf;
int err = 0;
 
out = fopen(out_path, "w");
if (!out) {
fprintf(stderr, "Couldn't open %s\n", out_path);
err = -EACCES;
goto out;
}
 
buf = malloc(length);
if (!buf) {
fprintf(stderr, "Couldn't alloc %zu B buffer\n", length);
err = -ENOMEM;
goto err_close;
}
 
fseek(trx, offset, SEEK_SET);
bytes = fread(buf, 1, length, trx);
if (bytes != length) {
fprintf(stderr, "Couldn't read %zu B of data from %s\n", length, trx_path);
err = -ENOMEM;
goto err_free_buf;
};
 
bytes = fwrite(buf, 1, length, out);
if (bytes != length) {
fprintf(stderr, "Couldn't write %zu B to %s\n", length, out_path);
err = -ENOMEM;
goto err_free_buf;
}
 
printf("Extracted 0x%zx bytes into %s\n", length, out_path);
 
err_free_buf:
free(buf);
err_close:
fclose(out);
out:
return err;
}
 
static int otrx_extract(int argc, char **argv) {
FILE *trx;
struct trx_header hdr;
size_t bytes;
int i;
int err = 0;
 
if (argc < 3) {
fprintf(stderr, "No TRX file passed\n");
err = -EINVAL;
goto out;
}
trx_path = argv[2];
 
optind = 3;
otrx_extract_parse_options(argc, argv);
 
trx = fopen(trx_path, "r");
if (!trx) {
fprintf(stderr, "Couldn't open %s\n", trx_path);
err = -EACCES;
goto out;
}
 
fseek(trx, trx_offset, SEEK_SET);
bytes = fread(&hdr, 1, sizeof(hdr), trx);
if (bytes != sizeof(hdr)) {
fprintf(stderr, "Couldn't read %s header\n", trx_path);
err = -EIO;
goto err_close;
}
 
if (le32_to_cpu(hdr.magic) != TRX_MAGIC) {
fprintf(stderr, "Invalid TRX magic: 0x%08x\n", le32_to_cpu(hdr.magic));
err = -EINVAL;
goto err_close;
}
 
for (i = 0; i < TRX_MAX_PARTS; i++) {
size_t length;
 
if (!partition[i])
continue;
if (!hdr.offset[i]) {
printf("TRX doesn't contain partition %d, can't extract %s\n", i + 1, partition[i]);
continue;
}
 
if (i + 1 >= TRX_MAX_PARTS || !hdr.offset[i + 1])
length = le32_to_cpu(hdr.length) - le32_to_cpu(hdr.offset[i]);
else
length = le32_to_cpu(hdr.offset[i + 1]) - le32_to_cpu(hdr.offset[i]);
 
otrx_extract_copy(trx, trx_offset + le32_to_cpu(hdr.offset[i]), length, partition[i]);
}
 
err_close:
fclose(trx);
out:
return err;
}
 
/**************************************************
* Start
**************************************************/
 
static void usage() {
printf("Usage:\n");
printf("\n");
printf("Checking TRX file:\n");
printf("\totrx check <file> [options]\tcheck if file is a valid TRX\n");
printf("\t-o offset\t\t\toffset of TRX data in file (default: 0)\n");
printf("\n");
printf("Creating new TRX file:\n");
printf("\totrx create <file> [options] [partitions]\n");
printf("\t-f file\t\t\t\t[partition] start new partition with content copied from file\n");
printf("\t-A file\t\t\t\t[partition] append current partition with content copied from file\n");
printf("\t-a alignment\t\t\t[partition] align current partition\n");
printf("\t-b offset\t\t\t[partition] append zeros to partition till reaching absolute offset\n");
printf("\n");
printf("Extracting from TRX file:\n");
printf("\totrx extract <file> [options]\textract partitions from TRX file\n");
printf("\t-o offset\t\t\toffset of TRX data in file (default: 0)\n");
printf("\t-1 file\t\t\t\tfile to extract 1st partition to (optional)\n");
printf("\t-2 file\t\t\t\tfile to extract 2nd partition to (optional)\n");
printf("\t-3 file\t\t\t\tfile to extract 3rd partition to (optional)\n");
}
 
int main(int argc, char **argv) {
if (argc > 1) {
if (!strcmp(argv[1], "check"))
return otrx_check(argc, argv);
else if (!strcmp(argv[1], "create"))
return otrx_create(argc, argv);
else if (!strcmp(argv[1], "extract"))
return otrx_extract(argc, argv);
}
 
usage();
return 0;
}
/branches/gl-inet/tools/firmware-utils/src/pc1crypt.c
@@ -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 ": %s\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;
}
 
/branches/gl-inet/tools/firmware-utils/src/ptgen.c
@@ -0,0 +1,256 @@
/*
* ptgen - partition table generator
* Copyright (C) 2006 by Felix Fietkau <nbd@nbd.name>
*
* 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 <stdint.h>
#include <ctype.h>
#include <fcntl.h>
#include <stdint.h>
 
#if __BYTE_ORDER == __BIG_ENDIAN
#define cpu_to_le32(x) bswap_32(x)
#elif __BYTE_ORDER == __LITTLE_ENDIAN
#define cpu_to_le32(x) (x)
#else
#error unknown endianness!
#endif
 
/* Partition table entry */
struct pte {
uint8_t active;
uint8_t chs_start[3];
uint8_t type;
uint8_t chs_end[3];
uint32_t start;
uint32_t 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) */
if (exp == 0)
return result;
return result * (2 << ((10 * exp) - 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_le32(start);
 
sect = start + parts[i].size * 2;
if (kb_align == 0)
sect = round_to_cyl(sect);
pte[i].length = cpu_to_le32(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(EXIT_FAILURE);
}
 
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(EXIT_FAILURE);
}
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) ? EXIT_FAILURE : EXIT_SUCCESS;
}
/branches/gl-inet/tools/firmware-utils/src/seama.c
@@ -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 : %zu 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 : %zu 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: %zu\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;
}
/branches/gl-inet/tools/firmware-utils/src/seama.h
@@ -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
/branches/gl-inet/tools/firmware-utils/src/sha1.c
@@ -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
/branches/gl-inet/tools/firmware-utils/src/sha1.h
@@ -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 */
/branches/gl-inet/tools/firmware-utils/src/spw303v.c
@@ -0,0 +1,242 @@
/*
* spw303v.c - partially based on OpenWrt'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 <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.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;
}
/branches/gl-inet/tools/firmware-utils/src/srec2bin.c
@@ -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);
}
 
int main(int argc, char *argv[])
{
debug = TRUE;
debug = FALSE;
verbose = FALSE;
srec2bin(argc,argv,verbose);
return 0;
}
 
/branches/gl-inet/tools/firmware-utils/src/tplink-safeloader.c
@@ -0,0 +1,1953 @@
/*
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 <limits.h>
 
#include "md5.h"
 
 
#define ALIGN(x,a) ({ typeof(a) __a = (a); (((x) + __a - 1) & ~(__a - 1)); })
 
 
#define MAX_PARTITIONS 32
 
/** 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;
};
 
/** Firmware layout description */
struct device_info {
const char *id;
const char *vendor;
const char *support_list;
char support_trail;
const char *soft_ver;
const struct flash_partition_entry partitions[MAX_PARTITIONS+1];
const char *first_sysupgrade_partition;
const char *last_sysupgrade_partition;
};
 
/** 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,
};
 
 
/** Firmware layout table */
static struct device_info boards[] = {
/** Firmware layout for the CPE210/220 */
{
.id = "CPE210",
.vendor = "CPE510(TP-LINK|UN|N300-5):1.0\r\n",
.support_list =
"SupportList:\r\n"
"CPE210(TP-LINK|UN|N300-2):1.0\r\n"
"CPE210(TP-LINK|UN|N300-2):1.1\r\n"
"CPE210(TP-LINK|US|N300-2):1.1\r\n"
"CPE210(TP-LINK|EU|N300-2):1.1\r\n"
"CPE220(TP-LINK|UN|N300-2):1.1\r\n"
"CPE220(TP-LINK|US|N300-2):1.1\r\n"
"CPE220(TP-LINK|EU|N300-2):1.1\r\n",
.support_trail = '\xff',
.soft_ver = NULL,
 
.partitions = {
{"fs-uboot", 0x00000, 0x20000},
{"partition-table", 0x20000, 0x02000},
{"default-mac", 0x30000, 0x00020},
{"product-info", 0x31100, 0x00100},
{"signature", 0x32000, 0x00400},
{"os-image", 0x40000, 0x1c0000},
{"file-system", 0x200000, 0x5b0000},
{"soft-version", 0x7b0000, 0x00100},
{"support-list", 0x7b1000, 0x00400},
{"user-config", 0x7c0000, 0x10000},
{"default-config", 0x7d0000, 0x10000},
{"log", 0x7e0000, 0x10000},
{"radio", 0x7f0000, 0x10000},
{NULL, 0, 0}
},
 
.first_sysupgrade_partition = "os-image",
.last_sysupgrade_partition = "support-list",
},
 
/** Firmware layout for the CPE210 V2 */
{
.id = "CPE210V2",
.vendor = "CPE210(TP-LINK|UN|N300-2|00000000):2.0\r\n",
.support_list =
"SupportList:\r\n"
"CPE210(TP-LINK|EU|N300-2|00000000):2.0\r\n"
"CPE210(TP-LINK|EU|N300-2|45550000):2.0\r\n"
"CPE210(TP-LINK|EU|N300-2|55530000):2.0\r\n"
"CPE210(TP-LINK|UN|N300-2|00000000):2.0\r\n"
"CPE210(TP-LINK|UN|N300-2|45550000):2.0\r\n"
"CPE210(TP-LINK|UN|N300-2|55530000):2.0\r\n"
"CPE210(TP-LINK|US|N300-2|55530000):2.0\r\n"
"CPE210(TP-LINK|UN|N300-2):2.0\r\n"
"CPE210(TP-LINK|EU|N300-2):2.0\r\n"
"CPE210(TP-LINK|US|N300-2):2.0\r\n",
.support_trail = '\xff',
.soft_ver = NULL,
 
.partitions = {
{"fs-uboot", 0x00000, 0x20000},
{"partition-table", 0x20000, 0x02000},
{"default-mac", 0x30000, 0x00020},
{"product-info", 0x31100, 0x00100},
{"device-info", 0x31400, 0x00400},
{"signature", 0x32000, 0x00400},
{"device-id", 0x33000, 0x00100},
{"os-image", 0x40000, 0x1c0000},
{"file-system", 0x200000, 0x5b0000},
{"soft-version", 0x7b0000, 0x00100},
{"support-list", 0x7b1000, 0x01000},
{"user-config", 0x7c0000, 0x10000},
{"default-config", 0x7d0000, 0x10000},
{"log", 0x7e0000, 0x10000},
{"radio", 0x7f0000, 0x10000},
{NULL, 0, 0}
},
 
.first_sysupgrade_partition = "os-image",
.last_sysupgrade_partition = "support-list",
},
 
/** Firmware layout for the CPE510/520 */
{
.id = "CPE510",
.vendor = "CPE510(TP-LINK|UN|N300-5):1.0\r\n",
.support_list =
"SupportList:\r\n"
"CPE510(TP-LINK|UN|N300-5):1.0\r\n"
"CPE510(TP-LINK|UN|N300-5):1.1\r\n"
"CPE510(TP-LINK|UN|N300-5):1.1\r\n"
"CPE510(TP-LINK|US|N300-5):1.1\r\n"
"CPE510(TP-LINK|EU|N300-5):1.1\r\n"
"CPE520(TP-LINK|UN|N300-5):1.1\r\n"
"CPE520(TP-LINK|US|N300-5):1.1\r\n"
"CPE520(TP-LINK|EU|N300-5):1.1\r\n",
.support_trail = '\xff',
.soft_ver = NULL,
 
.partitions = {
{"fs-uboot", 0x00000, 0x20000},
{"partition-table", 0x20000, 0x02000},
{"default-mac", 0x30000, 0x00020},
{"product-info", 0x31100, 0x00100},
{"signature", 0x32000, 0x00400},
{"os-image", 0x40000, 0x1c0000},
{"file-system", 0x200000, 0x5b0000},
{"soft-version", 0x7b0000, 0x00100},
{"support-list", 0x7b1000, 0x00400},
{"user-config", 0x7c0000, 0x10000},
{"default-config", 0x7d0000, 0x10000},
{"log", 0x7e0000, 0x10000},
{"radio", 0x7f0000, 0x10000},
{NULL, 0, 0}
},
 
.first_sysupgrade_partition = "os-image",
.last_sysupgrade_partition = "support-list",
},
 
{
.id = "WBS210",
.vendor = "CPE510(TP-LINK|UN|N300-5):1.0\r\n",
.support_list =
"SupportList:\r\n"
"WBS210(TP-LINK|UN|N300-2):1.20\r\n"
"WBS210(TP-LINK|US|N300-2):1.20\r\n"
"WBS210(TP-LINK|EU|N300-2):1.20\r\n",
.support_trail = '\xff',
.soft_ver = NULL,
 
.partitions = {
{"fs-uboot", 0x00000, 0x20000},
{"partition-table", 0x20000, 0x02000},
{"default-mac", 0x30000, 0x00020},
{"product-info", 0x31100, 0x00100},
{"signature", 0x32000, 0x00400},
{"os-image", 0x40000, 0x1c0000},
{"file-system", 0x200000, 0x5b0000},
{"soft-version", 0x7b0000, 0x00100},
{"support-list", 0x7b1000, 0x00400},
{"user-config", 0x7c0000, 0x10000},
{"default-config", 0x7d0000, 0x10000},
{"log", 0x7e0000, 0x10000},
{"radio", 0x7f0000, 0x10000},
{NULL, 0, 0}
},
 
.first_sysupgrade_partition = "os-image",
.last_sysupgrade_partition = "support-list",
},
 
{
.id = "WBS510",
.vendor = "CPE510(TP-LINK|UN|N300-5):1.0\r\n",
.support_list =
"SupportList:\r\n"
"WBS510(TP-LINK|UN|N300-5):1.20\r\n"
"WBS510(TP-LINK|US|N300-5):1.20\r\n"
"WBS510(TP-LINK|EU|N300-5):1.20\r\n",
.support_trail = '\xff',
.soft_ver = NULL,
 
.partitions = {
{"fs-uboot", 0x00000, 0x20000},
{"partition-table", 0x20000, 0x02000},
{"default-mac", 0x30000, 0x00020},
{"product-info", 0x31100, 0x00100},
{"signature", 0x32000, 0x00400},
{"os-image", 0x40000, 0x1c0000},
{"file-system", 0x200000, 0x5b0000},
{"soft-version", 0x7b0000, 0x00100},
{"support-list", 0x7b1000, 0x00400},
{"user-config", 0x7c0000, 0x10000},
{"default-config", 0x7d0000, 0x10000},
{"log", 0x7e0000, 0x10000},
{"radio", 0x7f0000, 0x10000},
{NULL, 0, 0}
},
 
.first_sysupgrade_partition = "os-image",
.last_sysupgrade_partition = "support-list",
},
 
/** Firmware layout for the C2600 */
{
.id = "C2600",
.vendor = "",
.support_list =
"SupportList:\r\n"
"{product_name:Archer C2600,product_ver:1.0.0,special_id:00000000}\r\n",
.support_trail = '\x00',
.soft_ver = NULL,
 
/**
We use a bigger os-image partition than the stock images (and thus
smaller file-system), as our kernel doesn't fit in the stock firmware's
2 MB os-image since kernel 4.14.
*/
.partitions = {
{"SBL1", 0x00000, 0x20000},
{"MIBIB", 0x20000, 0x20000},
{"SBL2", 0x40000, 0x20000},
{"SBL3", 0x60000, 0x30000},
{"DDRCONFIG", 0x90000, 0x10000},
{"SSD", 0xa0000, 0x10000},
{"TZ", 0xb0000, 0x30000},
{"RPM", 0xe0000, 0x20000},
{"fs-uboot", 0x100000, 0x70000},
{"uboot-env", 0x170000, 0x40000},
{"radio", 0x1b0000, 0x40000},
{"os-image", 0x1f0000, 0x400000}, /* Stock: base 0x1f0000 size 0x200000 */
{"file-system", 0x5f0000, 0x1900000}, /* Stock: base 0x3f0000 size 0x1b00000 */
{"default-mac", 0x1ef0000, 0x00200},
{"pin", 0x1ef0200, 0x00200},
{"product-info", 0x1ef0400, 0x0fc00},
{"partition-table", 0x1f00000, 0x10000},
{"soft-version", 0x1f10000, 0x10000},
{"support-list", 0x1f20000, 0x10000},
{"profile", 0x1f30000, 0x10000},
{"default-config", 0x1f40000, 0x10000},
{"user-config", 0x1f50000, 0x40000},
{"qos-db", 0x1f90000, 0x40000},
{"usb-config", 0x1fd0000, 0x10000},
{"log", 0x1fe0000, 0x20000},
{NULL, 0, 0}
},
 
.first_sysupgrade_partition = "os-image",
.last_sysupgrade_partition = "file-system"
},
 
/** Firmware layout for the C25v1 */
{
.id = "ARCHER-C25-V1",
.support_list =
"SupportList:\n"
"{product_name:ArcherC25,product_ver:1.0.0,special_id:00000000}\n"
"{product_name:ArcherC25,product_ver:1.0.0,special_id:55530000}\n"
"{product_name:ArcherC25,product_ver:1.0.0,special_id:45550000}\n",
.support_trail = '\x00',
.soft_ver = "soft_ver:1.0.0\n",
 
/**
We use a bigger os-image partition than the stock images (and thus
smaller file-system), as our kernel doesn't fit in the stock firmware's
1MB os-image.
*/
.partitions = {
{"factory-boot", 0x00000, 0x20000},
{"fs-uboot", 0x20000, 0x10000},
{"os-image", 0x30000, 0x180000}, /* Stock: base 0x30000 size 0x100000 */
{"file-system", 0x1b0000, 0x620000}, /* Stock: base 0x130000 size 0x6a0000 */
{"user-config", 0x7d0000, 0x04000},
{"default-mac", 0x7e0000, 0x00100},
{"device-id", 0x7e0100, 0x00100},
{"extra-para", 0x7e0200, 0x00100},
{"pin", 0x7e0300, 0x00100},
{"support-list", 0x7e0400, 0x00400},
{"soft-version", 0x7e0800, 0x00400},
{"product-info", 0x7e0c00, 0x01400},
{"partition-table", 0x7e2000, 0x01000},
{"profile", 0x7e3000, 0x01000},
{"default-config", 0x7e4000, 0x04000},
{"merge-config", 0x7ec000, 0x02000},
{"qos-db", 0x7ee000, 0x02000},
{"radio", 0x7f0000, 0x10000},
{NULL, 0, 0}
},
 
.first_sysupgrade_partition = "os-image",
.last_sysupgrade_partition = "file-system",
},
 
/** Firmware layout for the C58v1 */
{
.id = "ARCHER-C58-V1",
.vendor = "",
.support_list =
"SupportList:\r\n"
"{product_name:Archer C58,product_ver:1.0.0,special_id:00000000}\r\n"
"{product_name:Archer C58,product_ver:1.0.0,special_id:45550000}\r\n"
"{product_name:Archer C58,product_ver:1.0.0,special_id:55530000}\r\n",
.support_trail = '\x00',
.soft_ver = "soft_ver:1.0.0\n",
 
.partitions = {
{"fs-uboot", 0x00000, 0x10000},
{"default-mac", 0x10000, 0x00200},
{"pin", 0x10200, 0x00200},
{"product-info", 0x10400, 0x00100},
{"partition-table", 0x10500, 0x00800},
{"soft-version", 0x11300, 0x00200},
{"support-list", 0x11500, 0x00100},
{"device-id", 0x11600, 0x00100},
{"profile", 0x11700, 0x03900},
{"default-config", 0x15000, 0x04000},
{"user-config", 0x19000, 0x04000},
{"os-image", 0x20000, 0x180000},
{"file-system", 0x1a0000, 0x648000},
{"certyficate", 0x7e8000, 0x08000},
{"radio", 0x7f0000, 0x10000},
{NULL, 0, 0}
},
 
.first_sysupgrade_partition = "os-image",
.last_sysupgrade_partition = "file-system",
},
 
/** Firmware layout for the C59v1 */
{
.id = "ARCHER-C59-V1",
.vendor = "",
.support_list =
"SupportList:\r\n"
"{product_name:Archer C59,product_ver:1.0.0,special_id:00000000}\r\n"
"{product_name:Archer C59,product_ver:1.0.0,special_id:45550000}\r\n"
"{product_name:Archer C59,product_ver:1.0.0,special_id:52550000}\r\n"
"{product_name:Archer C59,product_ver:1.0.0,special_id:55530000}\r\n",
.support_trail = '\x00',
.soft_ver = "soft_ver:1.0.0\n",
 
.partitions = {
{"fs-uboot", 0x00000, 0x10000},
{"default-mac", 0x10000, 0x00200},
{"pin", 0x10200, 0x00200},
{"device-id", 0x10400, 0x00100},
{"product-info", 0x10500, 0x0fb00},
{"os-image", 0x20000, 0x180000},
{"file-system", 0x1a0000, 0xcb0000},
{"partition-table", 0xe50000, 0x10000},
{"soft-version", 0xe60000, 0x10000},
{"support-list", 0xe70000, 0x10000},
{"profile", 0xe80000, 0x10000},
{"default-config", 0xe90000, 0x10000},
{"user-config", 0xea0000, 0x40000},
{"usb-config", 0xee0000, 0x10000},
{"certificate", 0xef0000, 0x10000},
{"qos-db", 0xf00000, 0x40000},
{"log", 0xfe0000, 0x10000},
{"radio", 0xff0000, 0x10000},
{NULL, 0, 0}
},
 
.first_sysupgrade_partition = "os-image",
.last_sysupgrade_partition = "file-system",
},
 
/** Firmware layout for the C60v1 */
{
.id = "ARCHER-C60-V1",
.vendor = "",
.support_list =
"SupportList:\r\n"
"{product_name:Archer C60,product_ver:1.0.0,special_id:00000000}\r\n"
"{product_name:Archer C60,product_ver:1.0.0,special_id:45550000}\r\n"
"{product_name:Archer C60,product_ver:1.0.0,special_id:55530000}\r\n",
.support_trail = '\x00',
.soft_ver = "soft_ver:1.0.0\n",
 
.partitions = {
{"fs-uboot", 0x00000, 0x10000},
{"default-mac", 0x10000, 0x00200},
{"pin", 0x10200, 0x00200},
{"product-info", 0x10400, 0x00100},
{"partition-table", 0x10500, 0x00800},
{"soft-version", 0x11300, 0x00200},
{"support-list", 0x11500, 0x00100},
{"device-id", 0x11600, 0x00100},
{"profile", 0x11700, 0x03900},
{"default-config", 0x15000, 0x04000},
{"user-config", 0x19000, 0x04000},
{"os-image", 0x20000, 0x180000},
{"file-system", 0x1a0000, 0x648000},
{"certyficate", 0x7e8000, 0x08000},
{"radio", 0x7f0000, 0x10000},
{NULL, 0, 0}
},
 
.first_sysupgrade_partition = "os-image",
.last_sysupgrade_partition = "file-system",
},
 
/** Firmware layout for the C60v2 */
{
.id = "ARCHER-C60-V2",
.vendor = "",
.support_list =
"SupportList:\r\n"
"{product_name:Archer C60,product_ver:2.0.0,special_id:42520000}\r\n"
"{product_name:Archer C60,product_ver:2.0.0,special_id:45550000}\r\n"
"{product_name:Archer C60,product_ver:2.0.0,special_id:55530000}\r\n",
.support_trail = '\x00',
.soft_ver = "soft_ver:2.0.0\n",
 
.partitions = {
{"factory-boot", 0x00000, 0x1fb00},
{"default-mac", 0x1fb00, 0x00200},
{"pin", 0x1fd00, 0x00100},
{"product-info", 0x1fe00, 0x00100},
{"device-id", 0x1ff00, 0x00100},
{"fs-uboot", 0x20000, 0x10000},
{"os-image", 0x30000, 0x180000},
{"file-system", 0x1b0000, 0x620000},
{"soft-version", 0x7d9500, 0x00100},
{"support-list", 0x7d9600, 0x00100},
{"extra-para", 0x7d9700, 0x00100},
{"profile", 0x7d9800, 0x03000},
{"default-config", 0x7dc800, 0x03000},
{"partition-table", 0x7df800, 0x00800},
{"user-config", 0x7e0000, 0x0c000},
{"certificate", 0x7ec000, 0x04000},
{"radio", 0x7f0000, 0x10000},
{NULL, 0, 0}
},
 
.first_sysupgrade_partition = "os-image",
.last_sysupgrade_partition = "file-system",
},
 
/** Firmware layout for the C5 */
{
.id = "ARCHER-C5-V2",
.vendor = "",
.support_list =
"SupportList:\r\n"
"{product_name:ArcherC5,product_ver:2.0.0,special_id:00000000}\r\n"
"{product_name:ArcherC5,product_ver:2.0.0,special_id:55530000}\r\n"
"{product_name:ArcherC5,product_ver:2.0.0,special_id:4A500000}\r\n", /* JP version */
.support_trail = '\x00',
.soft_ver = NULL,
 
.partitions = {
{"fs-uboot", 0x00000, 0x40000},
{"os-image", 0x40000, 0x200000},
{"file-system", 0x240000, 0xc00000},
{"default-mac", 0xe40000, 0x00200},
{"pin", 0xe40200, 0x00200},
{"product-info", 0xe40400, 0x00200},
{"partition-table", 0xe50000, 0x10000},
{"soft-version", 0xe60000, 0x00200},
{"support-list", 0xe61000, 0x0f000},
{"profile", 0xe70000, 0x10000},
{"default-config", 0xe80000, 0x10000},
{"user-config", 0xe90000, 0x50000},
{"log", 0xee0000, 0x100000},
{"radio_bk", 0xfe0000, 0x10000},
{"radio", 0xff0000, 0x10000},
{NULL, 0, 0}
},
 
.first_sysupgrade_partition = "os-image",
.last_sysupgrade_partition = "file-system"
},
 
/** Firmware layout for the C7 */
{
.id = "ARCHER-C7-V4",
.support_list =
"SupportList:\n"
"{product_name:Archer C7,product_ver:4.0.0,special_id:00000000}\n"
"{product_name:Archer C7,product_ver:4.0.0,special_id:41550000}\n"
"{product_name:Archer C7,product_ver:4.0.0,special_id:45550000}\n"
"{product_name:Archer C7,product_ver:4.0.0,special_id:4B520000}\n"
"{product_name:Archer C7,product_ver:4.0.0,special_id:42520000}\n"
"{product_name:Archer C7,product_ver:4.0.0,special_id:4A500000}\n"
"{product_name:Archer C7,product_ver:4.0.0,special_id:52550000}\n"
"{product_name:Archer C7,product_ver:4.0.0,special_id:54570000}\n"
"{product_name:Archer C7,product_ver:4.0.0,special_id:55530000}\n"
"{product_name:Archer C7,product_ver:4.0.0,special_id:43410000}\n",
.support_trail = '\x00',
.soft_ver = "soft_ver:1.0.0\n",
 
/**
We use a bigger os-image partition than the stock images (and thus
smaller file-system), as our kernel doesn't fit in the stock firmware's
1MB os-image.
*/
.partitions = {
{"factory-boot", 0x00000, 0x20000},
{"fs-uboot", 0x20000, 0x20000},
{"os-image", 0x40000, 0x180000}, /* Stock: base 0x40000 size 0x120000 */
{"file-system", 0x1c0000, 0xd40000}, /* Stock: base 0x160000 size 0xda0000 */
{"default-mac", 0xf00000, 0x00200},
{"pin", 0xf00200, 0x00200},
{"device-id", 0xf00400, 0x00100},
{"product-info", 0xf00500, 0x0fb00},
{"soft-version", 0xf10000, 0x00100},
{"extra-para", 0xf11000, 0x01000},
{"support-list", 0xf12000, 0x0a000},
{"profile", 0xf1c000, 0x04000},
{"default-config", 0xf20000, 0x10000},
{"user-config", 0xf30000, 0x40000},
{"qos-db", 0xf70000, 0x40000},
{"certificate", 0xfb0000, 0x10000},
{"partition-table", 0xfc0000, 0x10000},
{"log", 0xfd0000, 0x20000},
{"radio", 0xff0000, 0x10000},
{NULL, 0, 0}
},
 
.first_sysupgrade_partition = "os-image",
.last_sysupgrade_partition = "file-system",
},
 
/** Firmware layout for the C7 v5*/
{
.id = "ARCHER-C7-V5",
.support_list =
"SupportList:\n"
"{product_name:Archer C7,product_ver:5.0.0,special_id:00000000}\n"
"{product_name:Archer C7,product_ver:5.0.0,special_id:55530000}\n",
 
.support_trail = '\x00',
.soft_ver = "soft_ver:1.0.0\n",
 
/**
We use a bigger os-image partition than the stock images (and thus
smaller file-system), as our kernel doesn't fit in the stock firmware's
1MB os-image.
*/
.partitions = {
{"factory-boot", 0x00000, 0x20000},
{"fs-uboot", 0x20000, 0x20000},
{"partition-table", 0x40000, 0x10000},
{"radio", 0x50000, 0x10000},
{"default-mac", 0x60000, 0x00200},
{"pin", 0x60200, 0x00200},
{"device-id", 0x60400, 0x00100},
{"product-info", 0x60500, 0x0fb00},
{"soft-version", 0x70000, 0x01000},
{"extra-para", 0x71000, 0x01000},
{"support-list", 0x72000, 0x0a000},
{"profile", 0x7c000, 0x04000},
{"user-config", 0x80000, 0x40000},
 
 
{"os-image", 0xc0000, 0x180000}, /* Stock: base 0xc0000 size 0x120000 */
{"file-system", 0x240000, 0xd80000}, /* Stock: base 0x1e0000 size 0xde0000 */
 
{"log", 0xfc0000, 0x20000},
{"certificate", 0xfe0000, 0x10000},
{"default-config", 0xff0000, 0x10000},
{NULL, 0, 0}
 
},
 
.first_sysupgrade_partition = "os-image",
.last_sysupgrade_partition = "file-system",
},
 
/** Firmware layout for the C9 */
{
.id = "ARCHERC9",
.vendor = "",
.support_list =
"SupportList:\n"
"{product_name:ArcherC9,"
"product_ver:1.0.0,"
"special_id:00000000}\n",
.support_trail = '\x00',
.soft_ver = NULL,
 
.partitions = {
{"fs-uboot", 0x00000, 0x40000},
{"os-image", 0x40000, 0x200000},
{"file-system", 0x240000, 0xc00000},
{"default-mac", 0xe40000, 0x00200},
{"pin", 0xe40200, 0x00200},
{"product-info", 0xe40400, 0x00200},
{"partition-table", 0xe50000, 0x10000},
{"soft-version", 0xe60000, 0x00200},
{"support-list", 0xe61000, 0x0f000},
{"profile", 0xe70000, 0x10000},
{"default-config", 0xe80000, 0x10000},
{"user-config", 0xe90000, 0x50000},
{"log", 0xee0000, 0x100000},
{"radio_bk", 0xfe0000, 0x10000},
{"radio", 0xff0000, 0x10000},
{NULL, 0, 0}
},
 
.first_sysupgrade_partition = "os-image",
.last_sysupgrade_partition = "file-system"
},
 
/** Firmware layout for the EAP120 */
{
.id = "EAP120",
.vendor = "EAP120(TP-LINK|UN|N300-2):1.0\r\n",
.support_list =
"SupportList:\r\n"
"EAP120(TP-LINK|UN|N300-2):1.0\r\n",
.support_trail = '\xff',
.soft_ver = NULL,
 
.partitions = {
{"fs-uboot", 0x00000, 0x20000},
{"partition-table", 0x20000, 0x02000},
{"default-mac", 0x30000, 0x00020},
{"support-list", 0x31000, 0x00100},
{"product-info", 0x31100, 0x00100},
{"soft-version", 0x32000, 0x00100},
{"os-image", 0x40000, 0x180000},
{"file-system", 0x1c0000, 0x600000},
{"user-config", 0x7c0000, 0x10000},
{"backup-config", 0x7d0000, 0x10000},
{"log", 0x7e0000, 0x10000},
{"radio", 0x7f0000, 0x10000},
{NULL, 0, 0}
},
 
.first_sysupgrade_partition = "os-image",
.last_sysupgrade_partition = "file-system"
},
 
/** Firmware layout for the TL-WA850RE v2 */
{
.id = "TLWA850REV2",
.vendor = "",
.support_list =
"SupportList:\n"
"{product_name:TL-WA850RE,product_ver:2.0.0,special_id:55530000}\n"
"{product_name:TL-WA850RE,product_ver:2.0.0,special_id:00000000}\n"
"{product_name:TL-WA850RE,product_ver:2.0.0,special_id:55534100}\n"
"{product_name:TL-WA850RE,product_ver:2.0.0,special_id:45550000}\n"
"{product_name:TL-WA850RE,product_ver:2.0.0,special_id:4B520000}\n"
"{product_name:TL-WA850RE,product_ver:2.0.0,special_id:42520000}\n"
"{product_name:TL-WA850RE,product_ver:2.0.0,special_id:4A500000}\n"
"{product_name:TL-WA850RE,product_ver:2.0.0,special_id:43410000}\n"
"{product_name:TL-WA850RE,product_ver:2.0.0,special_id:41550000}\n"
"{product_name:TL-WA850RE,product_ver:2.0.0,special_id:52550000}\n",
.support_trail = '\x00',
.soft_ver = NULL,
 
/**
576KB were moved from file-system to os-image
in comparison to the stock image
*/
.partitions = {
{"fs-uboot", 0x00000, 0x20000},
{"os-image", 0x20000, 0x150000},
{"file-system", 0x170000, 0x240000},
{"partition-table", 0x3b0000, 0x02000},
{"default-mac", 0x3c0000, 0x00020},
{"pin", 0x3c0100, 0x00020},
{"product-info", 0x3c1000, 0x01000},
{"soft-version", 0x3c2000, 0x00100},
{"support-list", 0x3c3000, 0x01000},
{"profile", 0x3c4000, 0x08000},
{"user-config", 0x3d0000, 0x10000},
{"default-config", 0x3e0000, 0x10000},
{"radio", 0x3f0000, 0x10000},
{NULL, 0, 0}
},
 
.first_sysupgrade_partition = "os-image",
.last_sysupgrade_partition = "file-system"
},
 
/** Firmware layout for the TL-WA855RE v1 */
{
.id = "TLWA855REV1",
.vendor = "",
.support_list =
"SupportList:\n"
"{product_name:TL-WA855RE,product_ver:1.0.0,special_id:00000000}\n"
"{product_name:TL-WA855RE,product_ver:1.0.0,special_id:55530000}\n"
"{product_name:TL-WA855RE,product_ver:1.0.0,special_id:45550000}\n"
"{product_name:TL-WA855RE,product_ver:1.0.0,special_id:4B520000}\n"
"{product_name:TL-WA855RE,product_ver:1.0.0,special_id:42520000}\n"
"{product_name:TL-WA855RE,product_ver:1.0.0,special_id:4A500000}\n"
"{product_name:TL-WA855RE,product_ver:1.0.0,special_id:43410000}\n"
"{product_name:TL-WA855RE,product_ver:1.0.0,special_id:41550000}\n"
"{product_name:TL-WA855RE,product_ver:1.0.0,special_id:52550000}\n",
.support_trail = '\x00',
.soft_ver = NULL,
 
.partitions = {
{"fs-uboot", 0x00000, 0x20000},
{"os-image", 0x20000, 0x150000},
{"file-system", 0x170000, 0x240000},
{"partition-table", 0x3b0000, 0x02000},
{"default-mac", 0x3c0000, 0x00020},
{"pin", 0x3c0100, 0x00020},
{"product-info", 0x3c1000, 0x01000},
{"soft-version", 0x3c2000, 0x00100},
{"support-list", 0x3c3000, 0x01000},
{"profile", 0x3c4000, 0x08000},
{"user-config", 0x3d0000, 0x10000},
{"default-config", 0x3e0000, 0x10000},
{"radio", 0x3f0000, 0x10000},
{NULL, 0, 0}
},
 
.first_sysupgrade_partition = "os-image",
.last_sysupgrade_partition = "file-system"
},
 
/** Firmware layout for the TL-WR1043 v5 */
{
.id = "TLWR1043NV5",
.vendor = "",
.support_list =
"SupportList:\n"
"{product_name:TL-WR1043N,product_ver:5.0.0,special_id:45550000}\n"
"{product_name:TL-WR1043N,product_ver:5.0.0,special_id:55530000}\n",
.support_trail = '\x00',
.soft_ver = "soft_ver:1.0.0\n",
.partitions = {
{"factory-boot", 0x00000, 0x20000},
{"fs-uboot", 0x20000, 0x20000},
{"os-image", 0x40000, 0x180000},
{"file-system", 0x1c0000, 0xd40000},
{"default-mac", 0xf00000, 0x00200},
{"pin", 0xf00200, 0x00200},
{"device-id", 0xf00400, 0x00100},
{"product-info", 0xf00500, 0x0fb00},
{"soft-version", 0xf10000, 0x01000},
{"extra-para", 0xf11000, 0x01000},
{"support-list", 0xf12000, 0x0a000},
{"profile", 0xf1c000, 0x04000},
{"default-config", 0xf20000, 0x10000},
{"user-config", 0xf30000, 0x40000},
{"qos-db", 0xf70000, 0x40000},
{"certificate", 0xfb0000, 0x10000},
{"partition-table", 0xfc0000, 0x10000},
{"log", 0xfd0000, 0x20000},
{"radio", 0xff0000, 0x10000},
{NULL, 0, 0}
},
.first_sysupgrade_partition = "os-image",
.last_sysupgrade_partition = "file-system"
},
 
/** Firmware layout for the TL-WR1043 v4 */
{
.id = "TLWR1043NDV4",
.vendor = "",
.support_list =
"SupportList:\n"
"{product_name:TL-WR1043ND,product_ver:4.0.0,special_id:45550000}\n",
.support_trail = '\x00',
.soft_ver = NULL,
 
/**
We use a bigger os-image partition than the stock images (and thus
smaller file-system), as our kernel doesn't fit in the stock firmware's
1MB os-image.
*/
.partitions = {
{"fs-uboot", 0x00000, 0x20000},
{"os-image", 0x20000, 0x180000},
{"file-system", 0x1a0000, 0xdb0000},
{"default-mac", 0xf50000, 0x00200},
{"pin", 0xf50200, 0x00200},
{"product-info", 0xf50400, 0x0fc00},
{"soft-version", 0xf60000, 0x0b000},
{"support-list", 0xf6b000, 0x04000},
{"profile", 0xf70000, 0x04000},
{"default-config", 0xf74000, 0x0b000},
{"user-config", 0xf80000, 0x40000},
{"partition-table", 0xfc0000, 0x10000},
{"log", 0xfd0000, 0x20000},
{"radio", 0xff0000, 0x10000},
{NULL, 0, 0}
},
 
.first_sysupgrade_partition = "os-image",
.last_sysupgrade_partition = "file-system"
},
 
/** Firmware layout for the TL-WR902AC v1 */
{
.id = "TL-WR902AC-V1",
.vendor = "",
.support_list =
"SupportList:\n"
"{product_name:TL-WR902AC,product_ver:1.0.0,special_id:45550000}\n"
"{product_name:TL-WR902AC,product_ver:1.0.0,special_id:55530000}\n",
.support_trail = '\x00',
.soft_ver = NULL,
 
/**
384KB were moved from file-system to os-image
in comparison to the stock image
*/
.partitions = {
{"fs-uboot", 0x00000, 0x20000},
{"os-image", 0x20000, 0x180000},
{"file-system", 0x1a0000, 0x5b0000},
{"default-mac", 0x750000, 0x00200},
{"pin", 0x750200, 0x00200},
{"product-info", 0x750400, 0x0fc00},
{"soft-version", 0x760000, 0x0b000},
{"support-list", 0x76b000, 0x04000},
{"profile", 0x770000, 0x04000},
{"default-config", 0x774000, 0x0b000},
{"user-config", 0x780000, 0x40000},
{"partition-table", 0x7c0000, 0x10000},
{"log", 0x7d0000, 0x20000},
{"radio", 0x7f0000, 0x10000},
{NULL, 0, 0}
},
 
.first_sysupgrade_partition = "os-image",
.last_sysupgrade_partition = "file-system",
},
 
/** Firmware layout for the TL-WR942N V1 */
{
.id = "TLWR942NV1",
.vendor = "",
.support_list =
"SupportList:\r\n"
"{product_name:TL-WR942N,product_ver:1.0.0,special_id:00000000}\r\n"
"{product_name:TL-WR942N,product_ver:1.0.0,special_id:52550000}\r\n",
.support_trail = '\x00',
.soft_ver = NULL,
 
.partitions = {
{"fs-uboot", 0x00000, 0x20000},
{"os-image", 0x20000, 0x180000},
{"file-system", 0x1a0000, 0xca0000},
{"default-mac", 0xe40000, 0x00200},
{"pin", 0xe40200, 0x00200},
{"product-info", 0xe40400, 0x0fc00},
{"partition-table", 0xe50000, 0x10000},
{"soft-version", 0xe60000, 0x10000},
{"support-list", 0xe70000, 0x10000},
{"profile", 0xe80000, 0x10000},
{"default-config", 0xe90000, 0x10000},
{"user-config", 0xea0000, 0x40000},
{"qos-db", 0xee0000, 0x40000},
{"certificate", 0xf20000, 0x10000},
{"usb-config", 0xfb0000, 0x10000},
{"log", 0xfc0000, 0x20000},
{"radio-bk", 0xfe0000, 0x10000},
{"radio", 0xff0000, 0x10000},
{NULL, 0, 0}
},
 
.first_sysupgrade_partition = "os-image",
.last_sysupgrade_partition = "file-system",
},
 
/** Firmware layout for the RE350 v1 */
{
.id = "RE350-V1",
.vendor = "",
.support_list =
"SupportList:\n"
"{product_name:RE350,product_ver:1.0.0,special_id:45550000}\n"
"{product_name:RE350,product_ver:1.0.0,special_id:00000000}\n"
"{product_name:RE350,product_ver:1.0.0,special_id:41550000}\n"
"{product_name:RE350,product_ver:1.0.0,special_id:55530000}\n"
"{product_name:RE350,product_ver:1.0.0,special_id:43410000}\n"
"{product_name:RE350,product_ver:1.0.0,special_id:4b520000}\n"
"{product_name:RE350,product_ver:1.0.0,special_id:4a500000}\n",
.support_trail = '\x00',
.soft_ver = NULL,
 
/**
The original os-image partition is too small,
so we enlarge it to 1.75M
*/
.partitions = {
{"fs-uboot", 0x00000, 0x20000},
{"os-image", 0x20000, 0x1c0000},
{"file-system", 0x1e0000, 0x420000},
{"partition-table", 0x600000, 0x02000},
{"default-mac", 0x610000, 0x00020},
{"pin", 0x610100, 0x00020},
{"product-info", 0x611100, 0x01000},
{"soft-version", 0x620000, 0x01000},
{"support-list", 0x621000, 0x01000},
{"profile", 0x622000, 0x08000},
{"user-config", 0x630000, 0x10000},
{"default-config", 0x640000, 0x10000},
{"radio", 0x7f0000, 0x10000},
{NULL, 0, 0}
},
 
.first_sysupgrade_partition = "os-image",
.last_sysupgrade_partition = "file-system"
},
 
/** Firmware layout for the RE355 */
{
.id = "RE355",
.vendor = "",
.support_list =
"SupportList:\r\n"
"{product_name:RE355,product_ver:1.0.0,special_id:00000000}\r\n"
"{product_name:RE355,product_ver:1.0.0,special_id:55530000}\r\n"
"{product_name:RE355,product_ver:1.0.0,special_id:45550000}\r\n"
"{product_name:RE355,product_ver:1.0.0,special_id:4A500000}\r\n"
"{product_name:RE355,product_ver:1.0.0,special_id:43410000}\r\n"
"{product_name:RE355,product_ver:1.0.0,special_id:41550000}\r\n"
"{product_name:RE355,product_ver:1.0.0,special_id:4B520000}\r\n"
"{product_name:RE355,product_ver:1.0.0,special_id:55534100}\r\n",
.support_trail = '\x00',
.soft_ver = NULL,
 
/**
The flash partition table for RE355;
it is almost the same as the one used by the stock images,
576KB were moved from file-system to os-image.
*/
.partitions = {
{"fs-uboot", 0x00000, 0x20000},
{"os-image", 0x20000, 0x180000},
{"file-system", 0x1a0000, 0x460000},
{"partition-table", 0x600000, 0x02000},
{"default-mac", 0x610000, 0x00020},
{"pin", 0x610100, 0x00020},
{"product-info", 0x611100, 0x01000},
{"soft-version", 0x620000, 0x01000},
{"support-list", 0x621000, 0x01000},
{"profile", 0x622000, 0x08000},
{"user-config", 0x630000, 0x10000},
{"default-config", 0x640000, 0x10000},
{"radio", 0x7f0000, 0x10000},
{NULL, 0, 0}
},
 
.first_sysupgrade_partition = "os-image",
.last_sysupgrade_partition = "file-system"
},
 
/** Firmware layout for the RE450 */
{
.id = "RE450",
.vendor = "",
.support_list =
"SupportList:\r\n"
"{product_name:RE450,product_ver:1.0.0,special_id:00000000}\r\n"
"{product_name:RE450,product_ver:1.0.0,special_id:55530000}\r\n"
"{product_name:RE450,product_ver:1.0.0,special_id:45550000}\r\n"
"{product_name:RE450,product_ver:1.0.0,special_id:4A500000}\r\n"
"{product_name:RE450,product_ver:1.0.0,special_id:43410000}\r\n"
"{product_name:RE450,product_ver:1.0.0,special_id:41550000}\r\n"
"{product_name:RE450,product_ver:1.0.0,special_id:4B520000}\r\n"
"{product_name:RE450,product_ver:1.0.0,special_id:55534100}\r\n",
.support_trail = '\x00',
.soft_ver = NULL,
 
/**
The flash partition table for RE450;
it is almost the same as the one used by the stock images,
576KB were moved from file-system to os-image.
*/
.partitions = {
{"fs-uboot", 0x00000, 0x20000},
{"os-image", 0x20000, 0x180000},
{"file-system", 0x1a0000, 0x460000},
{"partition-table", 0x600000, 0x02000},
{"default-mac", 0x610000, 0x00020},
{"pin", 0x610100, 0x00020},
{"product-info", 0x611100, 0x01000},
{"soft-version", 0x620000, 0x01000},
{"support-list", 0x621000, 0x01000},
{"profile", 0x622000, 0x08000},
{"user-config", 0x630000, 0x10000},
{"default-config", 0x640000, 0x10000},
{"radio", 0x7f0000, 0x10000},
{NULL, 0, 0}
},
 
.first_sysupgrade_partition = "os-image",
.last_sysupgrade_partition = "file-system"
},
 
{}
};
 
#define error(_ret, _errno, _str, ...) \
do { \
fprintf(stderr, _str ": %s\n", ## __VA_ARGS__, \
strerror(_errno)); \
if (_ret) \
exit(_ret); \
} while (0)
 
 
/** Stores a uint32 as big endian */
static inline void put32(uint8_t *buf, uint32_t val) {
buf[0] = val >> 24;
buf[1] = val >> 16;
buf[2] = val >> 8;
buf[3] = val;
}
 
/** Allocates a new image partition */
static 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 */
static void free_image_partition(struct image_partition_entry entry) {
free(entry.data);
}
 
static time_t source_date_epoch = -1;
static void set_source_date_epoch() {
char *env = getenv("SOURCE_DATE_EPOCH");
char *endptr = env;
errno = 0;
if (env && *env) {
source_date_epoch = strtoull(env, &endptr, 10);
if (errno || (endptr && *endptr != '\0')) {
fprintf(stderr, "Invalid SOURCE_DATE_EPOCH");
exit(1);
}
}
}
 
/** Generates the partition-table partition */
static 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 */
static 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 (source_date_epoch != -1)
t = source_date_epoch;
else 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;
}
 
static struct image_partition_entry make_soft_version_from_string(const char *soft_ver) {
/** String length _including_ the terminating zero byte */
uint32_t ver_len = strlen(soft_ver) + 1;
/** Partition contains 64 bit header, the version string, and one additional null byte */
size_t partition_len = 2*sizeof(uint32_t) + ver_len + 1;
struct image_partition_entry entry = alloc_image_partition("soft-version", partition_len);
 
uint32_t *len = (uint32_t *)entry.data;
len[0] = htonl(ver_len);
len[1] = 0;
memcpy(&len[2], soft_ver, ver_len);
 
entry.data[partition_len - 1] = 0;
 
return entry;
}
 
/** Generates the support-list partition */
static struct image_partition_entry make_support_list(const struct device_info *info) {
size_t len = strlen(info->support_list);
struct image_partition_entry entry = alloc_image_partition("support-list", len + 9);
 
put32(entry.data, len);
memset(entry.data+4, 0, 4);
memcpy(entry.data+8, info->support_list, len);
entry.data[len+8] = info->support_trail;
 
return entry;
}
 
/** Creates a new image partition with an arbitrary name from a file */
static 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;
}
 
/** Creates a new image partition from arbitrary data */
static struct image_partition_entry put_data(const char *part_name, const char *datain, size_t len) {
 
struct image_partition_entry entry = alloc_image_partition(part_name, len);
 
memcpy(entry.data, datain, len);
 
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.
*/
static void put_partitions(uint8_t *buffer, const struct flash_partition_entry *flash_parts, const struct image_partition_entry *parts) {
size_t i, j;
char *image_pt = (char *)buffer, *end = image_pt + 0x800;
 
size_t base = 0x800;
for (i = 0; parts[i].name; i++) {
for (j = 0; flash_parts[j].name; j++) {
if (!strcmp(flash_parts[j].name, parts[i].name)) {
if (parts[i].size > flash_parts[j].size)
error(1, 0, "%s partition too big (more than %u bytes)", flash_parts[j].name, (unsigned)flash_parts[j].size);
break;
}
}
 
assert(flash_parts[j].name);
 
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;
}
}
 
/** Generates and writes the image MD5 checksum */
static 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-0017 Vendor information length (without padding) (4 bytes, big endian)
0018-1013 Vendor information (4092 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
*/
static void * generate_factory_image(const struct device_info *info, 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");
 
memset(image, 0xff, *len);
put32(image, *len);
 
if (info->vendor) {
size_t vendor_len = strlen(info->vendor);
put32(image+0x14, vendor_len);
memcpy(image+0x18, info->vendor, vendor_len);
}
 
put_partitions(image + 0x1014, info->partitions, 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.
*/
static void * generate_sysupgrade_image(const struct device_info *info, const struct image_partition_entry *image_parts, size_t *len) {
size_t i, j;
size_t flash_first_partition_index = 0;
size_t flash_last_partition_index = 0;
const struct flash_partition_entry *flash_first_partition = NULL;
const struct flash_partition_entry *flash_last_partition = NULL;
const struct image_partition_entry *image_last_partition = NULL;
 
/** Find first and last partitions */
for (i = 0; info->partitions[i].name; i++) {
if (!strcmp(info->partitions[i].name, info->first_sysupgrade_partition)) {
flash_first_partition = &info->partitions[i];
flash_first_partition_index = i;
} else if (!strcmp(info->partitions[i].name, info->last_sysupgrade_partition)) {
flash_last_partition = &info->partitions[i];
flash_last_partition_index = i;
}
}
 
assert(flash_first_partition && flash_last_partition);
assert(flash_first_partition_index < flash_last_partition_index);
 
/** Find last partition from image to calculate needed size */
for (i = 0; image_parts[i].name; i++) {
if (!strcmp(image_parts[i].name, info->last_sysupgrade_partition)) {
image_last_partition = &image_parts[i];
break;
}
}
 
assert(image_last_partition);
 
*len = flash_last_partition->base - flash_first_partition->base + image_last_partition->size;
 
uint8_t *image = malloc(*len);
if (!image)
error(1, errno, "malloc");
 
memset(image, 0xff, *len);
 
for (i = flash_first_partition_index; i <= flash_last_partition_index; i++) {
for (j = 0; image_parts[j].name; j++) {
if (!strcmp(info->partitions[i].name, image_parts[j].name)) {
if (image_parts[j].size > info->partitions[i].size)
error(1, 0, "%s partition too big (more than %u bytes)", info->partitions[i].name, (unsigned)info->partitions[i].size);
memcpy(image + info->partitions[i].base - flash_first_partition->base, image_parts[j].data, image_parts[j].size);
break;
}
 
assert(image_parts[j].name);
}
}
 
return image;
}
 
/** Generates an image according to a given layout and writes it to a file */
static void build_image(const char *output,
const char *kernel_image,
const char *rootfs_image,
uint32_t rev,
bool add_jffs2_eof,
bool sysupgrade,
const struct device_info *info) {
 
struct image_partition_entry parts[7] = {};
 
parts[0] = make_partition_table(info->partitions);
if (info->soft_ver)
parts[1] = make_soft_version_from_string(info->soft_ver);
else
parts[1] = make_soft_version(rev);
 
parts[2] = make_support_list(info);
parts[3] = read_file("os-image", kernel_image, false);
parts[4] = read_file("file-system", rootfs_image, add_jffs2_eof);
 
/* Some devices need the extra-para partition to accept the firmware */
if (strcasecmp(info->id, "ARCHER-C25-V1") == 0 ||
strcasecmp(info->id, "ARCHER-C60-V2") == 0 ||
strcasecmp(info->id, "TLWR1043NV5") == 0) {
const char mdat[11] = {0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00};
parts[5] = put_data("extra-para", mdat, 11);
} else if (strcasecmp(info->id, "ARCHER-C7-V4") == 0 || strcasecmp(info->id, "ARCHER-C7-V5") == 0) {
const char mdat[11] = {0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0xca, 0x00, 0x01, 0x00, 0x00};
parts[5] = put_data("extra-para", mdat, 11);
}
 
size_t len;
void *image;
if (sysupgrade)
image = generate_sysupgrade_image(info, parts, &len);
else
image = generate_factory_image(info, 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 */
static void usage(const char *argv0) {
fprintf(stderr,
"Usage: %s [OPTIONS...]\n"
"\n"
"Options:\n"
" -h show this help\n"
"\n"
"Create a new image:\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"
"Extract an old image:\n"
" -x <file> extract all oem firmware partition\n"
" -d <dir> destination to extract the firmware partition\n"
" -z <file> convert an oem firmware into a sysupgade file. Use -o for output file\n",
argv0
);
};
 
 
static const struct device_info *find_board(const char *id)
{
struct device_info *board = NULL;
 
for (board = boards; board->id != NULL; board++)
if (strcasecmp(id, board->id) == 0)
return board;
 
return NULL;
}
 
static int add_flash_partition(
struct flash_partition_entry *part_list,
size_t max_entries,
const char *name,
unsigned long base,
unsigned long size)
{
int ptr;
/* check if the list has a free entry */
for (ptr = 0; ptr < max_entries; ptr++, part_list++) {
if (part_list->name == NULL &&
part_list->base == 0 &&
part_list->size == 0)
break;
}
 
if (ptr == max_entries) {
error(1, 0, "No free flash part entry available.");
}
 
part_list->name = calloc(1, strlen(name) + 1);
memcpy((char *)part_list->name, name, strlen(name));
part_list->base = base;
part_list->size = size;
 
return 0;
}
 
/** read the partition table into struct flash_partition_entry */
static int read_partition_table(
FILE *file, long offset,
struct flash_partition_entry *entries, size_t max_entries,
int type)
{
char buf[2048];
char *ptr, *end;
const char *parthdr = NULL;
const char *fwuphdr = "fwup-ptn";
const char *flashhdr = "partition";
 
/* TODO: search for the partition table */
 
switch(type) {
case 0:
parthdr = fwuphdr;
break;
case 1:
parthdr = flashhdr;
break;
default:
error(1, 0, "Invalid partition table");
}
 
if (fseek(file, offset, SEEK_SET) < 0)
error(1, errno, "Can not seek in the firmware");
 
if (fread(buf, 1, 2048, file) < 0)
error(1, errno, "Can not read fwup-ptn from the firmware");
 
buf[2047] = '\0';
 
/* look for the partition header */
if (memcmp(buf, parthdr, strlen(parthdr)) != 0) {
fprintf(stderr, "DEBUG: can not find fwuphdr\n");
return 1;
}
 
ptr = buf;
end = buf + sizeof(buf);
while ((ptr + strlen(parthdr)) < end &&
memcmp(ptr, parthdr, strlen(parthdr)) == 0) {
char *end_part;
char *end_element;
 
char name[32] = { 0 };
int name_len = 0;
unsigned long base = 0;
unsigned long size = 0;
 
end_part = memchr(ptr, '\n', (end - ptr));
if (end_part == NULL) {
/* in theory this should never happen, because a partition always ends with 0x09, 0x0D, 0x0A */
break;
}
 
for (int i = 0; i <= 4; i++) {
if (end_part <= ptr)
break;
 
end_element = memchr(ptr, 0x20, (end_part - ptr));
if (end_element == NULL) {
error(1, errno, "Ignoring the rest of the partition entries.");
break;
}
 
switch (i) {
/* partition header */
case 0:
ptr = end_element + 1;
continue;
/* name */
case 1:
name_len = (end_element - ptr) > 31 ? 31 : (end_element - ptr);
strncpy(name, ptr, name_len);
name[name_len] = '\0';
ptr = end_element + 1;
continue;
 
/* string "base" */
case 2:
ptr = end_element + 1;
continue;
 
/* actual base */
case 3:
base = strtoul(ptr, NULL, 16);
ptr = end_element + 1;
continue;
 
/* string "size" */
case 4:
ptr = end_element + 1;
/* actual size. The last element doesn't have a sepeartor */
size = strtoul(ptr, NULL, 16);
/* the part ends with 0x09, 0x0d, 0x0a */
ptr = end_part + 1;
add_flash_partition(entries, max_entries, name, base, size);
continue;
}
}
}
 
return 0;
}
 
static void write_partition(
FILE *input_file,
size_t firmware_offset,
struct flash_partition_entry *entry,
FILE *output_file)
{
char buf[4096];
size_t offset;
 
fseek(input_file, entry->base + firmware_offset, SEEK_SET);
 
for (offset = 0; sizeof(buf) + offset <= entry->size; offset += sizeof(buf)) {
if (fread(buf, sizeof(buf), 1, input_file) < 0)
error(1, errno, "Can not read partition from input_file");
 
if (fwrite(buf, sizeof(buf), 1, output_file) < 0)
error(1, errno, "Can not write partition to output_file");
}
/* write last chunk smaller than buffer */
if (offset < entry->size) {
offset = entry->size - offset;
if (fread(buf, offset, 1, input_file) < 0)
error(1, errno, "Can not read partition from input_file");
if (fwrite(buf, offset, 1, output_file) < 0)
error(1, errno, "Can not write partition to output_file");
}
}
 
static int extract_firmware_partition(FILE *input_file, size_t firmware_offset, struct flash_partition_entry *entry, const char *output_directory)
{
FILE *output_file;
char output[PATH_MAX];
 
snprintf(output, PATH_MAX, "%s/%s", output_directory, entry->name);
output_file = fopen(output, "wb+");
if (output_file == NULL) {
error(1, errno, "Can not open output file %s", output);
}
 
write_partition(input_file, firmware_offset, entry, output_file);
 
fclose(output_file);
 
return 0;
}
 
/** extract all partitions from the firmware file */
static int extract_firmware(const char *input, const char *output_directory)
{
struct flash_partition_entry entries[16] = { 0 };
size_t max_entries = 16;
size_t firmware_offset = 0x1014;
FILE *input_file;
 
struct stat statbuf;
 
/* check input file */
if (stat(input, &statbuf)) {
error(1, errno, "Can not read input firmware %s", input);
}
 
/* check if output directory exists */
if (stat(output_directory, &statbuf)) {
error(1, errno, "Failed to stat output directory %s", output_directory);
}
 
if ((statbuf.st_mode & S_IFMT) != S_IFDIR) {
error(1, errno, "Given output directory is not a directory %s", output_directory);
}
 
input_file = fopen(input, "rb");
 
if (read_partition_table(input_file, firmware_offset, entries, 16, 0) != 0) {
error(1, 0, "Error can not read the partition table (fwup-ptn)");
}
 
for (int i = 0; i < max_entries; i++) {
if (entries[i].name == NULL &&
entries[i].base == 0 &&
entries[i].size == 0)
continue;
 
extract_firmware_partition(input_file, firmware_offset, &entries[i], output_directory);
}
 
return 0;
}
 
static struct flash_partition_entry *find_partition(
struct flash_partition_entry *entries, size_t max_entries,
const char *name, const char *error_msg)
{
for (int i = 0; i < max_entries; i++, entries++) {
if (strcmp(entries->name, name) == 0)
return entries;
}
 
error(1, 0, "%s", error_msg);
return NULL;
}
 
static void write_ff(FILE *output_file, size_t size)
{
char buf[4096];
int offset;
 
memset(buf, 0xff, sizeof(buf));
 
for (offset = 0; offset + sizeof(buf) < size ; offset += sizeof(buf)) {
if (fwrite(buf, sizeof(buf), 1, output_file) < 0)
error(1, errno, "Can not write 0xff to output_file");
}
 
/* write last chunk smaller than buffer */
if (offset < size) {
offset = size - offset;
if (fwrite(buf, offset, 1, output_file) < 0)
error(1, errno, "Can not write partition to output_file");
}
}
 
static void convert_firmware(const char *input, const char *output)
{
struct flash_partition_entry fwup[MAX_PARTITIONS] = { 0 };
struct flash_partition_entry flash[MAX_PARTITIONS] = { 0 };
struct flash_partition_entry *fwup_os_image = NULL, *fwup_file_system = NULL;
struct flash_partition_entry *flash_os_image = NULL, *flash_file_system = NULL;
struct flash_partition_entry *fwup_partition_table = NULL;
size_t firmware_offset = 0x1014;
FILE *input_file, *output_file;
 
struct stat statbuf;
 
/* check input file */
if (stat(input, &statbuf)) {
error(1, errno, "Can not read input firmware %s", input);
}
 
input_file = fopen(input, "rb");
if (!input_file)
error(1, 0, "Can not open input firmware %s", input);
 
output_file = fopen(output, "wb");
if (!output_file)
error(1, 0, "Can not open output firmware %s", output);
 
if (read_partition_table(input_file, firmware_offset, fwup, MAX_PARTITIONS, 0) != 0) {
error(1, 0, "Error can not read the partition table (fwup-ptn)");
}
 
fwup_os_image = find_partition(fwup, MAX_PARTITIONS,
"os-image", "Error can not find os-image partition (fwup)");
fwup_file_system = find_partition(fwup, MAX_PARTITIONS,
"file-system", "Error can not find file-system partition (fwup)");
fwup_partition_table = find_partition(fwup, MAX_PARTITIONS,
"partition-table", "Error can not find partition-table partition");
 
/* the flash partition table has a 0x00000004 magic haeder */
if (read_partition_table(input_file, firmware_offset + fwup_partition_table->base + 4, flash, MAX_PARTITIONS, 1) != 0)
error(1, 0, "Error can not read the partition table (flash)");
 
flash_os_image = find_partition(flash, MAX_PARTITIONS,
"os-image", "Error can not find os-image partition (flash)");
flash_file_system = find_partition(flash, MAX_PARTITIONS,
"file-system", "Error can not find file-system partition (flash)");
 
/* write os_image to 0x0 */
write_partition(input_file, firmware_offset, fwup_os_image, output_file);
write_ff(output_file, flash_os_image->size - fwup_os_image->size);
 
/* write file-system behind os_image */
fseek(output_file, flash_file_system->base - flash_os_image->base, SEEK_SET);
write_partition(input_file, firmware_offset, fwup_file_system, output_file);
write_ff(output_file, flash_file_system->size - fwup_file_system->size);
 
fclose(output_file);
fclose(input_file);
}
 
int main(int argc, char *argv[]) {
const char *board = NULL, *kernel_image = NULL, *rootfs_image = NULL, *output = NULL;
const char *extract_image = NULL, *output_directory = NULL, *convert_image = NULL;
bool add_jffs2_eof = false, sysupgrade = false;
unsigned rev = 0;
const struct device_info *info;
set_source_date_epoch();
 
while (true) {
int c;
 
c = getopt(argc, argv, "B:k:r:o:V:jSh:x:d:z:");
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;
 
case 'd':
output_directory = optarg;
break;
 
case 'x':
extract_image = optarg;
break;
 
case 'z':
convert_image = optarg;
break;
 
default:
usage(argv[0]);
return 1;
}
}
 
if (extract_image || output_directory) {
if (!extract_image)
error(1, 0, "No factory/oem image given via -x <file>. Output directory is only valid with -x");
if (!output_directory)
error(1, 0, "Can not extract an image without output directory. Use -d <dir>");
extract_firmware(extract_image, output_directory);
} else if (convert_image) {
if (!output)
error(1, 0, "Can not convert a factory/oem image into sysupgrade image without output file. Use -o <file>");
convert_firmware(convert_image, output);
} else {
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");
 
info = find_board(board);
 
if (info == NULL)
error(1, 0, "unsupported board %s", board);
 
build_image(output, kernel_image, rootfs_image, rev, add_jffs2_eof, sysupgrade, info);
}
 
return 0;
}
/branches/gl-inet/tools/firmware-utils/src/trx.c
@@ -0,0 +1,427 @@
/*
* 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, magic;
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:M:")) != -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;
case 'M':
errno = 0;
magic = strtoul(optarg, &e, 0);
if (errno || (e == optarg) || *e) {
fprintf(stderr, "illegal numeric string\n");
usage();
}
p->magic = STORE32_LE(magic);
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;
}
/branches/gl-inet/tools/firmware-utils/src/trx2edips.c
@@ -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);
}
 
/branches/gl-inet/tools/firmware-utils/src/trx2usr.c
@@ -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;
}
/branches/gl-inet/tools/firmware-utils/src/wrt400n.c
@@ -0,0 +1,336 @@
/*
* 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 <arpa/inet.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
 
#include "cyg_crc.h"
 
// https://dev.openwrt.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;
}
/branches/gl-inet/tools/firmware-utils/src/xorimage.c
@@ -0,0 +1,134 @@
/*
* xorimage.c - partially based on OpenWrt'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 <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;
}
/branches/gl-inet/tools/firmware-utils/src/zyimage.c
@@ -0,0 +1,148 @@
/*
* Copyright (C) 2014 Soul Trace <S-trace@list.ru>
*
* 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.
*
*/
 
#define _POSIX_SOURCE
#define _POSIX_C_SOURCE 199309L /* getopt */
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <unistd.h>
 
#define szbuf 32768
 
u_int32_t crc_tab[256];
 
u_int32_t chksum_crc32 (FILE *f)
{
register unsigned long crc;
unsigned long i, j;
char *buffer = malloc(szbuf);
char *buf;
 
crc = 0xFFFFFFFF;
while (!feof(f))
{
j = fread(buffer, 1, szbuf, f);
buf = buffer;
for (i = 0; i < j; i++)
crc = ((crc >> 8) & 0x00FFFFFF) ^ crc_tab[(crc ^ *buf++) & 0xFF];
}
free(buffer);
return crc;
}
 
void chksum_crc32gentab ()
{
unsigned long crc, poly;
int i, j;
 
poly = 0xEDB88320L;
for (i = 0; i < 256; i++)
{
crc = i;
for (j = 8; j > 0; j--)
{
if (crc & 1)
crc = (crc >> 1) ^ poly;
else
crc >>= 1;
}
crc_tab[i] = crc;
}
}
 
void usage(char *progname)
{
printf("Usage: %s [ -v Version ] [ -d Device_ID ] <input file>\n", progname);
exit(1);
}
 
int main(int argc, char *argv[]) {
struct signature
{
const char magic[4];
unsigned int device_id;
char firmware_version[48];
unsigned int crc32;
}
sign =
{
{ 'Z', 'N', 'B', 'G' },
1,
{ "V.1.0.0(1.0.0)" },
0
};
FILE *f;
struct signature oldsign;
char *filename;
static const char *optString;
int opt;
 
if (argc < 1)
usage(argv[0]);
 
optString = "v:d:h";
opt = getopt( argc, argv, optString );
while( opt != -1 ) {
switch( opt ) {
case 'v':
if (optarg == NULL)
usage(argv[0]);
strncpy(sign.firmware_version, optarg, sizeof(sign.firmware_version)-1);
sign.firmware_version[sizeof(sign.firmware_version)-1]='\0'; /* Make sure that string is terminated correctly */
break;
 
case 'd':
sign.device_id = atoi(optarg);
if (sign.device_id == 0)
sign.device_id = (int)strtol(optarg, NULL, 16);
break;
 
case '?':
case 'h':
usage(argv[0]);
break;
 
default:
break;
}
 
opt = getopt( argc, argv, optString );
}
 
chksum_crc32gentab();
 
filename=argv[optind];
if (access(filename, W_OK) || access(filename, R_OK))
{
printf("Not open input file %s\n", filename);
exit(1);
}
f = fopen(argv[optind], "r+");
if (f != NULL)
{
fseek(f, sizeof(sign)*-1, SEEK_END);
fread(&oldsign, sizeof(oldsign), 1, f);
 
if (strncmp(oldsign.magic,"ZNBG", sizeof(oldsign.magic)) == 0 )
{
printf("Image is already signed as:\nDevice ID: 0x%08x\nFirmware version: %s\nImage CRC32: 0x%x\n", oldsign.device_id, oldsign.firmware_version, oldsign.crc32);
exit(0);
}
 
fseek(f, 0, SEEK_SET);
sign.crc32 = chksum_crc32(f);
fwrite(&sign, sizeof(sign), 1, f);
fclose(f);
 
printf("Image signed as:\nDevice ID: 0x%08x\nFirmware version: %s\nImage CRC32: 0x%x\n", sign.device_id, sign.firmware_version, sign.crc32);
}
return 0;
}
/branches/gl-inet/tools/firmware-utils/src/zynos.h
@@ -0,0 +1,225 @@
/*
*
* Copyright (C) 2007-2008 OpenWrt.org
* Copyright (C) 2007-2008 Gabor Juhos <juhosg at openwrt.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 */
/branches/gl-inet/tools/firmware-utils/src/zyxbcm.c
@@ -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 <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.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 OpenWRT, 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 OpenWRT)
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 OpenWRT, 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 OpenWRT)
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;
}