mac80211: fix AP mode scanning issues
[openwrt.git] / tools / wrt350nv2-builder / src / wrt350nv2-builder.c
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 }