OpenWrt – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | |||
3 | WRT350Nv2-Builder 2.4 (previously called buildimg) |
||
4 | Copyright (C) 2008-2009 Dirk Teurlings <info@upexia.nl> |
||
5 | Copyright (C) 2009-2011 Matthias Buecher (http://www.maddes.net/) |
||
6 | |||
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. |
||
11 | |||
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. |
||
16 | |||
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 |
||
20 | |||
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. |
||
24 | |||
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. |
||
29 | |||
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 |
||
34 | #version 0x2020 |
||
35 | |||
36 | Additionally since v2.4 an already complete image can be used: |
||
37 | :image 0 /path/to/openwrt-wrt350nv2-[squashfs|jffs2-64k].img |
||
38 | |||
39 | args: |
||
40 | 1 wrt350nv2.par parameter file describing the image layout |
||
41 | 2 wrt350nv2.img output file for linksys style image |
||
42 | |||
43 | A u-boot image inside the bin file is not necessary. |
||
44 | The version is not important. |
||
45 | The name of the bin file is not important, but still "wrt350n.bin" is used to |
||
46 | keep as close as possible to the stock firmware. |
||
47 | |||
48 | Linksys assumes that no mtd will be used to its maximum, so the last 16 bytes |
||
49 | of the mtd are abused to define the length of the next mtd content (4 bytes for |
||
50 | size + 12 pad bytes). |
||
51 | |||
52 | At the end of "rootfs" additional 16 bytes are abused for some data and a |
||
53 | highly important eRcOmM identifier, so the last 32 bytes of "rootfs" are abused. |
||
54 | |||
55 | At the end of "u-boot" 128 bytes are abused for some data, a checksum and a |
||
56 | highly important sErCoMm identifier. |
||
57 | |||
58 | |||
59 | This program uses a special GNU scanf modifier to allocate |
||
60 | sufficient memory for a strings with unknown length. |
||
61 | See http://www.kernel.org/doc/man-pages/online/pages/man3/scanf.3.html#NOTES |
||
62 | |||
63 | |||
64 | To extract everything from a Linksys style firmware image see |
||
65 | https://forum.openwrt.org/viewtopic.php?pid=92928#p92928 |
||
66 | |||
67 | Changelog: |
||
68 | v2.4 - added ":image" definition for parameter file, this allows |
||
69 | to use a complete sysupgrade image without any kernel size check |
||
70 | v2.3 - allow jffs by adding its magic number (0x8519) |
||
71 | added parameter option -i to ignore unknown magic numbers |
||
72 | v2.2 - fixed checksum byte calculation for other versions than 0x2019 |
||
73 | fixed rare problem with padsize |
||
74 | updated info to stock firmware 2.00.20 |
||
75 | fixed typos |
||
76 | v2.1 - used "wrt350n.bin" for the created image (closer to stock) |
||
77 | added option to create the image in two separate steps (-b / -z) |
||
78 | v2.0 - complete re-write |
||
79 | |||
80 | */ |
||
81 | |||
82 | // includes |
||
83 | #define _GNU_SOURCE // for GNU's basename() |
||
84 | #include <assert.h> |
||
85 | #include <errno.h> // errno |
||
86 | #include <stdarg.h> |
||
87 | #include <stdio.h> // fopen(), fread(), fclose(), etc. |
||
88 | #include <stdlib.h> // system(), etc. |
||
89 | #include <string.h> // basename(), strerror(), strdup(), etc. |
||
90 | #include <unistd.h> // optopt(), access(), etc. |
||
91 | #include <libgen.h> |
||
92 | #include <sys/wait.h> // WEXITSTATUS, etc. |
||
93 | |||
94 | // custom includes |
||
95 | #include "md5.h" // MD5 routines |
||
96 | #include "upgrade.h" // Linksys definitions from firmware 2.0.19 (unchanged up to 2.0.20) |
||
97 | |||
98 | |||
99 | // version info |
||
100 | #define VERSION "2.4" |
||
101 | char program_info[] = "WRT350Nv2-Builder v%s by Dirk Teurlings <info@upexia.nl> and Matthias Buecher (http://www.maddes.net/)\n"; |
||
102 | |||
103 | // verbosity |
||
104 | #define DEBUG 1 |
||
105 | #define DEBUG_LVL2 2 |
||
106 | int verbosity = 0; |
||
107 | |||
108 | // mtd info |
||
109 | typedef struct { |
||
110 | char *name; |
||
111 | int offset; |
||
112 | int size; |
||
113 | char *filename; |
||
114 | long int filesize; |
||
115 | unsigned char magic[2]; |
||
116 | } mtd_info; |
||
117 | |||
118 | mtd_info mtd_kernel = { "kernel", 0, 0, NULL, 0L, { 0, 0 } }; |
||
119 | mtd_info mtd_rootfs = { "rootfs", 0, 0, NULL, 0L, { 0, 0 } }; |
||
120 | mtd_info mtd_image = { "image", 0, 0, NULL, 0L, { 0, 0 } }; |
||
121 | mtd_info mtd_uboot = { "u-boot", 0, 0, NULL, 0L, { 0, 0 } }; |
||
122 | |||
123 | #define ROOTFS_END_OFFSET 0x00760000 |
||
124 | #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 |
||
125 | // 2.0.17: filled up to 0x00640000 |
||
126 | // 2.0.19: filled up to 0x00670000 |
||
127 | // 2.0.20: filled up to 0x00670000 |
||
128 | |||
129 | // rootfs statics via: hexdump -v -e '1/1 "0x%02X, "' -s 0x0075FFE0 -n 16 "wrt350n.bin" ; echo -en "\n" |
||
130 | unsigned char product_id[] = { 0x00, 0x03 }; // seems to be a fixed value |
||
131 | unsigned char protocol_id[] = { 0x00, 0x00 }; // seems to be a fixed value |
||
132 | unsigned char fw_version[] = { 0x20, 0x20 }; |
||
133 | unsigned char rootfs_unknown[] = { 0x90, 0xF7 }; // seems to be a fixed value |
||
134 | unsigned char sign[] = { 0x65, 0x52, 0x63, 0x4F, 0x6D, 0x4D, 0x00, 0x00 }; // eRcOmM |
||
135 | |||
136 | // u-boot statics via: hexdump -v -e '1/1 "0x%02X, "' -s 0x007FFF80 -n 128 "wrt350n.bin" ; echo -en "\n" |
||
137 | //unsigned char sn[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // (12) seems to be an unused value |
||
138 | //unsigned char pin[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // (8) seems to be an unused value |
||
139 | //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 |
||
140 | // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; |
||
141 | //unsigned char checksum[] = { 0xE9 }; // (1) is calculated, does it belong to node? |
||
142 | 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 |
||
143 | 0x10, 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, 0x03, 0x00, // protocol id? |
||
145 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, // protocol id? |
||
146 | 0x12, 0x34, // firmware version, same as in rootfs |
||
147 | 0x00, 0x00, 0x00, 0x04, |
||
148 | 0x73, 0x45, 0x72, 0x43, 0x6F, 0x4D, 0x6D }; // sErCoMm |
||
149 | |||
150 | // 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) |
||
151 | unsigned char img_hdr[] = { 0x00, 0x01, 0x00, 0x00, 0x59, 0x42, 0x50, 0x00, 0x01, 0x10, 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, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, |
||
154 | 0x00, 0x00, |
||
155 | 0x12, 0x34, // firmware version, same as in rootfs |
||
156 | 0x00, 0x00, 0x00, 0x04, 0x61, 0x44, 0x6D, 0x42, 0x6C, 0x4B, 0x3D, 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 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||
176 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||
177 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||
178 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||
179 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||
180 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||
181 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||
182 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||
183 | 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, // md5 checksum |
||
184 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; |
||
185 | |||
186 | unsigned char img_eof[] = { 0xFF }; |
||
187 | |||
188 | |||
189 | void lprintf(int outputlevel, char *fmt, ...) { |
||
190 | va_list argp; |
||
191 | if (outputlevel <= verbosity) { |
||
192 | va_start(argp, fmt); |
||
193 | vprintf(fmt, argp); |
||
194 | va_end(argp); |
||
195 | } |
||
196 | } |
||
197 | |||
198 | |||
199 | int parse_par_file(FILE *f_par) { |
||
200 | int exitcode = 0; |
||
201 | |||
202 | char *buffer; |
||
203 | size_t buffer_size; |
||
204 | char *line; |
||
205 | |||
206 | int lineno; |
||
207 | int count; |
||
208 | |||
209 | char string1[256]; |
||
210 | char string2[256]; |
||
211 | int value; |
||
212 | |||
213 | mtd_info *mtd; |
||
214 | FILE *f_in; |
||
215 | int f_exitcode = 0; |
||
216 | |||
217 | // read all lines |
||
218 | buffer_size = 1000; |
||
219 | buffer = NULL; |
||
220 | lineno = 0; |
||
221 | while (!feof(f_par)) { |
||
222 | // read next line into memory |
||
223 | do { |
||
224 | // allocate memory for input line |
||
225 | if (!buffer) { |
||
226 | buffer = malloc(buffer_size); |
||
227 | } |
||
228 | if (!buffer) { |
||
229 | exitcode = 1; |
||
230 | printf("parse_par_file: can not allocate %i bytes\n", (int) buffer_size); |
||
231 | break; |
||
232 | } |
||
233 | |||
234 | line = fgets(buffer, buffer_size, f_par); |
||
235 | if (!line) { |
||
236 | exitcode = ferror(f_par); |
||
237 | if (exitcode) { |
||
238 | printf("parse_par_file: %s\n", strerror(exitcode)); |
||
239 | } |
||
240 | break; |
||
241 | } |
||
242 | |||
243 | // if buffer was not completely filled, then assume that line is complete |
||
244 | count = strlen(buffer) + 1; |
||
245 | if (count-- < buffer_size) { |
||
246 | break; |
||
247 | } |
||
248 | |||
249 | // otherwise.... |
||
250 | |||
251 | // reset file position to line start |
||
252 | value = fseek(f_par, -count, SEEK_CUR); |
||
253 | if (value == -1) { |
||
254 | exitcode = errno; |
||
255 | printf("parse_par_file: %s\n", strerror(exitcode)); |
||
256 | break; |
||
257 | } |
||
258 | |||
259 | // double buffer size |
||
260 | free(buffer); |
||
261 | buffer = NULL; |
||
262 | buffer_size *= 2; |
||
263 | lprintf(DEBUG_LVL2, " extending buffer to %i bytes\n", buffer_size); |
||
264 | } while (1); |
||
265 | if ((!line) || (exitcode)) { |
||
266 | break; |
||
267 | } |
||
268 | |||
269 | lineno++; // increase line number |
||
270 | |||
271 | lprintf(DEBUG_LVL2, " line %i (%i) %s", lineno, count, line); |
||
272 | |||
273 | value = 0; |
||
274 | mtd = NULL; |
||
275 | |||
276 | // split line if starting with a colon |
||
277 | switch (line[0]) { |
||
278 | case ':': |
||
279 | count = sscanf(line, ":%255s %i %255s", string1, &value, string2); |
||
280 | if (count != 3) { |
||
281 | printf("line %i does not meet defined format (:<mtdname> <mtdsize> <file>)\n", lineno); |
||
282 | } else { |
||
283 | // populate mtd_info if supported mtd names |
||
284 | if (!strcmp(string1, mtd_kernel.name)) { |
||
285 | mtd = &mtd_kernel; |
||
286 | } else if (!strcmp(string1, mtd_rootfs.name)) { |
||
287 | mtd = &mtd_rootfs; |
||
288 | } else if (!strcmp(string1, mtd_uboot.name)) { |
||
289 | mtd = &mtd_uboot; |
||
290 | } else if (!strcmp(string1, mtd_image.name)) { |
||
291 | mtd = &mtd_image; |
||
292 | } |
||
293 | |||
294 | if (!mtd) { |
||
295 | printf("unknown mtd %s in line %i\n", string1, lineno); |
||
296 | } else if (mtd->filename) { |
||
297 | f_exitcode = 1; |
||
298 | printf("mtd %s in line %i multiple definitions\n", string1, lineno); |
||
299 | } else { |
||
300 | mtd->size = value; |
||
301 | mtd->filename = strdup(string2); |
||
302 | |||
303 | // Get file size |
||
304 | f_in = fopen(mtd->filename, "rb"); |
||
305 | if (!f_in) { |
||
306 | f_exitcode = errno; |
||
307 | printf("input file %s: %s\n", mtd->filename, strerror(f_exitcode)); |
||
308 | } else { |
||
309 | value = fread(&mtd->magic, 1, 2, f_in); |
||
310 | if (value < 2) { |
||
311 | if (ferror(f_in)) { |
||
312 | f_exitcode = ferror(f_in); |
||
313 | printf("input file %s: %s\n", mtd->filename, strerror(f_exitcode)); |
||
314 | } else { |
||
315 | f_exitcode = 1; |
||
316 | printf("input file %s: smaller than two bytes, no magic code\n", mtd->filename); |
||
317 | } |
||
318 | } |
||
319 | |||
320 | value = fseek(f_in, 0, SEEK_END); |
||
321 | if (value == -1) { |
||
322 | f_exitcode = errno; |
||
323 | printf("input file %s: %s\n", mtd->filename, strerror(f_exitcode)); |
||
324 | } else { |
||
325 | mtd->filesize = ftell(f_in); |
||
326 | if (mtd->filesize == -1) { |
||
327 | f_exitcode = errno; |
||
328 | printf("input file %s: %s\n", mtd->filename, strerror(f_exitcode)); |
||
329 | } |
||
330 | } |
||
331 | |||
332 | fclose(f_in); |
||
333 | } |
||
334 | |||
335 | 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); |
||
336 | } |
||
337 | } |
||
338 | break; |
||
339 | case '#': // integer values |
||
340 | count = sscanf(line, "#%255s %i", string1, &value); |
||
341 | if (count != 2) { |
||
342 | printf("line %i does not meet defined format (#<variable name> <integer>\n", lineno); |
||
343 | } else { |
||
344 | if (!strcmp(string1, "version")) { |
||
345 | // changing version |
||
346 | fw_version[0] = 0x000000FF & ( value >> 8 ); |
||
347 | fw_version[1] = 0x000000FF & value; |
||
348 | } else { |
||
349 | printf("unknown integer variable %s in line %i\n", string1, lineno); |
||
350 | } |
||
351 | |||
352 | lprintf(DEBUG, "integer variable %s in line %i: 0x%08X\n", string1, lineno, value); |
||
353 | } |
||
354 | break; |
||
355 | case '$': // strings |
||
356 | count = sscanf(line, "$%255s %255s", string1, string2); |
||
357 | if (count != 2) { |
||
358 | printf("line %i does not meet defined format (:<mtdname> <mtdsize> <file>)\n", lineno); |
||
359 | } else { |
||
360 | /* |
||
361 | if (!strcmp(string1, "something")) { |
||
362 | something = strdup(string2); |
||
363 | } else { |
||
364 | */ |
||
365 | printf("unknown string variable %s in line %i\n", string1, lineno); |
||
366 | // } |
||
367 | lprintf(DEBUG, "string variable %s in line %i: %s\n", string1, lineno, string2); |
||
368 | } |
||
369 | break; |
||
370 | default: |
||
371 | break; |
||
372 | } |
||
373 | } |
||
374 | free(buffer); |
||
375 | |||
376 | if (!exitcode) { |
||
377 | exitcode = f_exitcode; |
||
378 | } |
||
379 | |||
380 | return exitcode; |
||
381 | } |
||
382 | |||
383 | |||
384 | int create_bin_file(char *bin_filename) { |
||
385 | int exitcode = 0; |
||
386 | |||
387 | unsigned char *buffer; |
||
388 | |||
389 | int i; |
||
390 | mtd_info *mtd; |
||
391 | int addsize; |
||
392 | int padsize; |
||
393 | |||
394 | char *rand_filename = "/dev/urandom"; |
||
395 | FILE *f_in; |
||
396 | int size; |
||
397 | |||
398 | unsigned long int csum; |
||
399 | unsigned char checksum; |
||
400 | |||
401 | FILE *f_out; |
||
402 | |||
403 | // allocate memory for bin file |
||
404 | buffer = malloc(KERNEL_CODE_OFFSET + FLASH_SIZE); |
||
405 | if (!buffer) { |
||
406 | exitcode = 1; |
||
407 | printf("create_bin_file: can not allocate %i bytes\n", FLASH_SIZE); |
||
408 | } else { |
||
409 | // initialize with zero |
||
410 | memset(buffer, 0, KERNEL_CODE_OFFSET + FLASH_SIZE); |
||
411 | } |
||
412 | |||
413 | // add files |
||
414 | if (!exitcode) { |
||
415 | for (i = 1; i <= 4; i++) { |
||
416 | addsize = 0; |
||
417 | padsize = 0; |
||
418 | |||
419 | switch (i) { |
||
420 | case 1: |
||
421 | mtd = &mtd_image; |
||
422 | padsize = ROOTFS_MIN_OFFSET - mtd->filesize; |
||
423 | break; |
||
424 | case 2: |
||
425 | mtd = &mtd_kernel; |
||
426 | break; |
||
427 | case 3: |
||
428 | mtd = &mtd_rootfs; |
||
429 | addsize = mtd->filesize; |
||
430 | padsize = ROOTFS_MIN_OFFSET - mtd_kernel.size - mtd->filesize; |
||
431 | break; |
||
432 | case 4: |
||
433 | mtd = &mtd_uboot; |
||
434 | addsize = mtd->filesize; |
||
435 | break; |
||
436 | default: |
||
437 | mtd = NULL; |
||
438 | exitcode = 1; |
||
439 | printf("create_bin_file: unknown mtd %i\n", i); |
||
440 | break; |
||
441 | } |
||
442 | if (!mtd) { |
||
443 | break; |
||
444 | } |
||
445 | if (!mtd->filename) { |
||
446 | continue; |
||
447 | } |
||
448 | |||
449 | lprintf(DEBUG, "adding mtd %s file %s\n", mtd->name, mtd->filename); |
||
450 | |||
451 | // adding file size |
||
452 | if (addsize) { |
||
453 | buffer[KERNEL_CODE_OFFSET + mtd->offset - 16] = 0x000000FFL & ( addsize >> 24 ); |
||
454 | buffer[KERNEL_CODE_OFFSET + mtd->offset - 15] = 0x000000FFL & ( addsize >> 16 ); |
||
455 | buffer[KERNEL_CODE_OFFSET + mtd->offset - 14] = 0x000000FFL & ( addsize >> 8 ); |
||
456 | buffer[KERNEL_CODE_OFFSET + mtd->offset - 13] = 0x000000FFL & addsize; |
||
457 | } |
||
458 | |||
459 | // adding file content |
||
460 | f_in = fopen(mtd->filename, "rb"); |
||
461 | if (!f_in) { |
||
462 | exitcode = errno; |
||
463 | printf("input file %s: %s\n", mtd->filename, strerror(exitcode)); |
||
464 | } else { |
||
465 | size = fread(&buffer[KERNEL_CODE_OFFSET + mtd->offset], mtd->filesize, 1, f_in); |
||
466 | if (size < 1) { |
||
467 | if (ferror(f_in)) { |
||
468 | exitcode = ferror(f_in); |
||
469 | printf("input file %s: %s\n", mtd->filename, strerror(exitcode)); |
||
470 | } else { |
||
471 | exitcode = 1; |
||
472 | printf("input file %s: smaller than before *doh*\n", mtd->filename); |
||
473 | } |
||
474 | } |
||
475 | fclose(f_in); |
||
476 | } |
||
477 | |||
478 | // padding |
||
479 | if (padsize > 0) { |
||
480 | addsize = padsize & 0x0000FFFF; // start on next 64KB border |
||
481 | padsize -= addsize; |
||
482 | } |
||
483 | if (padsize > 0) { |
||
484 | printf("mtd %s input file %s is too small (0x%08lX), adding 0x%08X random bytes\n", mtd->name, mtd->filename, mtd->filesize, padsize); |
||
485 | |||
486 | addsize += KERNEL_CODE_OFFSET + mtd->offset + mtd->filesize; // get offset |
||
487 | lprintf(DEBUG, " padding offset 0x%08X length 0x%08X\n", addsize, padsize); |
||
488 | |||
489 | f_in = fopen(rand_filename, "rb"); |
||
490 | if (!f_in) { |
||
491 | exitcode = errno; |
||
492 | printf("input file %s: %s\n", rand_filename, strerror(exitcode)); |
||
493 | } else { |
||
494 | size = fread(&buffer[addsize], padsize, 1, f_in); |
||
495 | if (size < 1) { |
||
496 | if (ferror(f_in)) { |
||
497 | exitcode = ferror(f_in); |
||
498 | printf("input file %s: %s\n", rand_filename, strerror(exitcode)); |
||
499 | } else { |
||
500 | exitcode = 1; |
||
501 | printf("input file %s: smaller than before *doh*\n", rand_filename); |
||
502 | } |
||
503 | } |
||
504 | } |
||
505 | fclose(f_in); |
||
506 | } |
||
507 | } |
||
508 | } |
||
509 | |||
510 | // add special contents |
||
511 | if (!exitcode) { |
||
512 | lprintf(DEBUG, "adding rootfs special data\n"); |
||
513 | memcpy(&buffer[KERNEL_CODE_OFFSET + PRODUCT_ID_OFFSET], product_id, 2); |
||
514 | memcpy(&buffer[KERNEL_CODE_OFFSET + PROTOCOL_ID_OFFSET], protocol_id, 2); |
||
515 | memcpy(&buffer[KERNEL_CODE_OFFSET + FW_VERSION_OFFSET], fw_version, 2); |
||
516 | memcpy(&buffer[KERNEL_CODE_OFFSET + FW_VERSION_OFFSET + 2], rootfs_unknown, 2); |
||
517 | memcpy(&buffer[KERNEL_CODE_OFFSET + SIGN_OFFSET], sign, 8); // eRcOmM |
||
518 | |||
519 | lprintf(DEBUG, "adding u-boot special data\n"); |
||
520 | // memcpy(&buffer[KERNEL_CODE_OFFSET + SN_OFF], sn, 12); // ToDo: currently zero, find out what's this for? |
||
521 | // memcpy(&buffer[KERNEL_CODE_OFFSET + PIN_OFF], pin, 8); // ToDo: currently zero, find out what's this for? |
||
522 | // memcpy(&buffer[KERNEL_CODE_OFFSET + NODE_BASE_OFF], node, 25); // ToDo: currently zero, find out what's this for? |
||
523 | memcpy(&buffer[KERNEL_CODE_OFFSET + BOOT_ADDR_BASE_OFF + PID_OFFSET], pid, 70); // sErCoMm |
||
524 | memcpy(&buffer[KERNEL_CODE_OFFSET + BOOT_ADDR_BASE_OFF + PID_OFFSET + 57], fw_version, 2); |
||
525 | |||
526 | lprintf(DEBUG, "adding checksum byte\n"); |
||
527 | csum = 0; |
||
528 | for (i = 0; i < KERNEL_CODE_OFFSET + FLASH_SIZE; i++) { |
||
529 | csum += buffer[i]; |
||
530 | } |
||
531 | lprintf(DEBUG_LVL2, " checksum 0x%016lX (%li)\n", csum, csum); |
||
532 | |||
533 | buffer[KERNEL_CODE_OFFSET + NODE_BASE_OFF + 25] = ~csum + 1; |
||
534 | lprintf(DEBUG, " byte 0x%02X\n", buffer[KERNEL_CODE_OFFSET + NODE_BASE_OFF + 25]); |
||
535 | } |
||
536 | |||
537 | // write bin file |
||
538 | if (!exitcode) { |
||
539 | lprintf(DEBUG, "writing file %s\n", bin_filename); |
||
540 | f_out = fopen(bin_filename, "wb"); |
||
541 | if (!f_out) { |
||
542 | exitcode = errno; |
||
543 | printf("output file %s: %s\n", bin_filename, strerror(exitcode)); |
||
544 | } else { |
||
545 | size = fwrite(buffer, KERNEL_CODE_OFFSET + FLASH_SIZE, 1, f_out); |
||
546 | if (size < 1) { |
||
547 | if (ferror(f_out)) { |
||
548 | exitcode = ferror(f_out); |
||
549 | printf("output file %s: %s\n", bin_filename, strerror(exitcode)); |
||
550 | } else { |
||
551 | exitcode = 1; |
||
552 | printf("output file %s: unspecified write error\n", bin_filename); |
||
553 | } |
||
554 | } |
||
555 | fclose(f_out); |
||
556 | } |
||
557 | } |
||
558 | |||
559 | return exitcode; |
||
560 | } |
||
561 | |||
562 | |||
563 | int create_zip_file(char *zip_filename, char *bin_filename) { |
||
564 | int exitcode = 0; |
||
565 | |||
566 | char *buffer; |
||
567 | size_t buffer_size; |
||
568 | int count; |
||
569 | |||
570 | buffer_size = 1000; |
||
571 | buffer = NULL; |
||
572 | do { |
||
573 | // allocate memory for command line |
||
574 | if (!buffer) { |
||
575 | buffer = malloc(buffer_size); |
||
576 | } |
||
577 | if (!buffer) { |
||
578 | exitcode = 1; |
||
579 | printf("create_zip_file: can not allocate %i bytes\n", (int) buffer_size); |
||
580 | break; |
||
581 | } |
||
582 | |||
583 | // if buffer was not completely filled, then line fit in completely |
||
584 | count = snprintf(buffer, buffer_size, "zip \"%s\" \"%s\"", zip_filename, bin_filename); |
||
585 | if ((count > -1) && (count < buffer_size)) { |
||
586 | break; |
||
587 | } |
||
588 | |||
589 | // otherwise try again with more space |
||
590 | if (count > -1) { // glibc 2.1 |
||
591 | buffer_size = count + 1; // precisely what is needed |
||
592 | } else { // glibc 2.0 |
||
593 | buffer_size *= 2; // twice the old size |
||
594 | } |
||
595 | free(buffer); |
||
596 | buffer = NULL; |
||
597 | lprintf(DEBUG_LVL2, " extending buffer to %i bytes\n", buffer_size); |
||
598 | } while (1); |
||
599 | |||
600 | if (!exitcode) { |
||
601 | // zipping binfile |
||
602 | lprintf(DEBUG, "%s\n", buffer); |
||
603 | count = system(buffer); |
||
604 | if ((count < 0) || (WEXITSTATUS(count))) { |
||
605 | exitcode = 1; |
||
606 | printf("create_zip_file: can not execute %s bytes\n", buffer); |
||
607 | } |
||
608 | } |
||
609 | |||
610 | return exitcode; |
||
611 | } |
||
612 | |||
613 | |||
614 | int create_img_file(FILE *f_out, char *out_filename, char *zip_filename) { |
||
615 | int exitcode = 0; |
||
616 | |||
617 | md5_state_t state; |
||
618 | md5_byte_t digest[16]; |
||
619 | |||
620 | int i; |
||
621 | int size; |
||
622 | |||
623 | FILE *f_in; |
||
624 | unsigned char buffer[1]; |
||
625 | |||
626 | // copy firmware version |
||
627 | memcpy(&img_hdr[50], fw_version, 2); |
||
628 | |||
629 | // clear md5 checksum |
||
630 | memset(&img_hdr[480], 0, 16); |
||
631 | |||
632 | // prepare md5 checksum calculation |
||
633 | md5_init(&state); |
||
634 | |||
635 | // add img header |
||
636 | lprintf(DEBUG_LVL2, " adding img header\n"); |
||
637 | for (i = 0; i < 512; i++) { |
||
638 | size = fputc(img_hdr[i], f_out); |
||
639 | if (size == EOF) { |
||
640 | exitcode = ferror(f_out); |
||
641 | printf("output file %s: %s\n", out_filename, strerror(exitcode)); |
||
642 | break; |
||
643 | } |
||
644 | md5_append(&state, (const md5_byte_t *)&img_hdr[i], 1); |
||
645 | } |
||
646 | |||
647 | // adding zip file |
||
648 | if (!exitcode) { |
||
649 | lprintf(DEBUG_LVL2, " adding zip file\n"); |
||
650 | f_in = fopen(zip_filename, "rb"); |
||
651 | if (!f_in) { |
||
652 | exitcode = errno; |
||
653 | printf("input file %s: %s\n", zip_filename, strerror(exitcode)); |
||
654 | } else { |
||
655 | while ((size = fgetc(f_in)) != EOF) { |
||
656 | buffer[0] = size; |
||
657 | |||
658 | size = fputc(buffer[0], f_out); |
||
659 | if (size == EOF) { |
||
660 | exitcode = ferror(f_out); |
||
661 | printf("output file %s: %s\n", out_filename, strerror(exitcode)); |
||
662 | break; |
||
663 | } |
||
664 | md5_append(&state, (const md5_byte_t *)buffer, 1); |
||
665 | } |
||
666 | if (ferror(f_in)) { |
||
667 | exitcode = ferror(f_in); |
||
668 | printf("input file %s: %s\n", zip_filename, strerror(exitcode)); |
||
669 | } |
||
670 | } |
||
671 | |||
672 | } |
||
673 | |||
674 | // add end byte |
||
675 | if (!exitcode) { |
||
676 | lprintf(DEBUG_LVL2, " adding img eof byte\n"); |
||
677 | size = fputc(img_eof[0], f_out); |
||
678 | if (size == EOF) { |
||
679 | exitcode = ferror(f_out); |
||
680 | printf("output file %s: %s\n", out_filename, strerror(exitcode)); |
||
681 | } |
||
682 | md5_append(&state, (const md5_byte_t *)img_eof, 1); |
||
683 | } |
||
684 | |||
685 | // append salt to md5 checksum |
||
686 | md5_append(&state, (const md5_byte_t *)"A^gU*<>?RFY@#DR&Z", 17); |
||
687 | |||
688 | // finish md5 checksum calculation |
||
689 | md5_finish(&state, digest); |
||
690 | |||
691 | // write md5 checksum into img header |
||
692 | if (!exitcode) { |
||
693 | lprintf(DEBUG_LVL2, " writing md5 checksum into img header of file\n"); |
||
694 | |||
695 | size = fseek(f_out, 480, SEEK_SET); |
||
696 | if (size == -1) { |
||
697 | exitcode = errno; |
||
698 | printf("output file %s: %s\n", out_filename, strerror(exitcode)); |
||
699 | } else { |
||
700 | size = fwrite(digest, 16, 1, f_out); |
||
701 | if (size < 1) { |
||
702 | if (ferror(f_out)) { |
||
703 | exitcode = ferror(f_out); |
||
704 | printf("output file %s: %s\n", out_filename, strerror(exitcode)); |
||
705 | } else { |
||
706 | exitcode = 1; |
||
707 | printf("output file %s: unspecified write error\n", out_filename); |
||
708 | } |
||
709 | } |
||
710 | } |
||
711 | |||
712 | fclose(f_in); |
||
713 | } |
||
714 | |||
715 | return exitcode; |
||
716 | } |
||
717 | |||
718 | |||
719 | int main(int argc, char *argv[]) { |
||
720 | int exitcode = 0; |
||
721 | |||
722 | int help; |
||
723 | int onlybin; |
||
724 | int havezip; |
||
725 | int ignoremagic; |
||
726 | char option; |
||
727 | char *par_filename = NULL; |
||
728 | char *img_filename = NULL; |
||
729 | char *base_filename = NULL; |
||
730 | char *bin_filename = NULL; |
||
731 | char *zip_filename = NULL; |
||
732 | |||
733 | FILE *f_par = NULL; |
||
734 | FILE *f_img = NULL; |
||
735 | |||
736 | int i; |
||
737 | mtd_info *mtd; |
||
738 | int noupdate; |
||
739 | int sizecheck; |
||
740 | int magiccheck; |
||
741 | int magicerror; |
||
742 | |||
743 | |||
744 | // display program header |
||
745 | printf(program_info, VERSION); |
||
746 | |||
747 | |||
748 | // command line processing |
||
749 | // options |
||
750 | help = 0; |
||
751 | onlybin = 0; |
||
752 | havezip = 0; |
||
753 | ignoremagic = 0; |
||
754 | while ((option = getopt(argc, argv, "hbzif:v")) != -1) { |
||
755 | switch(option) { |
||
756 | case 'h': |
||
757 | help = 1; |
||
758 | break; |
||
759 | case 'b': |
||
760 | onlybin = 1; |
||
761 | break; |
||
762 | case 'z': |
||
763 | havezip = 1; |
||
764 | break; |
||
765 | case 'i': |
||
766 | ignoremagic = 1; |
||
767 | break; |
||
768 | case 'f': |
||
769 | sizecheck = sscanf(optarg, "%i", &i); |
||
770 | if (sizecheck != 1) { |
||
771 | printf("Firmware version of -f option not a valid integer\n"); |
||
772 | exitcode = 1; |
||
773 | } else { |
||
774 | fw_version[0] = 0x000000FF & ( i >> 8 ); |
||
775 | fw_version[1] = 0x000000FF & i; |
||
776 | } |
||
777 | break; |
||
778 | case 'v': |
||
779 | verbosity++; |
||
780 | break; |
||
781 | case ':': // option with missing operand |
||
782 | printf("Option -%c requires an operand\n", optopt); |
||
783 | exitcode = 1; |
||
784 | break; |
||
785 | case '?': |
||
786 | printf("Unrecognized option: -%c\n", optopt); |
||
787 | exitcode = 1; |
||
788 | break; |
||
789 | } |
||
790 | } |
||
791 | |||
792 | // files |
||
793 | for ( ; optind < argc; optind++) { |
||
794 | if (!par_filename) { |
||
795 | par_filename = argv[optind]; |
||
796 | |||
797 | if (access(par_filename, R_OK)) { |
||
798 | if (havezip) { |
||
799 | printf("No read access to zip file %s\n", par_filename); |
||
800 | } else { |
||
801 | printf("No read access to parameter or zip file %s\n", par_filename); |
||
802 | } |
||
803 | exitcode = 1; |
||
804 | } |
||
805 | |||
806 | continue; |
||
807 | } |
||
808 | |||
809 | if ((!onlybin) && (!img_filename)) { |
||
810 | img_filename = argv[optind]; |
||
811 | |||
812 | if (!access(img_filename, F_OK)) { // if file already exists then check write access |
||
813 | if (access(img_filename, W_OK)) { |
||
814 | printf("No write access to image file %s\n", img_filename); |
||
815 | exitcode = 1; |
||
816 | } |
||
817 | } |
||
818 | |||
819 | continue; |
||
820 | } |
||
821 | |||
822 | printf("Too many files stated\n"); |
||
823 | exitcode = 1; |
||
824 | break; |
||
825 | } |
||
826 | |||
827 | // file name checks |
||
828 | if (!par_filename) { |
||
829 | if (havezip) { |
||
830 | printf("Zip file not stated\n"); |
||
831 | } else { |
||
832 | printf("Parameter file not stated\n"); |
||
833 | } |
||
834 | exitcode = 1; |
||
835 | } else { |
||
836 | base_filename = basename(par_filename); |
||
837 | if (!base_filename) { |
||
838 | if (havezip) { |
||
839 | printf("Zip file is a directory\n"); |
||
840 | } else { |
||
841 | printf("Parameter file is a directory\n"); |
||
842 | } |
||
843 | exitcode = 1; |
||
844 | } |
||
845 | } |
||
846 | |||
847 | if (!onlybin) { |
||
848 | if (!img_filename) { |
||
849 | printf("Image file not stated\n"); |
||
850 | exitcode = 1; |
||
851 | } else { |
||
852 | base_filename = basename(img_filename); |
||
853 | if (!base_filename) { |
||
854 | printf("Image file is a directory\n"); |
||
855 | exitcode = 1; |
||
856 | } |
||
857 | } |
||
858 | } |
||
859 | |||
860 | // check for mutually exclusive options |
||
861 | if ((onlybin) && (havezip)) { |
||
862 | printf("Option -b and -z are mutually exclusive\n"); |
||
863 | exitcode = 1; |
||
864 | } |
||
865 | |||
866 | // react on option problems or help request, then exit |
||
867 | if ((exitcode) || (help)) { |
||
868 | if (help) { |
||
869 | printf("This program creates Linksys style images for the WRT350Nv2 router.\n"); |
||
870 | } |
||
871 | printf(" Usage:\n\ |
||
872 | %s [-h] [-b] [-z] [-i] [-f <version>] [-v] <parameter or zip file> [<image file>]\n\n\ |
||
873 | Options:\n\ |
||
874 | -h - Show this help\n\ |
||
875 | -b - Create only bin file, no img or zip file is created\n\ |
||
876 | -z - Have zip file, the img file will be directly created from it\n\ |
||
877 | -i - Ignore unknown magic numbers\n\ |
||
878 | -f <version> - Wanted firmware version to use with -z\n\ |
||
879 | Default firmware version is 0x2020 = 2.00.20.\n\ |
||
880 | Note: version from parameter file will supersede this\n\ |
||
881 | -v - Increase debug verbosity level\n\n\ |
||
882 | Example:\n\ |
||
883 | %s wrt350nv2.par wrt350nv2.img\n\n", argv[0], argv[0]); |
||
884 | return exitcode; |
||
885 | } |
||
886 | |||
887 | // handle special case when zipfile is stated |
||
888 | if (havezip) { |
||
889 | zip_filename = par_filename; |
||
890 | par_filename = NULL; |
||
891 | } |
||
892 | |||
893 | lprintf(DEBUG_LVL2, " Verbosity: %i\n", verbosity); |
||
894 | lprintf(DEBUG_LVL2, " Program: %s\n", argv[0]); |
||
895 | |||
896 | if (par_filename) { |
||
897 | lprintf(DEBUG, "Parameter file: %s\n", par_filename); |
||
898 | } |
||
899 | if (zip_filename) { |
||
900 | lprintf(DEBUG, "Zip file: %s\n", zip_filename); |
||
901 | } |
||
902 | if (img_filename) { |
||
903 | lprintf(DEBUG, "Image file: %s\n", img_filename); |
||
904 | } |
||
905 | |||
906 | |||
907 | // open files from command line |
||
908 | // parameter/zip file |
||
909 | if (par_filename) { |
||
910 | f_par = fopen(par_filename, "rt"); |
||
911 | if (!f_par) { |
||
912 | exitcode = errno; |
||
913 | printf("Input file %s: %s\n", par_filename, strerror(exitcode)); |
||
914 | } |
||
915 | } |
||
916 | |||
917 | // image file |
||
918 | if (img_filename) { |
||
919 | f_img = fopen(img_filename, "wb"); |
||
920 | if (!f_img) { |
||
921 | exitcode = errno; |
||
922 | printf("Output file %s: %s\n", img_filename, strerror(exitcode)); |
||
923 | } |
||
924 | } |
||
925 | |||
926 | if (exitcode) { |
||
927 | return exitcode; |
||
928 | } |
||
929 | |||
930 | |||
931 | // parameter file processing |
||
932 | if ((!exitcode) && (f_par)) { |
||
933 | lprintf(DEBUG, "parsing parameter file...\n"); |
||
934 | |||
935 | exitcode = parse_par_file(f_par); |
||
936 | |||
937 | lprintf(DEBUG, "...done parsing file\n"); |
||
938 | } |
||
939 | if (f_par) { |
||
940 | fclose(f_par); |
||
941 | } |
||
942 | |||
943 | |||
944 | // check all input data |
||
945 | if ((!exitcode) && (par_filename)) { |
||
946 | lprintf(DEBUG, "checking mtd data...\n"); |
||
947 | |||
948 | for (i = 1; i <= 4; i++) { |
||
949 | noupdate = 0; |
||
950 | sizecheck = 0; |
||
951 | magiccheck = 0; |
||
952 | |||
953 | switch (i) { |
||
954 | case 1: |
||
955 | mtd = &mtd_image; |
||
956 | sizecheck = ROOTFS_END_OFFSET; |
||
957 | magiccheck = 1; |
||
958 | break; |
||
959 | case 2: |
||
960 | mtd = &mtd_kernel; |
||
961 | sizecheck = mtd_kernel.size - 16; |
||
962 | magiccheck = 1; |
||
963 | break; |
||
964 | case 3: |
||
965 | mtd = &mtd_rootfs; |
||
966 | mtd->offset = mtd_kernel.size; |
||
967 | mtd->size = ROOTFS_END_OFFSET - mtd_kernel.size; |
||
968 | sizecheck = PRODUCT_ID_OFFSET - mtd_kernel.size; |
||
969 | magiccheck = 1; |
||
970 | break; |
||
971 | case 4: |
||
972 | mtd = &mtd_uboot; |
||
973 | mtd->offset = BOOT_ADDR_BASE_OFF; |
||
974 | noupdate = 1; |
||
975 | sizecheck = SN_OFF - BOOT_ADDR_BASE_OFF; |
||
976 | break; |
||
977 | default: |
||
978 | mtd = NULL; |
||
979 | exitcode = 1; |
||
980 | printf("unknown mtd check %i\n", i); |
||
981 | break; |
||
982 | } |
||
983 | if (!mtd) { |
||
984 | break; |
||
985 | } |
||
986 | |||
987 | lprintf(DEBUG_LVL2, " checking mtd %s\n", mtd->name); |
||
988 | |||
989 | // general checks |
||
990 | |||
991 | // no further checks if no file data present |
||
992 | if (!mtd->filename) { |
||
993 | continue; |
||
994 | } |
||
995 | |||
996 | // not updated by stock firmware |
||
997 | if (noupdate) { |
||
998 | printf("mtd %s is specified, but will not be updated as of Linksys firmware 2.0.19\n", mtd->name); |
||
999 | } |
||
1000 | |||
1001 | // general magic number check |
||
1002 | magicerror = 0; |
||
1003 | if (magiccheck) { |
||
1004 | switch (i) { |
||
1005 | case 1: // image |
||
1006 | case 2: // kernel |
||
1007 | if (!( |
||
1008 | ((mtd->magic[0] == 0x27) && (mtd->magic[1] == 0x05)) // uImage |
||
1009 | )) { |
||
1010 | magicerror = 1; |
||
1011 | } |
||
1012 | break; |
||
1013 | case 3: // rootfs |
||
1014 | if (!( |
||
1015 | ((mtd->magic[0] == 0x68) && (mtd->magic[1] == 0x73)) // squashfs |
||
1016 | || ((mtd->magic[0] == 0x85) && (mtd->magic[1] == 0x19)) // jffs |
||
1017 | )) { |
||
1018 | magicerror = 1; |
||
1019 | } |
||
1020 | break; |
||
1021 | default: |
||
1022 | magicerror = 1; |
||
1023 | break; |
||
1024 | } |
||
1025 | if (magicerror) { |
||
1026 | printf("mtd %s input file %s has unknown magic number (0x%02X%02X)", mtd->name, mtd->filename, mtd->magic[0], mtd->magic[1]); |
||
1027 | if (ignoremagic) { |
||
1028 | printf("...ignoring"); |
||
1029 | } else { |
||
1030 | exitcode = 1; |
||
1031 | } |
||
1032 | printf("\n"); |
||
1033 | } |
||
1034 | } |
||
1035 | |||
1036 | // mtd specific size check |
||
1037 | if (mtd == &mtd_image) { |
||
1038 | if (mtd->filesize < 0x00200000) { |
||
1039 | exitcode = 1; |
||
1040 | printf("mtd %s input file %s too unrealistic small (0x%08lX)\n", mtd->name, mtd->filename, mtd->filesize); |
||
1041 | } |
||
1042 | } |
||
1043 | |||
1044 | if (mtd == &mtd_kernel) { |
||
1045 | if (mtd->filesize < 0x00080000) { |
||
1046 | exitcode = 1; |
||
1047 | printf("mtd %s input file %s too unrealistic small (0x%08lX)\n", mtd->name, mtd->filename, mtd->filesize); |
||
1048 | } |
||
1049 | } |
||
1050 | |||
1051 | // general size check |
||
1052 | if (sizecheck) { |
||
1053 | if (sizecheck <= 0) { |
||
1054 | exitcode = 1; |
||
1055 | printf("mtd %s bad file size check (%i) due to input data\n", mtd->name, sizecheck); |
||
1056 | } else { |
||
1057 | if (mtd->filesize > sizecheck) { |
||
1058 | exitcode = 1; |
||
1059 | printf("mtd %s input file %s too big (0x%08lX)\n", mtd->name, mtd->filename, mtd->filesize); |
||
1060 | } |
||
1061 | } |
||
1062 | } |
||
1063 | } |
||
1064 | |||
1065 | // Check for mandatory parts |
||
1066 | if ((!mtd_image.filename) && (!mtd_kernel.filename || !mtd_rootfs.filename)) { |
||
1067 | exitcode = 1; |
||
1068 | if (mtd_kernel.filename && !mtd_rootfs.filename) { |
||
1069 | printf("Kernel without rootfs, either incorrectly specified or not at all in parameter file\n"); |
||
1070 | } else if (!mtd_kernel.filename && mtd_rootfs.filename) { |
||
1071 | printf("Rootfs without kernel, either incorrectly specified or not at all in parameter file\n"); |
||
1072 | } else { |
||
1073 | printf("Neither an image nor kernel with rootfs was/were correctly specified or at all in parameter file\n"); |
||
1074 | } |
||
1075 | } |
||
1076 | |||
1077 | // Check for duplicate parts |
||
1078 | if ((mtd_image.filename) && (mtd_kernel.filename || mtd_rootfs.filename)) { |
||
1079 | exitcode = 1; |
||
1080 | printf("Image and kernel/rootfs specified in parameter file\n"); |
||
1081 | } |
||
1082 | |||
1083 | lprintf(DEBUG, "...done checking mtd data\n"); |
||
1084 | } |
||
1085 | |||
1086 | |||
1087 | // bin creation in memory |
||
1088 | if ((!exitcode) && (par_filename)) { |
||
1089 | bin_filename = "wrt350n.bin"; |
||
1090 | |||
1091 | lprintf(DEBUG, "creating bin file %s...\n", bin_filename); |
||
1092 | |||
1093 | exitcode = create_bin_file(bin_filename); |
||
1094 | |||
1095 | lprintf(DEBUG, "...done creating bin file\n"); |
||
1096 | } |
||
1097 | |||
1098 | // zip file creation |
||
1099 | if ((!exitcode) && (!onlybin) && (!zip_filename)) { |
||
1100 | zip_filename = "wrt350n.zip"; |
||
1101 | |||
1102 | lprintf(DEBUG, "creating zip file %s...\n", zip_filename); |
||
1103 | |||
1104 | exitcode = create_zip_file(zip_filename, bin_filename); |
||
1105 | |||
1106 | lprintf(DEBUG, "...done creating zip file\n"); |
||
1107 | } |
||
1108 | |||
1109 | |||
1110 | // img file creation |
||
1111 | if ((!exitcode) && (f_img)) { |
||
1112 | lprintf(DEBUG, "creating img file...\n"); |
||
1113 | |||
1114 | exitcode = create_img_file(f_img, img_filename, zip_filename); |
||
1115 | |||
1116 | lprintf(DEBUG, "...done creating img file\n"); |
||
1117 | } |
||
1118 | |||
1119 | // clean up |
||
1120 | if (f_img) { |
||
1121 | fclose(f_img); |
||
1122 | } |
||
1123 | |||
1124 | // end program |
||
1125 | return exitcode; |
||
1126 | } |