48feea4861
Add Netgear WNCE2001. This is a small RT3052 device with 4MB spi flash and 32MB ram. 2 built-in antennas, 1x fastE, no USB, reset & wps switch. On my model the AP/RT switch is unpopulated, but I verified the gpio mapping for it. The stock firmware is running an unprotected tftpd which allows you to read any file from the filesystem. Serial port is present on testpads (See image on the wiki page). There are more testpads below the shield near the SoC, which may have JTAG. Slight annoyance: The bootloader is checksumming kernel&rootfs, but can be tricked by zeroing checksum and length fields in the checksum partition, see target/linux/ramips/base-files/lib/preinit/04_disable_wnce2001_flash_checksumming The manufacturer image is very similar to the DAP one, so I slightly modified mkdapimg to support generating it. The resulting openwrt-ramips-rt305x-wnce2001-squashfs-factory-(worldwide|northamerica).bin can be used to flash from stock to OpenWRT using the stock firmware upgrade function, without using the serial port. http://www.netgear.com/landing/wnce2001.aspx http://wiki.openwrt.org/toh/netgear/wnce2001 Signed-off-by: Tobias Diedrich <ranma+openwrt@tdiedrich.de> SVN-Revision: 36289
226 lines
5.2 KiB
C
226 lines
5.2 KiB
C
#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(®ion, 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);
|
|
}
|