3 WRT350Nv2-Builder 2.2 (previously called buildimg)
4 Copyright (C) 2008-2009 Dirk Teurlings <info@upexia.nl>
5 Copyright (C) 2009-2010 Matthias Buecher (http://www.maddes.net/)
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 A lot of thanks to Kaloz and juhosg from OpenWRT and Lennert Buytenhek from
22 marvell for helping me figure this one out. This code is based on bash
23 scripts wrote by Peter van Valderen so the real credit should go to him.
25 This program reads the provided parameter file and creates an image which can
26 be used to flash a Linksys WRT350N v2 from stock firmware.
27 The trick is to fill unused space in the bin file with random, so that the
28 resulting zip file passes the size check of the stock firmware.
30 The parameter file layout for an original Linksys firmware:
31 :kernel 0x001A0000 /path/to/uImage
32 :rootfs 0 /path/to/root.squashfs
33 :u-boot 0 /path/to/u-boot.bin
37 1 wrt350nv2.par parameter file describing the image layout
38 2 wrt350nv2.img output file for linksys style image
40 A u-boot image inside the bin file is not necessary.
41 The version is not important.
42 The name of the bin file is not important, but still "wrt350n.bin" is used to
43 keep as close as possible to the stock firmware.
45 Linksys assumes that no mtd will be used to its maximum, so the last 16 bytes
46 of the mtd are abused to define the length of the next mtd content (4 bytes for
49 At the end of "rootfs" additional 16 bytes are abused for some data and a
50 highly important eRcOmM identifier, so the last 32 bytes of "rootfs" are abused.
52 At the end of "u-boot" 128 bytes are abused for some data, a checksum and a
53 highly important sErCoMm identifier.
56 This program uses a special GNU scanf modifier to allocate
57 sufficient memory for a strings with unknown length.
58 See http://www.kernel.org/doc/man-pages/online/pages/man3/scanf.3.html#NOTES
61 To extract everything from a Linksys style firmware image see
62 https://forum.openwrt.org/viewtopic.php?pid=92928#p92928
65 v2.2 - fixed checksum byte calculation for other versions than 0x2019
66 fixed rare problem with padsize
67 updated info to stock firmware 2.00.20
69 v2.1 - used "wrt350n.bin" for the created image (closer to stock)
70 added option to create the image in two separate steps (-b / -z)
71 v2.0 - complete re-write
76 #define _GNU_SOURCE // for GNU's basename()
78 #include <errno.h> // errno
80 #include <stdio.h> // fopen(), fread(), fclose(), etc.
81 #include <stdlib.h> // system(), etc.
82 #include <string.h> // basename(), strerror(), strdup(), etc.
83 #include <unistd.h> // optopt(), access(), etc.
85 #include <sys/wait.h> // WEXITSTATUS, etc.
88 #include "md5.h" // MD5 routines
89 #include "upgrade.h" // Linksys definitions from firmware 2.0.19 (unchanged up to 2.0.20)
94 char program_info
[] = "WRT350Nv2-Builder v%s by Dirk Teurlings <info@upexia.nl> and Matthias Buecher (http://www.maddes.net/)\n";
108 unsigned char magic
[2];
111 mtd_info mtd_kernel
= { "kernel", 0, 0, NULL
, 0L, { 0, 0 } };
112 mtd_info mtd_rootfs
= { "rootfs", 0, 0, NULL
, 0L, { 0, 0 } };
113 mtd_info mtd_uboot
= { "u-boot", 0, 0, NULL
, 0L, { 0, 0 } };
115 #define ROOTFS_END_OFFSET 0x00760000
116 #define ROOTFS_MIN_OFFSET 0x00640000 // should be filled up to here, to make sure that the zip file is big enough to pass the size check of the stock firmware
117 // 2.0.17: filled up to 0x00640000
118 // 2.0.19: filled up to 0x00670000
119 // 2.0.20: filled up to 0x00670000
121 // rootfs statics via: hexdump -v -e '1/1 "0x%02X, "' -s 0x0075FFE0 -n 16 "wrt350n.bin" ; echo -en "\n"
122 unsigned char product_id
[] = { 0x00, 0x03 }; // seems to be a fixed value
123 unsigned char protocol_id
[] = { 0x00, 0x00 }; // seems to be a fixed value
124 unsigned char fw_version
[] = { 0x20, 0x20 };
125 unsigned char rootfs_unknown
[] = { 0x90, 0xF7 }; // seems to be a fixed value
126 unsigned char sign
[] = { 0x65, 0x52, 0x63, 0x4F, 0x6D, 0x4D, 0x00, 0x00 }; // eRcOmM
128 // u-boot statics via: hexdump -v -e '1/1 "0x%02X, "' -s 0x007FFF80 -n 128 "wrt350n.bin" ; echo -en "\n"
129 //unsigned char sn[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // (12) seems to be an unused value
130 //unsigned char pin[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // (8) seems to be an unused value
131 //unsigned char node[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // (25) seems to be an unused value
132 // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
133 //unsigned char checksum[] = { 0xE9 }; // (1) is calculated, does it belong to node?
134 unsigned char pid
[] = { 0x73, 0x45, 0x72, 0x43, 0x6F, 0x4D, 0x6D, 0x00, 0x01, 0x00, 0x00, 0x59, 0x42, 0x50, 0x00, 0x01, // (70) seems to be a fixed value, except for fw version
135 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
136 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, // protocol id?
137 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, // protocol id?
138 0x12, 0x34, // firmware version, same as in rootfs
139 0x00, 0x00, 0x00, 0x04,
140 0x73, 0x45, 0x72, 0x43, 0x6F, 0x4D, 0x6D }; // sErCoMm
142 // img statics via: hexdump -v -e '1/1 "0x%02X, "' -s 0 -n 512 "WRT350N-EU-ETSI-2.00.19.img" ; echo -en "\n" (unchanged up to 2.0.20)
143 unsigned char img_hdr
[] = { 0x00, 0x01, 0x00, 0x00, 0x59, 0x42, 0x50, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
144 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
145 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
147 0x12, 0x34, // firmware version, same as in rootfs
148 0x00, 0x00, 0x00, 0x04, 0x61, 0x44, 0x6D, 0x42, 0x6C, 0x4B, 0x3D, 0x00,
149 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
150 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
151 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
152 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
153 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
154 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
155 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
156 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
157 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
158 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
159 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
160 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
161 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
162 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
163 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
164 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
165 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
166 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
167 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
168 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
169 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
170 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
171 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
172 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
173 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
174 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
175 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, // md5 checksum
176 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
178 unsigned char img_eof
[] = { 0xFF };
181 void lprintf(int outputlevel
, char *fmt
, ...) {
183 if (outputlevel
<= verbosity
) {
191 int parse_par_file(FILE *f_par
) {
213 while (!feof(f_par
)) {
214 // read next line into memory
216 // allocate memory for input line
218 buffer
= malloc(buffer_size
);
222 printf("parse_par_file: can not allocate %i bytes\n", (int) buffer_size
);
226 line
= fgets(buffer
, buffer_size
, f_par
);
228 exitcode
= ferror(f_par
);
230 printf("parse_par_file: %s\n", strerror(exitcode
));
235 // if buffer was not completely filled, then assume that line is complete
236 count
= strlen(buffer
) + 1;
237 if (count
-- < buffer_size
) {
243 // reset file position to line start
244 value
= fseek(f_par
, -count
, SEEK_CUR
);
247 printf("parse_par_file: %s\n", strerror(exitcode
));
251 // double buffer size
255 lprintf(DEBUG_LVL2
, " extending buffer to %i bytes\n", buffer_size
);
257 if ((!line
) || (exitcode
)) {
261 lineno
++; // increase line number
263 lprintf(DEBUG_LVL2
, " line %i (%i) %s", lineno
, count
, line
);
268 // split line if starting with a colon
271 count
= sscanf(line
, ":%255s %i %255s", string1
, &value
, string2
);
273 printf("line %i does not meet defined format (:<mtdname> <mtdsize> <file>)\n", lineno
);
275 // populate mtd_info if supported mtd names
276 if (!strcmp(string1
, mtd_kernel
.name
)) {
278 } else if (!strcmp(string1
, mtd_rootfs
.name
)) {
280 } else if (!strcmp(string1
, mtd_uboot
.name
)) {
285 printf("unknown mtd %s in line %i\n", string1
, lineno
);
286 } else if (mtd
->filename
) {
288 printf("mtd %s in line %i multiple definitions\n", string1
, lineno
);
291 mtd
->filename
= strdup(string2
);
294 f_in
= fopen(mtd
->filename
, "rb");
297 printf("input file %s: %s\n", mtd
->filename
, strerror(f_exitcode
));
299 value
= fread(&mtd
->magic
, 1, 2, f_in
);
302 f_exitcode
= ferror(f_in
);
303 printf("input file %s: %s\n", mtd
->filename
, strerror(f_exitcode
));
306 printf("input file %s: smaller than two bytes, no magic code\n", mtd
->filename
);
310 value
= fseek(f_in
, 0, SEEK_END
);
313 printf("input file %s: %s\n", mtd
->filename
, strerror(f_exitcode
));
315 mtd
->filesize
= ftell(f_in
);
316 if (mtd
->filesize
== -1) {
318 printf("input file %s: %s\n", mtd
->filename
, strerror(f_exitcode
));
325 lprintf(DEBUG
, "mtd %s in line %i: size=0x%08X, filesize=0x%08lX, magic=0x%02X%02X, file=%s\n", mtd
->name
, lineno
, mtd
->size
, mtd
->filesize
, mtd
->magic
[0], mtd
->magic
[1], mtd
->filename
);
329 case '#': // integer values
330 count
= sscanf(line
, "#%255s %i", string1
, &value
);
332 printf("line %i does not meet defined format (#<variable name> <integer>\n", lineno
);
334 if (!strcmp(string1
, "version")) {
336 fw_version
[0] = 0x000000FF & ( value
>> 8 );
337 fw_version
[1] = 0x000000FF & value
;
339 printf("unknown integer variable %s in line %i\n", string1
, lineno
);
342 lprintf(DEBUG
, "integer variable %s in line %i: 0x%08X\n", string1
, lineno
, value
);
346 count
= sscanf(line
, "$%255s %255s", string1
, string2
);
348 printf("line %i does not meet defined format (:<mtdname> <mtdsize> <file>)\n", lineno
);
351 if (!strcmp(string1, "something")) {
352 something = strdup(string2);
355 printf("unknown string variable %s in line %i\n", string1
, lineno
);
357 lprintf(DEBUG
, "string variable %s in line %i: %s\n", string1
, lineno
, string2
);
367 exitcode
= f_exitcode
;
374 int create_bin_file(char *bin_filename
) {
377 unsigned char *buffer
;
384 char *rand_filename
= "/dev/urandom";
388 unsigned long int csum
;
389 unsigned char checksum
;
393 // allocate memory for bin file
394 buffer
= malloc(KERNEL_CODE_OFFSET
+ FLASH_SIZE
);
397 printf("create_bin_file: can not allocate %i bytes\n", FLASH_SIZE
);
399 // initialize with zero
400 memset(buffer
, 0, KERNEL_CODE_OFFSET
+ FLASH_SIZE
);
405 for (i
= 1; i
<= 3; i
++) {
415 addsize
= mtd
->filesize
;
416 padsize
= ROOTFS_MIN_OFFSET
- mtd_kernel
.size
- mtd
->filesize
;
420 addsize
= mtd
->filesize
;
425 printf("create_bin_file: unknown mtd %i\n", i
);
431 if (!mtd
->filename
) {
435 lprintf(DEBUG
, "adding mtd %s file %s\n", mtd
->name
, mtd
->filename
);
439 buffer
[KERNEL_CODE_OFFSET
+ mtd
->offset
- 16] = 0x000000FFL
& ( addsize
>> 24 );
440 buffer
[KERNEL_CODE_OFFSET
+ mtd
->offset
- 15] = 0x000000FFL
& ( addsize
>> 16 );
441 buffer
[KERNEL_CODE_OFFSET
+ mtd
->offset
- 14] = 0x000000FFL
& ( addsize
>> 8 );
442 buffer
[KERNEL_CODE_OFFSET
+ mtd
->offset
- 13] = 0x000000FFL
& addsize
;
445 // adding file content
446 f_in
= fopen(mtd
->filename
, "rb");
449 printf("input file %s: %s\n", mtd
->filename
, strerror(exitcode
));
451 size
= fread(&buffer
[KERNEL_CODE_OFFSET
+ mtd
->offset
], mtd
->filesize
, 1, f_in
);
454 exitcode
= ferror(f_in
);
455 printf("input file %s: %s\n", mtd
->filename
, strerror(exitcode
));
458 printf("input file %s: smaller than before *doh*\n", mtd
->filename
);
466 addsize
= padsize
& 0x0000FFFF; // start on next 64KB border
470 printf("mtd %s input file %s is too small (0x%08lX), adding 0x%08X random bytes\n", mtd
->name
, mtd
->filename
, mtd
->filesize
, padsize
);
472 addsize
+= KERNEL_CODE_OFFSET
+ mtd
->offset
+ mtd
->filesize
; // get offset
473 lprintf(DEBUG
, " padding offset 0x%08X length 0x%08X\n", addsize
, padsize
);
475 f_in
= fopen(rand_filename
, "rb");
478 printf("input file %s: %s\n", rand_filename
, strerror(exitcode
));
480 size
= fread(&buffer
[addsize
], padsize
, 1, f_in
);
483 exitcode
= ferror(f_in
);
484 printf("input file %s: %s\n", rand_filename
, strerror(exitcode
));
487 printf("input file %s: smaller than before *doh*\n", rand_filename
);
496 // add special contents
498 lprintf(DEBUG
, "adding rootfs special data\n");
499 memcpy(&buffer
[KERNEL_CODE_OFFSET
+ PRODUCT_ID_OFFSET
], product_id
, 2);
500 memcpy(&buffer
[KERNEL_CODE_OFFSET
+ PROTOCOL_ID_OFFSET
], protocol_id
, 2);
501 memcpy(&buffer
[KERNEL_CODE_OFFSET
+ FW_VERSION_OFFSET
], fw_version
, 2);
502 memcpy(&buffer
[KERNEL_CODE_OFFSET
+ FW_VERSION_OFFSET
+ 2], rootfs_unknown
, 2);
503 memcpy(&buffer
[KERNEL_CODE_OFFSET
+ SIGN_OFFSET
], sign
, 8); // eRcOmM
505 lprintf(DEBUG
, "adding u-boot special data\n");
506 // memcpy(&buffer[KERNEL_CODE_OFFSET + SN_OFF], sn, 12); // ToDo: currently zero, find out what's this for?
507 // memcpy(&buffer[KERNEL_CODE_OFFSET + PIN_OFF], pin, 8); // ToDo: currently zero, find out what's this for?
508 // memcpy(&buffer[KERNEL_CODE_OFFSET + NODE_BASE_OFF], node, 25); // ToDo: currently zero, find out what's this for?
509 memcpy(&buffer
[KERNEL_CODE_OFFSET
+ BOOT_ADDR_BASE_OFF
+ PID_OFFSET
], pid
, 70); // sErCoMm
510 memcpy(&buffer
[KERNEL_CODE_OFFSET
+ BOOT_ADDR_BASE_OFF
+ PID_OFFSET
+ 57], fw_version
, 2);
512 lprintf(DEBUG
, "adding checksum byte\n");
514 for (i
= 0; i
< KERNEL_CODE_OFFSET
+ FLASH_SIZE
; i
++) {
517 lprintf(DEBUG_LVL2
, " checksum 0x%016lX (%li)\n", csum
, csum
);
519 buffer
[KERNEL_CODE_OFFSET
+ NODE_BASE_OFF
+ 25] = ~csum
+ 1;
520 lprintf(DEBUG
, " byte 0x%02X\n", buffer
[KERNEL_CODE_OFFSET
+ NODE_BASE_OFF
+ 25]);
525 lprintf(DEBUG
, "writing file %s\n", bin_filename
);
526 f_out
= fopen(bin_filename
, "wb");
529 printf("output file %s: %s\n", bin_filename
, strerror(exitcode
));
531 size
= fwrite(buffer
, KERNEL_CODE_OFFSET
+ FLASH_SIZE
, 1, f_out
);
534 exitcode
= ferror(f_out
);
535 printf("output file %s: %s\n", bin_filename
, strerror(exitcode
));
538 printf("output file %s: unspecified write error\n", bin_filename
);
549 int create_zip_file(char *zip_filename
, char *bin_filename
) {
559 // allocate memory for command line
561 buffer
= malloc(buffer_size
);
565 printf("create_zip_file: can not allocate %i bytes\n", (int) buffer_size
);
569 // if buffer was not completely filled, then line fit in completely
570 count
= snprintf(buffer
, buffer_size
, "zip \"%s\" \"%s\"", zip_filename
, bin_filename
);
571 if ((count
> -1) && (count
< buffer_size
)) {
575 // otherwise try again with more space
576 if (count
> -1) { // glibc 2.1
577 buffer_size
= count
+ 1; // precisely what is needed
578 } else { // glibc 2.0
579 buffer_size
*= 2; // twice the old size
583 lprintf(DEBUG_LVL2
, " extending buffer to %i bytes\n", buffer_size
);
588 lprintf(DEBUG
, "%s\n", buffer
);
589 count
= system(buffer
);
590 if ((count
< 0) || (WEXITSTATUS(count
))) {
592 printf("create_zip_file: can not execute %s bytes\n", buffer
);
600 int create_img_file(FILE *f_out
, char *out_filename
, char *zip_filename
) {
604 md5_byte_t digest
[16];
610 unsigned char buffer
[1];
612 // copy firmware version
613 memcpy(&img_hdr
[50], fw_version
, 2);
615 // clear md5 checksum
616 memset(&img_hdr
[480], 0, 16);
618 // prepare md5 checksum calculation
622 lprintf(DEBUG_LVL2
, " adding img header\n");
623 for (i
= 0; i
< 512; i
++) {
624 size
= fputc(img_hdr
[i
], f_out
);
626 exitcode
= ferror(f_out
);
627 printf("output file %s: %s\n", out_filename
, strerror(exitcode
));
630 md5_append(&state
, (const md5_byte_t
*)&img_hdr
[i
], 1);
635 lprintf(DEBUG_LVL2
, " adding zip file\n");
636 f_in
= fopen(zip_filename
, "rb");
639 printf("input file %s: %s\n", zip_filename
, strerror(exitcode
));
641 while ((size
= fgetc(f_in
)) != EOF
) {
644 size
= fputc(buffer
[0], f_out
);
646 exitcode
= ferror(f_out
);
647 printf("output file %s: %s\n", out_filename
, strerror(exitcode
));
650 md5_append(&state
, (const md5_byte_t
*)buffer
, 1);
653 exitcode
= ferror(f_in
);
654 printf("input file %s: %s\n", zip_filename
, strerror(exitcode
));
662 lprintf(DEBUG_LVL2
, " adding img eof byte\n");
663 size
= fputc(img_eof
[0], f_out
);
665 exitcode
= ferror(f_out
);
666 printf("output file %s: %s\n", out_filename
, strerror(exitcode
));
668 md5_append(&state
, (const md5_byte_t
*)img_eof
, 1);
671 // append salt to md5 checksum
672 md5_append(&state
, (const md5_byte_t
*)"A^gU*<>?RFY@#DR&Z", 17);
674 // finish md5 checksum calculation
675 md5_finish(&state
, digest
);
677 // write md5 checksum into img header
679 lprintf(DEBUG_LVL2
, " writing md5 checksum into img header of file\n");
681 size
= fseek(f_out
, 480, SEEK_SET
);
684 printf("output file %s: %s\n", out_filename
, strerror(exitcode
));
686 size
= fwrite(digest
, 16, 1, f_out
);
689 exitcode
= ferror(f_out
);
690 printf("output file %s: %s\n", out_filename
, strerror(exitcode
));
693 printf("output file %s: unspecified write error\n", out_filename
);
705 int main(int argc
, char *argv
[]) {
712 char *par_filename
= NULL
;
713 char *img_filename
= NULL
;
714 char *base_filename
= NULL
;
715 char *bin_filename
= NULL
;
716 char *zip_filename
= NULL
;
726 unsigned char magic
[2];
729 // display program header
730 printf(program_info
, VERSION
);
733 // command line processing
738 while ((option
= getopt(argc
, argv
, ":hbzf:v")) != -1) {
750 sizecheck
= sscanf(optarg
, "%i", &i
);
751 if (sizecheck
!= 1) {
752 printf("Firmware version of -f option not a valid integer\n");
755 fw_version
[0] = 0x000000FF & ( i
>> 8 );
756 fw_version
[1] = 0x000000FF & i
;
762 case ':': // option with missing operand
763 printf("Option -%c requires an operand\n", optopt
);
767 printf("Unrecognized option: -%c\n", optopt
);
774 for ( ; optind
< argc
; optind
++) {
776 par_filename
= argv
[optind
];
778 if (access(par_filename
, R_OK
)) {
780 printf("No read access to zip file %s\n", par_filename
);
782 printf("No read access to parameter or zip file %s\n", par_filename
);
790 if ((!onlybin
) && (!img_filename
)) {
791 img_filename
= argv
[optind
];
793 if (!access(img_filename
, F_OK
)) { // if file already exists then check write access
794 if (access(img_filename
, W_OK
)) {
795 printf("No write access to image file %s\n", img_filename
);
803 printf("Too many files stated\n");
811 printf("Zip file not stated\n");
813 printf("Parameter file not stated\n");
817 base_filename
= basename(par_filename
);
818 if (!base_filename
) {
820 printf("Zip file is a directory\n");
822 printf("Parameter file is a directory\n");
830 printf("Image file not stated\n");
833 base_filename
= basename(img_filename
);
834 if (!base_filename
) {
835 printf("Image file is a directory\n");
841 // check for mutually exclusive options
842 if ((onlybin
) && (havezip
)) {
843 printf("Option -b and -z are mutually exclusive\n");
847 // react on option problems or help request, then exit
848 if ((exitcode
) || (help
)) {
850 printf("This program creates Linksys style images for the WRT350Nv2 router.\n");
853 %s [-h] [-b] [-z] [-f <version>] [-v] <parameter or zip file> [<image file>]\n\n\
855 -h - Show this help\n\
856 -b - Create only bin file, no img or zip file is created\n\
857 -z - Have zip file, the img file will be directly created from it\n\
858 -f <version> - Wanted firmware version to use with -z\n\
859 Default firmware version is 0x2020 = 2.00.20.\n\
860 Note: version from parameter file will supersede this\n\
861 -v - Increase debug verbosity level\n\n\
863 %s wrt350nv2.par wrt350nv2.img\n\n", argv
[0], argv
[0]);
867 // handle special case when zipfile is stated
869 zip_filename
= par_filename
;
873 lprintf(DEBUG_LVL2
, " Verbosity: %i\n", verbosity
);
874 lprintf(DEBUG_LVL2
, " Program: %s\n", argv
[0]);
877 lprintf(DEBUG
, "Parameter file: %s\n", par_filename
);
880 lprintf(DEBUG
, "Zip file: %s\n", zip_filename
);
883 lprintf(DEBUG
, "Image file: %s\n", img_filename
);
887 // open files from command line
888 // parameter/zip file
890 f_par
= fopen(par_filename
, "rt");
893 printf("Input file %s: %s\n", par_filename
, strerror(exitcode
));
899 f_img
= fopen(img_filename
, "wb");
902 printf("Output file %s: %s\n", img_filename
, strerror(exitcode
));
911 // parameter file processing
912 if ((!exitcode
) && (f_par
)) {
913 lprintf(DEBUG
, "parsing parameter file...\n");
915 exitcode
= parse_par_file(f_par
);
917 lprintf(DEBUG
, "...done parsing file\n");
924 // check all input data
925 if ((!exitcode
) && (par_filename
)) {
926 lprintf(DEBUG
, "checking mtd data...\n");
928 for (i
= 1; i
<= 3; i
++) {
939 sizecheck
= mtd_kernel
.size
- 16;
945 mtd
->offset
= mtd_kernel
.size
;
946 mtd
->size
= ROOTFS_END_OFFSET
- mtd_kernel
.size
;
948 sizecheck
= PRODUCT_ID_OFFSET
- mtd_kernel
.size
;
954 mtd
->offset
= BOOT_ADDR_BASE_OFF
;
956 sizecheck
= SN_OFF
- BOOT_ADDR_BASE_OFF
;
961 printf("unknown mtd check %i\n", i
);
968 lprintf(DEBUG_LVL2
, " checking mtd %s\n", mtd
->name
);
971 if ((mandatory
) && (!mtd
->filename
)) {
973 printf("mtd %s not specified correctly or at all in parameter file\n", mtd
->name
);
976 // end checks if no file data present
977 if (!mtd
->filename
) {
981 // not updated by stock firmware
983 printf("mtd %s is specified, but will not be updated as of Linksys firmware 2.0.19\n", mtd
->name
);
986 // general magic number check
988 if ((mtd
->magic
[0] != magic
[0]) || (mtd
->magic
[1] != magic
[1])) {
990 printf("mtd %s input file %s has wrong magic number (0x%02X%02X)\n", mtd
->name
, mtd
->filename
, mtd
->magic
[0], mtd
->magic
[1]);
994 // mtd specific size check
995 if (mtd
== &mtd_kernel
) {
996 if (mtd
->filesize
< 0x00050000) {
998 printf("mtd %s input file %s too unrealistic small (0x%08lX)\n", mtd
->name
, mtd
->filename
, mtd
->filesize
);
1002 // general size check
1004 if (sizecheck
<= 0) {
1006 printf("mtd %s bad file size check (%i) due to input data\n", mtd
->name
, sizecheck
);
1008 if (mtd
->filesize
> sizecheck
) {
1010 printf("mtd %s input file %s too big (0x%08lX)\n", mtd
->name
, mtd
->filename
, mtd
->filesize
);
1015 lprintf(DEBUG
, "...done checking mtd data\n");
1019 // bin creation in memory
1020 if ((!exitcode
) && (par_filename
)) {
1021 bin_filename
= "wrt350n.bin";
1023 lprintf(DEBUG
, "creating bin file %s...\n", bin_filename
);
1025 exitcode
= create_bin_file(bin_filename
);
1027 lprintf(DEBUG
, "...done creating bin file\n");
1030 // zip file creation
1031 if ((!exitcode
) && (!onlybin
) && (!zip_filename
)) {
1032 zip_filename
= "wrt350n.zip";
1034 lprintf(DEBUG
, "creating zip file %s...\n", zip_filename
);
1036 exitcode
= create_zip_file(zip_filename
, bin_filename
);
1038 lprintf(DEBUG
, "...done creating zip file\n");
1042 // img file creation
1043 if ((!exitcode
) && (f_img
)) {
1044 lprintf(DEBUG
, "creating img file...\n");
1046 exitcode
= create_img_file(f_img
, img_filename
, zip_filename
);
1048 lprintf(DEBUG
, "...done creating img file\n");
This page took 0.09451 seconds and 5 git commands to generate.