9bc00066bace5a7027a0c44bc9f2f904847e1f70
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.
76 #include <sys/wait.h> // WEXITSTATUS, etc.
79 #include "md5.h" // MD5 routines
80 #include "upgrade.h" // Linksys definitions from firmware 2.0.19
85 char program_info
[] = "WRT350Nv2-Builder v%s by Dirk Teurlings <info@upexia.nl> and Matthias Buecher (http://www.maddes.net/)\n";
99 unsigned char magic
[2];
102 mtd_info mtd_kernel
= { "kernel", 0, 0, NULL
, 0L, { 0, 0 } };
103 mtd_info mtd_rootfs
= { "rootfs", 0, 0, NULL
, 0L, { 0, 0 } };
104 mtd_info mtd_uboot
= { "u-boot", 0, 0, NULL
, 0L, { 0, 0 } };
106 #define ROOTFS_END_OFFSET 0x00760000
107 #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
109 // rootfs statics via: hexdump -v -e '1/1 "0x%02X, "' -s 0x0075FFE0 -n 16 "wrt350n.bin" ; echo -en "\n"
110 unsigned char product_id
[] = { 0x00, 0x03 }; // seems to be a fixed value
111 unsigned char protocol_id
[] = { 0x00, 0x00 }; // seems to be a fixed value
112 unsigned char fw_version
[] = { 0x20, 0x19 };
113 unsigned char rootfs_unknown
[] = { 0x90, 0xF7 }; // seems to be a fixed value
114 unsigned char sign
[] = { 0x65, 0x52, 0x63, 0x4F, 0x6D, 0x4D, 0x00, 0x00 }; // eRcOmM
116 // u-boot statics via: hexdump -v -e '1/1 "0x%02X, "' -s 0x007FFF80 -n 128 "wrt350n.bin" ; echo -en "\n"
117 //unsigned char sn[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // (12) seems to be an unused value
118 //unsigned char pin[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // (8) seems to be an unused value
119 //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
120 // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
121 //unsigned char checksum[] = { 0xE9 }; // (1) is calculated, does it belong to node?
122 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
123 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
124 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, // protocol id?
125 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, // protocol id?
126 0x12, 0x34, // firmware version, same as in rootfs
127 0x00, 0x00, 0x00, 0x04,
128 0x73, 0x45, 0x72, 0x43, 0x6F, 0x4D, 0x6D }; // sErCoMm
130 // img statics via: hexdump -v -e '1/1 "0x%02X, "' -s 0 -n 512 "WRT350N-EU-ETSI-2.00.19.img" ; echo -en "\n"
131 unsigned char img_hdr
[] = { 0x00, 0x01, 0x00, 0x00, 0x59, 0x42, 0x50, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
132 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
133 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
135 0x12, 0x34, // firmware version, same as in rootfs
136 0x00, 0x00, 0x00, 0x04, 0x61, 0x44, 0x6D, 0x42, 0x6C, 0x4B, 0x3D, 0x00,
137 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, // md5 checksum
164 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
166 unsigned char img_eof
[] = { 0xFF };
169 void lprintf(int outputlevel
, char *fmt
, ...) {
171 if (outputlevel
<= verbosity
) {
179 int parse_par_file(FILE *f_par
) {
201 while (!feof(f_par
)) {
202 // read next line into memory
204 // allocate memory for input line
205 if (buffer
== NULL
) {
206 buffer
= malloc(buffer_size
);
208 if (buffer
== NULL
) {
210 printf("parse_par_file: can not allocate %i bytes\n", buffer_size
);
214 line
= fgets(buffer
, buffer_size
, f_par
);
216 exitcode
= ferror(f_par
);
218 printf("parse_par_file: %s\n", strerror(exitcode
));
223 // if buffer was not completely filled, then assume that line is complete
224 count
= strlen(buffer
) + 1;
225 if (count
-- < buffer_size
) {
231 // reset file position to line start
232 value
= fseek(f_par
, -count
, SEEK_CUR
);
235 printf("parse_par_file: %s\n", strerror(exitcode
));
239 // double buffer size
243 lprintf(DEBUG_LVL2
, " extending buffer to %i bytes\n", buffer_size
);
245 if (line
== NULL
|| exitcode
) {
249 lineno
++; // increase line number
251 lprintf(DEBUG_LVL2
, " line %i (%i) %s", lineno
, count
, line
);
258 // split line if starting with a colon
261 count
= sscanf(line
, ":%ms %i %ms", &string1
, &value
, &string2
);
263 printf("line %i does not meet defined format (:<mtdname> <mtdsize> <file>)\n", lineno
);
265 // populate mtd_info if supported mtd names
266 if (strcmp(string1
, mtd_kernel
.name
) == 0) {
268 } else if (strcmp(string1
, mtd_rootfs
.name
) == 0) {
270 } else if (strcmp(string1
, mtd_uboot
.name
) == 0) {
275 printf("unknown mtd %s in line %i\n", string1
, lineno
);
276 } else if (mtd
->filename
!= NULL
) {
278 printf("mtd %s in line %i multiple definitions\n", string1
, lineno
);
281 mtd
->filename
= string2
;
282 string2
= NULL
; // do not free
285 f_in
= fopen(mtd
->filename
, "rb");
288 printf("input file %s: %s\n", mtd
->filename
, strerror(f_exitcode
));
290 value
= fread(&mtd
->magic
, 1, 2, f_in
);
293 f_exitcode
= ferror(f_in
);
294 printf("input file %s: %s\n", mtd
->filename
, strerror(f_exitcode
));
297 printf("input file %s: smaller than two bytes, no magic code\n", mtd
->filename
);
301 value
= fseek(f_in
, 0, SEEK_END
);
304 printf("input file %s: %s\n", mtd
->filename
, strerror(f_exitcode
));
306 mtd
->filesize
= ftell(f_in
);
307 if (mtd
->filesize
== -1) {
309 printf("input file %s: %s\n", mtd
->filename
, strerror(f_exitcode
));
316 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
);
320 case '#': // integer values
321 count
= sscanf(line
, "#%ms %i", &string1
, &value
);
323 printf("line %i does not meet defined format (:<variable name> <integer>\n", lineno
);
325 if (strcmp(string1
, "version") == 0) {
327 fw_version
[0] = 0x000000FF & ( value
>> 8 );
328 fw_version
[1] = 0x000000FF & value
;
330 printf("unknown integer variable %s in line %i\n", string1
, lineno
);
333 lprintf(DEBUG
, "integer variable %s in line %i: 0x%08X\n", string1
, lineno
, value
);
337 count
= sscanf(line
, "$%ms %ms", &string1
, &string2
);
339 printf("line %i does not meet defined format (:<mtdname> <mtdsize> <file>)\n", lineno
);
342 if (strcmp(string1, "something") == 0) {
344 string2 = NULL; // do not free
347 printf("unknown string variable %s in line %i\n", string1
, lineno
);
349 lprintf(DEBUG
, "string variable %s in line %i: %s\n", string1
, lineno
, string2
);
366 exitcode
= f_exitcode
;
373 int create_bin_file(char *bin_filename
) {
376 unsigned char *buffer
;
383 char *rand_filename
= "/dev/urandom";
387 unsigned long int csum
;
388 unsigned char checksum
;
392 // allocate memory for bin file
393 buffer
= malloc(KERNEL_CODE_OFFSET
+ FLASH_SIZE
);
394 if (buffer
== NULL
) {
396 printf("create_bin_file: can not allocate %i bytes\n", FLASH_SIZE
);
398 // initialize with zero
399 memset(buffer
, 0, KERNEL_CODE_OFFSET
+ FLASH_SIZE
);
404 for (i
= 1; i
<= 3; i
++) {
414 addsize
= mtd
->filesize
;
415 padsize
= ROOTFS_MIN_OFFSET
- mtd_kernel
.size
- mtd
->filesize
;
419 addsize
= mtd
->filesize
;
424 printf("create_bin_file: unknown mtd %i\n", i
);
430 if (mtd
->filename
== NULL
) {
434 lprintf(DEBUG
, "adding mtd %s file %s\n", mtd
->name
, mtd
->filename
);
438 buffer
[KERNEL_CODE_OFFSET
+ mtd
->offset
- 16] = 0x000000FFL
& ( addsize
>> 24 );
439 buffer
[KERNEL_CODE_OFFSET
+ mtd
->offset
- 15] = 0x000000FFL
& ( addsize
>> 16 );
440 buffer
[KERNEL_CODE_OFFSET
+ mtd
->offset
- 14] = 0x000000FFL
& ( addsize
>> 8 );
441 buffer
[KERNEL_CODE_OFFSET
+ mtd
->offset
- 13] = 0x000000FFL
& addsize
;
444 // adding file content
445 f_in
= fopen(mtd
->filename
, "rb");
448 printf("input file %s: %s\n", mtd
->filename
, strerror(exitcode
));
450 size
= fread(&buffer
[KERNEL_CODE_OFFSET
+ mtd
->offset
], mtd
->filesize
, 1, f_in
);
453 exitcode
= ferror(f_in
);
454 printf("input file %s: %s\n", mtd
->filename
, strerror(exitcode
));
457 printf("input file %s: smaller than before *doh*\n", mtd
->filename
);
465 printf("mtd %s input file %s is too small (0x%08lX), adding 0x%08X random bytes\n", mtd
->name
, mtd
->filename
, mtd
->filesize
, padsize
);
467 addsize
= padsize
& 0x0000FFFF; // start on next 64KB border
469 addsize
+= KERNEL_CODE_OFFSET
+ mtd
->offset
+ mtd
->filesize
; // get offset
470 lprintf(DEBUG
, " padding offset 0x%08X length 0x%08X\n", addsize
, padsize
);
472 f_in
= fopen(rand_filename
, "rb");
475 printf("input file %s: %s\n", rand_filename
, strerror(exitcode
));
477 size
= fread(&buffer
[addsize
], padsize
, 1, f_in
);
480 exitcode
= ferror(f_in
);
481 printf("input file %s: %s\n", rand_filename
, strerror(exitcode
));
484 printf("input file %s: smaller than before *doh*\n", rand_filename
);
493 // add special contents
495 lprintf(DEBUG
, "adding rootfs special data\n");
496 memcpy(&buffer
[KERNEL_CODE_OFFSET
+ PRODUCT_ID_OFFSET
], product_id
, 2);
497 memcpy(&buffer
[KERNEL_CODE_OFFSET
+ PROTOCOL_ID_OFFSET
], protocol_id
, 2);
498 memcpy(&buffer
[KERNEL_CODE_OFFSET
+ FW_VERSION_OFFSET
], fw_version
, 2);
499 memcpy(&buffer
[KERNEL_CODE_OFFSET
+ FW_VERSION_OFFSET
+ 2], rootfs_unknown
, 2);
500 memcpy(&buffer
[KERNEL_CODE_OFFSET
+ SIGN_OFFSET
], sign
, 8); // eRcOmM
502 lprintf(DEBUG
, "adding u-boot special data 1/2\n"); // ToDo: or after creating the checksum byte?
503 // memcpy(&buffer[KERNEL_CODE_OFFSET + SN_OFF], sn, 12); // ToDo: find out what's this for?
504 // memcpy(&buffer[KERNEL_CODE_OFFSET + PIN_OFF], pin, 8); // ToDo: find out what's this for?
505 // memcpy(&buffer[KERNEL_CODE_OFFSET + NODE_BASE_OFF], node, 25); // ToDo: find out what's this for?
507 lprintf(DEBUG
, "adding checksum byte\n");
509 for (i
= 0; i
< KERNEL_CODE_OFFSET
+ FLASH_SIZE
; i
++) {
512 lprintf(DEBUG_LVL2
, " checksum 0x%016lX (%li)\n", csum
, csum
);
514 buffer
[KERNEL_CODE_OFFSET
+ NODE_BASE_OFF
+ 25] = ~(csum
+108)+1;
515 lprintf(DEBUG
, " byte 0x%02X\n", buffer
[KERNEL_CODE_OFFSET
+ NODE_BASE_OFF
+ 25]);
517 lprintf(DEBUG
, "adding u-boot special data 2/2\n");
518 memcpy(&buffer
[KERNEL_CODE_OFFSET
+ BOOT_ADDR_BASE_OFF
+ PID_OFFSET
], pid
, 70); // sErCoMm
519 memcpy(&buffer
[KERNEL_CODE_OFFSET
+ BOOT_ADDR_BASE_OFF
+ PID_OFFSET
+ 57], fw_version
, 2);
524 lprintf(DEBUG
, "writing file %s\n", bin_filename
);
525 f_out
= fopen(bin_filename
, "wb");
528 printf("output file %s: %s\n", bin_filename
, strerror(exitcode
));
530 size
= fwrite(buffer
, KERNEL_CODE_OFFSET
+ FLASH_SIZE
, 1, f_out
);
533 exitcode
= ferror(f_out
);
534 printf("output file %s: %s\n", bin_filename
, strerror(exitcode
));
537 printf("output file %s: unspecified write error\n", bin_filename
);
548 int create_zip_file(char *zip_filename
, char *bin_filename
) {
558 // allocate memory for command line
559 if (buffer
== NULL
) {
560 buffer
= malloc(buffer_size
);
562 if (buffer
== NULL
) {
564 printf("create_zip_file: can not allocate %i bytes\n", buffer_size
);
568 // if buffer was not completely filled, then line fit in completely
569 count
= snprintf(buffer
, buffer_size
, "zip %s %s", zip_filename
, bin_filename
);
570 if (count
> -1 && count
< buffer_size
) {
574 // otherwise try again with more space
575 if (count
> -1) { // glibc 2.1
576 buffer_size
= count
+ 1; // precisely what is needed
577 } else { // glibc 2.0
578 buffer_size
*= 2; // twice the old size
582 lprintf(DEBUG_LVL2
, " extending buffer to %i bytes\n", buffer_size
);
587 lprintf(DEBUG
, "%s\n", buffer
);
588 count
= system(buffer
);
589 if (count
< 0 || WEXITSTATUS(count
)) {
591 printf("create_zip_file: can not execute %s bytes\n", buffer
);
599 int create_img_file(FILE *f_out
, char *out_filename
, char *zip_filename
) {
603 md5_byte_t digest
[16];
609 unsigned char buffer
[1];
611 // copy firmware version
612 memcpy(&img_hdr
[50], fw_version
, 2);
614 // clear md5 checksum
615 memset(&img_hdr
[480], 0, 16);
617 // prepare md5 checksum calculation
621 lprintf(DEBUG_LVL2
, " adding img header\n");
622 for (i
= 0; i
< 512; i
++) {
623 size
= fputc(img_hdr
[i
], f_out
);
625 exitcode
= ferror(f_out
);
626 printf("output file %s: %s\n", out_filename
, strerror(exitcode
));
629 md5_append(&state
, (const md5_byte_t
*)&img_hdr
[i
], 1);
634 lprintf(DEBUG_LVL2
, " adding zip file\n");
635 f_in
= fopen(zip_filename
, "rb");
638 printf("input file %s: %s\n", zip_filename
, strerror(exitcode
));
640 while ((size
= fgetc(f_in
)) != EOF
) {
643 size
= fputc(buffer
[0], f_out
);
645 exitcode
= ferror(f_out
);
646 printf("output file %s: %s\n", out_filename
, strerror(exitcode
));
649 md5_append(&state
, (const md5_byte_t
*)buffer
, 1);
652 exitcode
= ferror(f_in
);
653 printf("input file %s: %s\n", zip_filename
, strerror(exitcode
));
661 lprintf(DEBUG_LVL2
, " adding img eof byte\n");
662 size
= fputc(img_eof
[0], f_out
);
664 exitcode
= ferror(f_out
);
665 printf("output file %s: %s\n", out_filename
, strerror(exitcode
));
667 md5_append(&state
, (const md5_byte_t
*)img_eof
, 1);
670 // append salt to md5 checksum
671 md5_append(&state
, (const md5_byte_t
*)"A^gU*<>?RFY@#DR&Z", 17);
673 // finish md5 checksum calculation
674 md5_finish(&state
, digest
);
676 // write md5 checksum into img header
678 lprintf(DEBUG_LVL2
, " writing md5 checksum into img header of file\n");
680 size
= fseek(f_out
, 480, SEEK_SET
);
683 printf("output file %s: %s\n", out_filename
, strerror(exitcode
));
685 size
= fwrite(digest
, 16, 1, f_out
);
688 exitcode
= ferror(f_out
);
689 printf("output file %s: %s\n", out_filename
, strerror(exitcode
));
692 printf("output file %s: unspecified write error\n", out_filename
);
704 int main(int argc
, char *argv
[]) {
710 char *par_filename
= NULL
;
711 char *out_filename
= NULL
;
712 char *base_filename
= NULL
;
713 char *bin_filename
= NULL
;
714 char *zip_filename
= NULL
;
724 unsigned char magic
[2];
727 // display program header
728 printf(program_info
, VERSION
);
731 // command line processing
735 while ((option
= getopt(argc
, argv
, ":hzf:v")) != -1) {
744 sizecheck
= sscanf(optarg
, "%i", &i
);
745 if (sizecheck
!= 1) {
746 printf("firmware version of -f option not a valid integer\n");
749 fw_version
[0] = 0x000000FF & ( i
>> 8 );
750 fw_version
[1] = 0x000000FF & i
;
756 case ':': // option with missing operand
757 printf("Option -%c requires an operand\n", optopt
);
761 printf("Unrecognized option: -%c\n", optopt
);
768 for ( ; optind
< argc
; optind
++) {
769 if (par_filename
== NULL
) {
770 par_filename
= argv
[optind
];
772 if (access(par_filename
, R_OK
)) {
774 printf("No read access to zip file %s\n", par_filename
);
776 printf("No read access to parameter or zip file %s\n", par_filename
);
784 if (out_filename
== NULL
) {
785 out_filename
= argv
[optind
];
787 if (!access(out_filename
, F_OK
)) { // if file already exists then check write access
788 if (access(out_filename
, W_OK
)) {
789 printf("No write access to output file %s\n", out_filename
);
797 printf("Too many files stated\n");
803 if (par_filename
== NULL
) {
805 printf("Zip file not stated\n");
807 printf("Parameter file not stated\n");
811 base_filename
= basename(par_filename
);
812 if (base_filename
== NULL
) {
814 printf("Zip file is a directory\n");
816 printf("Parameter file is a directory\n");
822 if (out_filename
== NULL
) {
823 printf("Output file not stated\n");
826 base_filename
= basename(out_filename
);
827 if (base_filename
== NULL
) {
828 printf("Output file is a directory\n");
831 base_filename
= strdup(base_filename
);
832 zip_filename
= strrchr(base_filename
, '.');
833 if (zip_filename
!= NULL
) {
835 zip_filename
= NULL
; // clean up
840 // react on parameter problems or help request, and exit
841 if ((exitcode
!= 0) || help
) {
843 printf("This program creates Linksys style images for the WRT350Nv2 router.\n");
846 %s [-h] [-z] [-f <version>] [-v] <parameter or zip file> <output file>\n\n\
848 -h - Show this help\n\
849 -z - Have zip file, the img file will be directly created from it\n\
850 -f <version> - Wanted firmware version to use with -z\n\
851 Default firmware version is 0x2019 = 2.00.19.\n\
852 Note: version from parameter file will supersede this\n\
853 -v - Increase debug verbosity level\n\n\
855 %s wrt350nv2.par wrt350nv2.img\n\n", argv
[0], argv
[0]);
859 // handle special case when zipfile is stated
861 zip_filename
= par_filename
;
865 lprintf(DEBUG_LVL2
, " verbosity: %i\n", verbosity
);
866 lprintf(DEBUG_LVL2
, " program: %s\n", argv
[0]);
868 lprintf(DEBUG
, "Parameter file: %s\n", par_filename
);
869 lprintf(DEBUG
, "Output file: %s\n", out_filename
);
870 lprintf(DEBUG_LVL2
, " basename: %s (%i)\n", base_filename
, strlen(base_filename
));
873 // open files from command line
875 if (par_filename
!= NULL
) {
876 f_par
= fopen(par_filename
, "r");
879 printf("input file %s: %s\n", par_filename
, strerror(exitcode
));
884 f_out
= fopen(out_filename
, "w");
887 printf("Output file %s: %s\n", out_filename
, strerror(exitcode
));
895 // parameter file processing
896 if (!exitcode
&& par_filename
!= NULL
) {
897 lprintf(DEBUG
, "parsing parameter file...\n");
899 exitcode
= parse_par_file(f_par
);
901 lprintf(DEBUG
, "...done parsing file\n");
903 if (par_filename
!= NULL
) {
908 // check all input data
909 if (!exitcode
&& par_filename
!= NULL
) {
910 lprintf(DEBUG
, "checking mtd data...\n");
912 for (i
= 1; i
<= 3; i
++) {
923 sizecheck
= mtd_kernel
.size
- 16;
929 mtd
->offset
= mtd_kernel
.size
;
930 mtd
->size
= ROOTFS_END_OFFSET
- mtd_kernel
.size
;
932 sizecheck
= PRODUCT_ID_OFFSET
- mtd_kernel
.size
;
938 mtd
->offset
= BOOT_ADDR_BASE_OFF
;
940 sizecheck
= SN_OFF
- BOOT_ADDR_BASE_OFF
;
945 printf("unknown mtd check %i\n", i
);
952 lprintf(DEBUG_LVL2
, " checking mtd %s\n", mtd
->name
);
955 if (mandatory
&& mtd
->filename
== NULL
) {
957 printf("mtd %s not specified correctly or at all in parameter file\n", mtd
->name
);
960 // end checks if no file data present
961 if (mtd
->filename
== NULL
) {
965 // not updated by stock firmware
967 printf("mtd %s is specified, but will not be updated as of Linksys firmware 2.0.19\n", mtd
->name
);
970 // general magic number check
972 if (mtd
->magic
[0] != magic
[0] || mtd
->magic
[1] != magic
[1]) {
974 printf("mtd %s input file %s has wrong magic number (0x%02X%02X)\n", mtd
->name
, mtd
->filename
, mtd
->magic
[0], mtd
->magic
[1]);
978 // mtd specific size check
979 if (mtd
== &mtd_kernel
) {
980 if (mtd
->filesize
< 0x00050000) {
982 printf("mtd %s input file %s too unrealistic small (0x%08lX)\n", mtd
->name
, mtd
->filesize
);
986 // general size check
988 if (sizecheck
<= 0) {
990 printf("mtd %s bad file size check (%i) due to input data\n", mtd
->name
, sizecheck
);
992 if (mtd
->filesize
> sizecheck
) {
994 printf("mtd %s input file %s too big (0x%08lX)\n", mtd
->name
, mtd
->filename
, mtd
->filesize
);
999 lprintf(DEBUG
, "...done checking mtd data\n");
1003 // bin creation in memory
1004 if (!exitcode
&& par_filename
!= NULL
) {
1005 // create bin name from basename
1006 bin_filename
= malloc(strlen(base_filename
)+10);
1007 sprintf(bin_filename
, "%s.bin", base_filename
);
1009 lprintf(DEBUG
, "creating bin file %s...\n", bin_filename
);
1011 exitcode
= create_bin_file(bin_filename
);
1013 lprintf(DEBUG
, "...done creating bin file\n");
1017 // zip file creation
1018 if (!exitcode
&& zip_filename
== NULL
) {
1019 // create zip name from basename
1020 zip_filename
= malloc(strlen(base_filename
)+10);
1021 sprintf(zip_filename
, "%s.zip", base_filename
);
1023 lprintf(DEBUG
, "creating zip file %s...\n", zip_filename
);
1025 exitcode
= create_zip_file(zip_filename
, bin_filename
);
1027 lprintf(DEBUG
, "...done creating zip file\n");
1031 // img file creation
1033 lprintf(DEBUG
, "creating img file...\n");
1035 exitcode
= create_img_file(f_out
, out_filename
, zip_filename
);
1037 lprintf(DEBUG
, "...done creating img file\n");
This page took 0.117514 seconds and 3 git commands to generate.