3 WRT350Nv2-Builder 2.0 (previously called buildimg)
4 Copyright (C) 2008-2009 Dirk Teurlings <info@upexia.nl>
5 Copyright (C) 2009 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
36 1 wrt350nv2.par parameter file describing the image layout
37 2 wrt350nv2.img output file for linksys style image
39 An u-boot image inside the bin file is not necessary.
40 The version is not important.
41 The name of the bin file is not important.
43 Linksys assumes that no mtd will be used to its maximum, so the last 16 bytes
44 of the mtd are abused to define the length of the next mtd content (4 bytes for
47 At the end of "rootfs" additional 16 bytes are abused for some data and an
48 highly important eRcOmM identifier, so the last 32 bytes of "rootfs" are abused.
50 At the end of "u-boot" 128 bytes are abused for some data, a checksum and an
51 highly important sErCoMm identifier.
54 This program uses a special GNU scanf modifier to allocate
55 sufficient memory for a strings with unknown length.
56 See http://www.kernel.org/doc/man-pages/online/pages/man3/scanf.3.html#NOTES
59 To extract everything from a Linksys style firmware image see
60 https://forum.openwrt.org/viewtopic.php?pid=92928#p92928
65 // * Has NODE to be added to bin file *after* creating checksum byte?
68 #define _GNU_SOURCE // for GNU's basename()
70 #include <errno.h> // errno
72 #include <stdio.h> // fopen(), fread(), fclose(), etc.
73 #include <stdlib.h> // system(), etc.
74 #include <string.h> // basename(), strerror(), strdup(), etc.
75 #include <unistd.h> // optopt(), access(), etc.
77 #include <sys/wait.h> // WEXITSTATUS, etc.
80 #include "md5.h" // MD5 routines
81 #include "upgrade.h" // Linksys definitions from firmware 2.0.19
86 char program_info
[] = "WRT350Nv2-Builder v%s by Dirk Teurlings <info@upexia.nl> and Matthias Buecher (http://www.maddes.net/)\n";
100 unsigned char magic
[2];
103 mtd_info mtd_kernel
= { "kernel", 0, 0, NULL
, 0L, { 0, 0 } };
104 mtd_info mtd_rootfs
= { "rootfs", 0, 0, NULL
, 0L, { 0, 0 } };
105 mtd_info mtd_uboot
= { "u-boot", 0, 0, NULL
, 0L, { 0, 0 } };
107 #define ROOTFS_END_OFFSET 0x00760000
108 #define ROOTFS_MIN_OFFSET 0x00700000 // should be filled up to here, to make sure that the zip file is big enough to pass the size check of the stock firmware
110 // rootfs statics via: hexdump -v -e '1/1 "0x%02X, "' -s 0x0075FFE0 -n 16 "wrt350n.bin" ; echo -en "\n"
111 unsigned char product_id
[] = { 0x00, 0x03 }; // seems to be a fixed value
112 unsigned char protocol_id
[] = { 0x00, 0x00 }; // seems to be a fixed value
113 unsigned char fw_version
[] = { 0x20, 0x19 };
114 unsigned char rootfs_unknown
[] = { 0x90, 0xF7 }; // seems to be a fixed value
115 unsigned char sign
[] = { 0x65, 0x52, 0x63, 0x4F, 0x6D, 0x4D, 0x00, 0x00 }; // eRcOmM
117 // u-boot statics via: hexdump -v -e '1/1 "0x%02X, "' -s 0x007FFF80 -n 128 "wrt350n.bin" ; echo -en "\n"
118 //unsigned char sn[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // (12) seems to be an unused value
119 //unsigned char pin[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // (8) seems to be an unused value
120 //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
121 // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
122 //unsigned char checksum[] = { 0xE9 }; // (1) is calculated, does it belong to node?
123 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
124 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
125 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, // protocol id?
126 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, // protocol id?
127 0x12, 0x34, // firmware version, same as in rootfs
128 0x00, 0x00, 0x00, 0x04,
129 0x73, 0x45, 0x72, 0x43, 0x6F, 0x4D, 0x6D }; // sErCoMm
131 // img statics via: hexdump -v -e '1/1 "0x%02X, "' -s 0 -n 512 "WRT350N-EU-ETSI-2.00.19.img" ; echo -en "\n"
132 unsigned char img_hdr
[] = { 0x00, 0x01, 0x00, 0x00, 0x59, 0x42, 0x50, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
133 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
134 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
136 0x12, 0x34, // firmware version, same as in rootfs
137 0x00, 0x00, 0x00, 0x04, 0x61, 0x44, 0x6D, 0x42, 0x6C, 0x4B, 0x3D, 0x00,
138 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
139 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
140 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
141 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
142 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
143 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
146 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
147 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
148 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, // md5 checksum
165 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
167 unsigned char img_eof
[] = { 0xFF };
170 void lprintf(int outputlevel
, char *fmt
, ...) {
172 if (outputlevel
<= verbosity
) {
180 int parse_par_file(FILE *f_par
) {
202 while (!feof(f_par
)) {
203 // read next line into memory
205 // allocate memory for input line
206 if (buffer
== NULL
) {
207 buffer
= malloc(buffer_size
);
209 if (buffer
== NULL
) {
211 printf("parse_par_file: can not allocate %i bytes\n", (int) buffer_size
);
215 line
= fgets(buffer
, buffer_size
, f_par
);
217 exitcode
= ferror(f_par
);
219 printf("parse_par_file: %s\n", strerror(exitcode
));
224 // if buffer was not completely filled, then assume that line is complete
225 count
= strlen(buffer
) + 1;
226 if (count
-- < buffer_size
) {
232 // reset file position to line start
233 value
= fseek(f_par
, -count
, SEEK_CUR
);
236 printf("parse_par_file: %s\n", strerror(exitcode
));
240 // double buffer size
244 lprintf(DEBUG_LVL2
, " extending buffer to %i bytes\n", buffer_size
);
246 if (line
== NULL
|| exitcode
) {
250 lineno
++; // increase line number
252 lprintf(DEBUG_LVL2
, " line %i (%i) %s", lineno
, count
, line
);
257 // split line if starting with a colon
260 count
= sscanf(line
, ":%255s %i %255s", string1
, &value
, string2
);
262 printf("line %i does not meet defined format (:<mtdname> <mtdsize> <file>)\n", lineno
);
264 // populate mtd_info if supported mtd names
265 if (strcmp(string1
, mtd_kernel
.name
) == 0) {
267 } else if (strcmp(string1
, mtd_rootfs
.name
) == 0) {
269 } else if (strcmp(string1
, mtd_uboot
.name
) == 0) {
274 printf("unknown mtd %s in line %i\n", string1
, lineno
);
275 } else if (mtd
->filename
!= NULL
) {
277 printf("mtd %s in line %i multiple definitions\n", string1
, lineno
);
280 mtd
->filename
= strdup(string2
);
283 f_in
= fopen(mtd
->filename
, "rb");
286 printf("input file %s: %s\n", mtd
->filename
, strerror(f_exitcode
));
288 value
= fread(&mtd
->magic
, 1, 2, f_in
);
291 f_exitcode
= ferror(f_in
);
292 printf("input file %s: %s\n", mtd
->filename
, strerror(f_exitcode
));
295 printf("input file %s: smaller than two bytes, no magic code\n", mtd
->filename
);
299 value
= fseek(f_in
, 0, SEEK_END
);
302 printf("input file %s: %s\n", mtd
->filename
, strerror(f_exitcode
));
304 mtd
->filesize
= ftell(f_in
);
305 if (mtd
->filesize
== -1) {
307 printf("input file %s: %s\n", mtd
->filename
, strerror(f_exitcode
));
314 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
);
318 case '#': // integer values
319 count
= sscanf(line
, "#%255s %i", string1
, &value
);
321 printf("line %i does not meet defined format (:<variable name> <integer>\n", lineno
);
323 if (strcmp(string1
, "version") == 0) {
325 fw_version
[0] = 0x000000FF & ( value
>> 8 );
326 fw_version
[1] = 0x000000FF & value
;
328 printf("unknown integer variable %s in line %i\n", string1
, lineno
);
331 lprintf(DEBUG
, "integer variable %s in line %i: 0x%08X\n", string1
, lineno
, value
);
335 count
= sscanf(line
, "$%255s %255s", string1
, string2
);
337 printf("line %i does not meet defined format (:<mtdname> <mtdsize> <file>)\n", lineno
);
340 if (strcmp(string1, "something") == 0) {
342 string2 = NULL; // do not free
345 printf("unknown string variable %s in line %i\n", string1
, lineno
);
347 lprintf(DEBUG
, "string variable %s in line %i: %s\n", string1
, lineno
, string2
);
357 exitcode
= f_exitcode
;
364 int create_bin_file(char *bin_filename
) {
367 unsigned char *buffer
;
374 char *rand_filename
= "/dev/urandom";
378 unsigned long int csum
;
379 unsigned char checksum
;
383 // allocate memory for bin file
384 buffer
= malloc(KERNEL_CODE_OFFSET
+ FLASH_SIZE
);
385 if (buffer
== NULL
) {
387 printf("create_bin_file: can not allocate %i bytes\n", FLASH_SIZE
);
389 // initialize with zero
390 memset(buffer
, 0, KERNEL_CODE_OFFSET
+ FLASH_SIZE
);
395 for (i
= 1; i
<= 3; i
++) {
405 addsize
= mtd
->filesize
;
406 padsize
= ROOTFS_MIN_OFFSET
- mtd_kernel
.size
- mtd
->filesize
;
410 addsize
= mtd
->filesize
;
415 printf("create_bin_file: unknown mtd %i\n", i
);
421 if (mtd
->filename
== NULL
) {
425 lprintf(DEBUG
, "adding mtd %s file %s\n", mtd
->name
, mtd
->filename
);
429 buffer
[KERNEL_CODE_OFFSET
+ mtd
->offset
- 16] = 0x000000FFL
& ( addsize
>> 24 );
430 buffer
[KERNEL_CODE_OFFSET
+ mtd
->offset
- 15] = 0x000000FFL
& ( addsize
>> 16 );
431 buffer
[KERNEL_CODE_OFFSET
+ mtd
->offset
- 14] = 0x000000FFL
& ( addsize
>> 8 );
432 buffer
[KERNEL_CODE_OFFSET
+ mtd
->offset
- 13] = 0x000000FFL
& addsize
;
435 // adding file content
436 f_in
= fopen(mtd
->filename
, "rb");
439 printf("input file %s: %s\n", mtd
->filename
, strerror(exitcode
));
441 size
= fread(&buffer
[KERNEL_CODE_OFFSET
+ mtd
->offset
], mtd
->filesize
, 1, f_in
);
444 exitcode
= ferror(f_in
);
445 printf("input file %s: %s\n", mtd
->filename
, strerror(exitcode
));
448 printf("input file %s: smaller than before *doh*\n", mtd
->filename
);
456 printf("mtd %s input file %s is too small (0x%08lX), adding 0x%08X random bytes\n", mtd
->name
, mtd
->filename
, mtd
->filesize
, padsize
);
458 addsize
= padsize
& 0x0000FFFF; // start on next 64KB border
460 addsize
+= KERNEL_CODE_OFFSET
+ mtd
->offset
+ mtd
->filesize
; // get offset
461 lprintf(DEBUG
, " padding offset 0x%08X length 0x%08X\n", addsize
, padsize
);
463 f_in
= fopen(rand_filename
, "rb");
466 printf("input file %s: %s\n", rand_filename
, strerror(exitcode
));
468 size
= fread(&buffer
[addsize
], padsize
, 1, f_in
);
471 exitcode
= ferror(f_in
);
472 printf("input file %s: %s\n", rand_filename
, strerror(exitcode
));
475 printf("input file %s: smaller than before *doh*\n", rand_filename
);
484 // add special contents
486 lprintf(DEBUG
, "adding rootfs special data\n");
487 memcpy(&buffer
[KERNEL_CODE_OFFSET
+ PRODUCT_ID_OFFSET
], product_id
, 2);
488 memcpy(&buffer
[KERNEL_CODE_OFFSET
+ PROTOCOL_ID_OFFSET
], protocol_id
, 2);
489 memcpy(&buffer
[KERNEL_CODE_OFFSET
+ FW_VERSION_OFFSET
], fw_version
, 2);
490 memcpy(&buffer
[KERNEL_CODE_OFFSET
+ FW_VERSION_OFFSET
+ 2], rootfs_unknown
, 2);
491 memcpy(&buffer
[KERNEL_CODE_OFFSET
+ SIGN_OFFSET
], sign
, 8); // eRcOmM
493 lprintf(DEBUG
, "adding u-boot special data 1/2\n"); // ToDo: or after creating the checksum byte?
494 // memcpy(&buffer[KERNEL_CODE_OFFSET + SN_OFF], sn, 12); // ToDo: find out what's this for?
495 // memcpy(&buffer[KERNEL_CODE_OFFSET + PIN_OFF], pin, 8); // ToDo: find out what's this for?
496 // memcpy(&buffer[KERNEL_CODE_OFFSET + NODE_BASE_OFF], node, 25); // ToDo: find out what's this for?
498 lprintf(DEBUG
, "adding checksum byte\n");
500 for (i
= 0; i
< KERNEL_CODE_OFFSET
+ FLASH_SIZE
; i
++) {
503 lprintf(DEBUG_LVL2
, " checksum 0x%016lX (%li)\n", csum
, csum
);
505 buffer
[KERNEL_CODE_OFFSET
+ NODE_BASE_OFF
+ 25] = ~(csum
+108)+1;
506 lprintf(DEBUG
, " byte 0x%02X\n", buffer
[KERNEL_CODE_OFFSET
+ NODE_BASE_OFF
+ 25]);
508 lprintf(DEBUG
, "adding u-boot special data 2/2\n");
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);
515 lprintf(DEBUG
, "writing file %s\n", bin_filename
);
516 f_out
= fopen(bin_filename
, "wb");
519 printf("output file %s: %s\n", bin_filename
, strerror(exitcode
));
521 size
= fwrite(buffer
, KERNEL_CODE_OFFSET
+ FLASH_SIZE
, 1, f_out
);
524 exitcode
= ferror(f_out
);
525 printf("output file %s: %s\n", bin_filename
, strerror(exitcode
));
528 printf("output file %s: unspecified write error\n", bin_filename
);
539 int create_zip_file(char *zip_filename
, char *bin_filename
) {
549 // allocate memory for command line
550 if (buffer
== NULL
) {
551 buffer
= malloc(buffer_size
);
553 if (buffer
== NULL
) {
555 printf("create_zip_file: can not allocate %i bytes\n", (int) buffer_size
);
559 // if buffer was not completely filled, then line fit in completely
560 count
= snprintf(buffer
, buffer_size
, "zip %s %s", zip_filename
, bin_filename
);
561 if (count
> -1 && count
< buffer_size
) {
565 // otherwise try again with more space
566 if (count
> -1) { // glibc 2.1
567 buffer_size
= count
+ 1; // precisely what is needed
568 } else { // glibc 2.0
569 buffer_size
*= 2; // twice the old size
573 lprintf(DEBUG_LVL2
, " extending buffer to %i bytes\n", buffer_size
);
578 lprintf(DEBUG
, "%s\n", buffer
);
579 count
= system(buffer
);
580 if (count
< 0 || WEXITSTATUS(count
)) {
582 printf("create_zip_file: can not execute %s bytes\n", buffer
);
590 int create_img_file(FILE *f_out
, char *out_filename
, char *zip_filename
) {
594 md5_byte_t digest
[16];
600 unsigned char buffer
[1];
602 // copy firmware version
603 memcpy(&img_hdr
[50], fw_version
, 2);
605 // clear md5 checksum
606 memset(&img_hdr
[480], 0, 16);
608 // prepare md5 checksum calculation
612 lprintf(DEBUG_LVL2
, " adding img header\n");
613 for (i
= 0; i
< 512; i
++) {
614 size
= fputc(img_hdr
[i
], f_out
);
616 exitcode
= ferror(f_out
);
617 printf("output file %s: %s\n", out_filename
, strerror(exitcode
));
620 md5_append(&state
, (const md5_byte_t
*)&img_hdr
[i
], 1);
625 lprintf(DEBUG_LVL2
, " adding zip file\n");
626 f_in
= fopen(zip_filename
, "rb");
629 printf("input file %s: %s\n", zip_filename
, strerror(exitcode
));
631 while ((size
= fgetc(f_in
)) != EOF
) {
634 size
= fputc(buffer
[0], f_out
);
636 exitcode
= ferror(f_out
);
637 printf("output file %s: %s\n", out_filename
, strerror(exitcode
));
640 md5_append(&state
, (const md5_byte_t
*)buffer
, 1);
643 exitcode
= ferror(f_in
);
644 printf("input file %s: %s\n", zip_filename
, strerror(exitcode
));
652 lprintf(DEBUG_LVL2
, " adding img eof byte\n");
653 size
= fputc(img_eof
[0], f_out
);
655 exitcode
= ferror(f_out
);
656 printf("output file %s: %s\n", out_filename
, strerror(exitcode
));
658 md5_append(&state
, (const md5_byte_t
*)img_eof
, 1);
661 // append salt to md5 checksum
662 md5_append(&state
, (const md5_byte_t
*)"A^gU*<>?RFY@#DR&Z", 17);
664 // finish md5 checksum calculation
665 md5_finish(&state
, digest
);
667 // write md5 checksum into img header
669 lprintf(DEBUG_LVL2
, " writing md5 checksum into img header of file\n");
671 size
= fseek(f_out
, 480, SEEK_SET
);
674 printf("output file %s: %s\n", out_filename
, strerror(exitcode
));
676 size
= fwrite(digest
, 16, 1, f_out
);
679 exitcode
= ferror(f_out
);
680 printf("output file %s: %s\n", out_filename
, strerror(exitcode
));
683 printf("output file %s: unspecified write error\n", out_filename
);
695 int main(int argc
, char *argv
[]) {
701 char *par_filename
= NULL
;
702 char *out_filename
= NULL
;
703 char *base_filename
= NULL
;
704 char *bin_filename
= NULL
;
705 char *zip_filename
= NULL
;
715 unsigned char magic
[2];
718 // display program header
719 printf(program_info
, VERSION
);
722 // command line processing
726 while ((option
= getopt(argc
, argv
, ":hzf:v")) != -1) {
735 sizecheck
= sscanf(optarg
, "%i", &i
);
736 if (sizecheck
!= 1) {
737 printf("firmware version of -f option not a valid integer\n");
740 fw_version
[0] = 0x000000FF & ( i
>> 8 );
741 fw_version
[1] = 0x000000FF & i
;
747 case ':': // option with missing operand
748 printf("Option -%c requires an operand\n", optopt
);
752 printf("Unrecognized option: -%c\n", optopt
);
759 for ( ; optind
< argc
; optind
++) {
760 if (par_filename
== NULL
) {
761 par_filename
= argv
[optind
];
763 if (access(par_filename
, R_OK
)) {
765 printf("No read access to zip file %s\n", par_filename
);
767 printf("No read access to parameter or zip file %s\n", par_filename
);
775 if (out_filename
== NULL
) {
776 out_filename
= argv
[optind
];
778 if (!access(out_filename
, F_OK
)) { // if file already exists then check write access
779 if (access(out_filename
, W_OK
)) {
780 printf("No write access to output file %s\n", out_filename
);
788 printf("Too many files stated\n");
794 if (par_filename
== NULL
) {
796 printf("Zip file not stated\n");
798 printf("Parameter file not stated\n");
802 base_filename
= basename(par_filename
);
803 if (base_filename
== NULL
) {
805 printf("Zip file is a directory\n");
807 printf("Parameter file is a directory\n");
813 if (out_filename
== NULL
) {
814 printf("Output file not stated\n");
817 base_filename
= basename(out_filename
);
818 if (base_filename
== NULL
) {
819 printf("Output file is a directory\n");
822 base_filename
= strdup(base_filename
);
823 zip_filename
= strrchr(base_filename
, '.');
824 if (zip_filename
!= NULL
) {
826 zip_filename
= NULL
; // clean up
831 // react on parameter problems or help request, and exit
832 if ((exitcode
!= 0) || help
) {
834 printf("This program creates Linksys style images for the WRT350Nv2 router.\n");
837 %s [-h] [-z] [-f <version>] [-v] <parameter or zip file> <output file>\n\n\
839 -h - Show this help\n\
840 -z - Have zip file, the img file will be directly created from it\n\
841 -f <version> - Wanted firmware version to use with -z\n\
842 Default firmware version is 0x2019 = 2.00.19.\n\
843 Note: version from parameter file will supersede this\n\
844 -v - Increase debug verbosity level\n\n\
846 %s wrt350nv2.par wrt350nv2.img\n\n", argv
[0], argv
[0]);
850 // handle special case when zipfile is stated
852 zip_filename
= par_filename
;
856 lprintf(DEBUG_LVL2
, " verbosity: %i\n", verbosity
);
857 lprintf(DEBUG_LVL2
, " program: %s\n", argv
[0]);
859 lprintf(DEBUG
, "Parameter file: %s\n", par_filename
);
860 lprintf(DEBUG
, "Output file: %s\n", out_filename
);
861 lprintf(DEBUG_LVL2
, " basename: %s (%i)\n", base_filename
, strlen(base_filename
));
864 // open files from command line
866 if (par_filename
!= NULL
) {
867 f_par
= fopen(par_filename
, "r");
870 printf("input file %s: %s\n", par_filename
, strerror(exitcode
));
875 f_out
= fopen(out_filename
, "w");
878 printf("Output file %s: %s\n", out_filename
, strerror(exitcode
));
886 // parameter file processing
887 if (!exitcode
&& par_filename
!= NULL
) {
888 lprintf(DEBUG
, "parsing parameter file...\n");
890 exitcode
= parse_par_file(f_par
);
892 lprintf(DEBUG
, "...done parsing file\n");
894 if (par_filename
!= NULL
) {
899 // check all input data
900 if (!exitcode
&& par_filename
!= NULL
) {
901 lprintf(DEBUG
, "checking mtd data...\n");
903 for (i
= 1; i
<= 3; i
++) {
914 sizecheck
= mtd_kernel
.size
- 16;
920 mtd
->offset
= mtd_kernel
.size
;
921 mtd
->size
= ROOTFS_END_OFFSET
- mtd_kernel
.size
;
923 sizecheck
= PRODUCT_ID_OFFSET
- mtd_kernel
.size
;
929 mtd
->offset
= BOOT_ADDR_BASE_OFF
;
931 sizecheck
= SN_OFF
- BOOT_ADDR_BASE_OFF
;
936 printf("unknown mtd check %i\n", i
);
943 lprintf(DEBUG_LVL2
, " checking mtd %s\n", mtd
->name
);
946 if (mandatory
&& mtd
->filename
== NULL
) {
948 printf("mtd %s not specified correctly or at all in parameter file\n", mtd
->name
);
951 // end checks if no file data present
952 if (mtd
->filename
== NULL
) {
956 // not updated by stock firmware
958 printf("mtd %s is specified, but will not be updated as of Linksys firmware 2.0.19\n", mtd
->name
);
961 // general magic number check
963 if (mtd
->magic
[0] != magic
[0] || mtd
->magic
[1] != magic
[1]) {
965 printf("mtd %s input file %s has wrong magic number (0x%02X%02X)\n", mtd
->name
, mtd
->filename
, mtd
->magic
[0], mtd
->magic
[1]);
969 // mtd specific size check
970 if (mtd
== &mtd_kernel
) {
971 if (mtd
->filesize
< 0x00050000) {
973 printf("mtd %s input file %s too unrealistic small (0x%08lX)\n", mtd
->name
, mtd
->filename
, mtd
->filesize
);
977 // general size check
979 if (sizecheck
<= 0) {
981 printf("mtd %s bad file size check (%i) due to input data\n", mtd
->name
, sizecheck
);
983 if (mtd
->filesize
> sizecheck
) {
985 printf("mtd %s input file %s too big (0x%08lX)\n", mtd
->name
, mtd
->filename
, mtd
->filesize
);
990 lprintf(DEBUG
, "...done checking mtd data\n");
994 // bin creation in memory
995 if (!exitcode
&& par_filename
!= NULL
) {
996 // create bin name from basename
997 bin_filename
= malloc(strlen(base_filename
)+10);
998 sprintf(bin_filename
, "%s.bin", base_filename
);
1000 lprintf(DEBUG
, "creating bin file %s...\n", bin_filename
);
1002 exitcode
= create_bin_file(bin_filename
);
1004 lprintf(DEBUG
, "...done creating bin file\n");
1008 // zip file creation
1009 if (!exitcode
&& zip_filename
== NULL
) {
1010 // create zip name from basename
1011 zip_filename
= malloc(strlen(base_filename
)+10);
1012 sprintf(zip_filename
, "%s.zip", base_filename
);
1014 lprintf(DEBUG
, "creating zip file %s...\n", zip_filename
);
1016 exitcode
= create_zip_file(zip_filename
, bin_filename
);
1018 lprintf(DEBUG
, "...done creating zip file\n");
1022 // img file creation
1024 lprintf(DEBUG
, "creating img file...\n");
1026 exitcode
= create_img_file(f_out
, out_filename
, zip_filename
);
1028 lprintf(DEBUG
, "...done creating img file\n");
This page took 0.146056 seconds and 5 git commands to generate.