OpenWrt – Blame information for rev 3

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /*
2 Copyright (c) 2014, Matthias Schiffer <mschiffer@universe-factory.net>
3 All rights reserved.
4  
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7  
8 1. Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright notice,
11 this list of conditions and the following disclaimer in the documentation
12 and/or other materials provided with the distribution.
13  
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25  
26  
27 /*
28 tplink-safeloader
29  
30 Image generation tool for the TP-LINK SafeLoader as seen on
31 TP-LINK Pharos devices (CPE210/220/510/520)
32 */
33  
34  
35 #include <assert.h>
36 #include <errno.h>
37 #include <stdbool.h>
38 #include <stdio.h>
39 #include <stdint.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <time.h>
43 #include <unistd.h>
44  
45 #include <arpa/inet.h>
46  
47 #include <sys/types.h>
48 #include <sys/stat.h>
49 #include <limits.h>
50  
51 #include "md5.h"
52  
53  
54 #define ALIGN(x,a) ({ typeof(a) __a = (a); (((x) + __a - 1) & ~(__a - 1)); })
55  
56  
57 #define MAX_PARTITIONS 32
58  
59 /** An image partition table entry */
60 struct image_partition_entry {
61 const char *name;
62 size_t size;
63 uint8_t *data;
64 };
65  
66 /** A flash partition table entry */
67 struct flash_partition_entry {
3 office 68 const char *name;
1 office 69 uint32_t base;
70 uint32_t size;
71 };
72  
73 /** Firmware layout description */
74 struct device_info {
75 const char *id;
76 const char *vendor;
77 const char *support_list;
78 char support_trail;
79 const char *soft_ver;
3 office 80 const struct flash_partition_entry partitions[MAX_PARTITIONS+1];
1 office 81 const char *first_sysupgrade_partition;
82 const char *last_sysupgrade_partition;
83 };
84  
85 /** The content of the soft-version structure */
86 struct __attribute__((__packed__)) soft_version {
87 uint32_t magic;
88 uint32_t zero;
89 uint8_t pad1;
90 uint8_t version_major;
91 uint8_t version_minor;
92 uint8_t version_patch;
93 uint8_t year_hi;
94 uint8_t year_lo;
95 uint8_t month;
96 uint8_t day;
97 uint32_t rev;
98 uint8_t pad2;
99 };
100  
101  
102 static const uint8_t jffs2_eof_mark[4] = {0xde, 0xad, 0xc0, 0xde};
103  
104  
105 /**
106 Salt for the MD5 hash
107  
108 Fortunately, TP-LINK seems to use the same salt for most devices which use
109 the new image format.
110 */
111 static const uint8_t md5_salt[16] = {
112 0x7a, 0x2b, 0x15, 0xed,
113 0x9b, 0x98, 0x59, 0x6d,
114 0xe5, 0x04, 0xab, 0x44,
115 0xac, 0x2a, 0x9f, 0x4e,
116 };
117  
118  
119 /** Firmware layout table */
120 static struct device_info boards[] = {
121 /** Firmware layout for the CPE210/220 */
122 {
123 .id = "CPE210",
124 .vendor = "CPE510(TP-LINK|UN|N300-5):1.0\r\n",
125 .support_list =
126 "SupportList:\r\n"
127 "CPE210(TP-LINK|UN|N300-2):1.0\r\n"
128 "CPE210(TP-LINK|UN|N300-2):1.1\r\n"
129 "CPE210(TP-LINK|US|N300-2):1.1\r\n"
130 "CPE210(TP-LINK|EU|N300-2):1.1\r\n"
131 "CPE220(TP-LINK|UN|N300-2):1.1\r\n"
132 "CPE220(TP-LINK|US|N300-2):1.1\r\n"
133 "CPE220(TP-LINK|EU|N300-2):1.1\r\n",
134 .support_trail = '\xff',
135 .soft_ver = NULL,
136  
137 .partitions = {
138 {"fs-uboot", 0x00000, 0x20000},
139 {"partition-table", 0x20000, 0x02000},
140 {"default-mac", 0x30000, 0x00020},
141 {"product-info", 0x31100, 0x00100},
142 {"signature", 0x32000, 0x00400},
143 {"os-image", 0x40000, 0x1c0000},
144 {"file-system", 0x200000, 0x5b0000},
145 {"soft-version", 0x7b0000, 0x00100},
146 {"support-list", 0x7b1000, 0x00400},
147 {"user-config", 0x7c0000, 0x10000},
148 {"default-config", 0x7d0000, 0x10000},
149 {"log", 0x7e0000, 0x10000},
150 {"radio", 0x7f0000, 0x10000},
151 {NULL, 0, 0}
152 },
153  
154 .first_sysupgrade_partition = "os-image",
155 .last_sysupgrade_partition = "support-list",
156 },
157  
158 /** Firmware layout for the CPE210 V2 */
159 {
160 .id = "CPE210V2",
161 .vendor = "CPE210(TP-LINK|UN|N300-2|00000000):2.0\r\n",
162 .support_list =
163 "SupportList:\r\n"
164 "CPE210(TP-LINK|EU|N300-2|00000000):2.0\r\n"
165 "CPE210(TP-LINK|EU|N300-2|45550000):2.0\r\n"
166 "CPE210(TP-LINK|EU|N300-2|55530000):2.0\r\n"
167 "CPE210(TP-LINK|UN|N300-2|00000000):2.0\r\n"
168 "CPE210(TP-LINK|UN|N300-2|45550000):2.0\r\n"
169 "CPE210(TP-LINK|UN|N300-2|55530000):2.0\r\n"
170 "CPE210(TP-LINK|US|N300-2|55530000):2.0\r\n"
171 "CPE210(TP-LINK|UN|N300-2):2.0\r\n"
172 "CPE210(TP-LINK|EU|N300-2):2.0\r\n"
173 "CPE210(TP-LINK|US|N300-2):2.0\r\n",
174 .support_trail = '\xff',
175 .soft_ver = NULL,
176  
177 .partitions = {
178 {"fs-uboot", 0x00000, 0x20000},
179 {"partition-table", 0x20000, 0x02000},
180 {"default-mac", 0x30000, 0x00020},
181 {"product-info", 0x31100, 0x00100},
182 {"device-info", 0x31400, 0x00400},
183 {"signature", 0x32000, 0x00400},
184 {"device-id", 0x33000, 0x00100},
185 {"os-image", 0x40000, 0x1c0000},
186 {"file-system", 0x200000, 0x5b0000},
187 {"soft-version", 0x7b0000, 0x00100},
188 {"support-list", 0x7b1000, 0x01000},
189 {"user-config", 0x7c0000, 0x10000},
190 {"default-config", 0x7d0000, 0x10000},
191 {"log", 0x7e0000, 0x10000},
192 {"radio", 0x7f0000, 0x10000},
193 {NULL, 0, 0}
194 },
195  
196 .first_sysupgrade_partition = "os-image",
197 .last_sysupgrade_partition = "support-list",
198 },
199  
200 /** Firmware layout for the CPE510/520 */
201 {
202 .id = "CPE510",
203 .vendor = "CPE510(TP-LINK|UN|N300-5):1.0\r\n",
204 .support_list =
205 "SupportList:\r\n"
206 "CPE510(TP-LINK|UN|N300-5):1.0\r\n"
207 "CPE510(TP-LINK|UN|N300-5):1.1\r\n"
208 "CPE510(TP-LINK|UN|N300-5):1.1\r\n"
209 "CPE510(TP-LINK|US|N300-5):1.1\r\n"
210 "CPE510(TP-LINK|EU|N300-5):1.1\r\n"
211 "CPE520(TP-LINK|UN|N300-5):1.1\r\n"
212 "CPE520(TP-LINK|US|N300-5):1.1\r\n"
3 office 213 "CPE520(TP-LINK|EU|N300-5):1.1\r\n",
1 office 214 .support_trail = '\xff',
215 .soft_ver = NULL,
216  
217 .partitions = {
218 {"fs-uboot", 0x00000, 0x20000},
219 {"partition-table", 0x20000, 0x02000},
220 {"default-mac", 0x30000, 0x00020},
221 {"product-info", 0x31100, 0x00100},
222 {"signature", 0x32000, 0x00400},
223 {"os-image", 0x40000, 0x1c0000},
224 {"file-system", 0x200000, 0x5b0000},
225 {"soft-version", 0x7b0000, 0x00100},
226 {"support-list", 0x7b1000, 0x00400},
227 {"user-config", 0x7c0000, 0x10000},
228 {"default-config", 0x7d0000, 0x10000},
229 {"log", 0x7e0000, 0x10000},
230 {"radio", 0x7f0000, 0x10000},
231 {NULL, 0, 0}
232 },
233  
234 .first_sysupgrade_partition = "os-image",
235 .last_sysupgrade_partition = "support-list",
236 },
237  
238 {
239 .id = "WBS210",
240 .vendor = "CPE510(TP-LINK|UN|N300-5):1.0\r\n",
241 .support_list =
242 "SupportList:\r\n"
243 "WBS210(TP-LINK|UN|N300-2):1.20\r\n"
244 "WBS210(TP-LINK|US|N300-2):1.20\r\n"
245 "WBS210(TP-LINK|EU|N300-2):1.20\r\n",
246 .support_trail = '\xff',
247 .soft_ver = NULL,
248  
249 .partitions = {
250 {"fs-uboot", 0x00000, 0x20000},
251 {"partition-table", 0x20000, 0x02000},
252 {"default-mac", 0x30000, 0x00020},
253 {"product-info", 0x31100, 0x00100},
254 {"signature", 0x32000, 0x00400},
255 {"os-image", 0x40000, 0x1c0000},
256 {"file-system", 0x200000, 0x5b0000},
257 {"soft-version", 0x7b0000, 0x00100},
258 {"support-list", 0x7b1000, 0x00400},
259 {"user-config", 0x7c0000, 0x10000},
260 {"default-config", 0x7d0000, 0x10000},
261 {"log", 0x7e0000, 0x10000},
262 {"radio", 0x7f0000, 0x10000},
263 {NULL, 0, 0}
264 },
265  
266 .first_sysupgrade_partition = "os-image",
267 .last_sysupgrade_partition = "support-list",
268 },
269  
270 {
271 .id = "WBS510",
272 .vendor = "CPE510(TP-LINK|UN|N300-5):1.0\r\n",
273 .support_list =
274 "SupportList:\r\n"
275 "WBS510(TP-LINK|UN|N300-5):1.20\r\n"
276 "WBS510(TP-LINK|US|N300-5):1.20\r\n"
277 "WBS510(TP-LINK|EU|N300-5):1.20\r\n",
278 .support_trail = '\xff',
279 .soft_ver = NULL,
280  
281 .partitions = {
282 {"fs-uboot", 0x00000, 0x20000},
283 {"partition-table", 0x20000, 0x02000},
284 {"default-mac", 0x30000, 0x00020},
285 {"product-info", 0x31100, 0x00100},
286 {"signature", 0x32000, 0x00400},
287 {"os-image", 0x40000, 0x1c0000},
288 {"file-system", 0x200000, 0x5b0000},
289 {"soft-version", 0x7b0000, 0x00100},
290 {"support-list", 0x7b1000, 0x00400},
291 {"user-config", 0x7c0000, 0x10000},
292 {"default-config", 0x7d0000, 0x10000},
293 {"log", 0x7e0000, 0x10000},
294 {"radio", 0x7f0000, 0x10000},
295 {NULL, 0, 0}
296 },
297  
298 .first_sysupgrade_partition = "os-image",
299 .last_sysupgrade_partition = "support-list",
300 },
301  
302 /** Firmware layout for the C2600 */
303 {
304 .id = "C2600",
305 .vendor = "",
306 .support_list =
307 "SupportList:\r\n"
308 "{product_name:Archer C2600,product_ver:1.0.0,special_id:00000000}\r\n",
309 .support_trail = '\x00',
310 .soft_ver = NULL,
311  
312 /**
313 We use a bigger os-image partition than the stock images (and thus
314 smaller file-system), as our kernel doesn't fit in the stock firmware's
315 2 MB os-image since kernel 4.14.
316 */
317 .partitions = {
318 {"SBL1", 0x00000, 0x20000},
319 {"MIBIB", 0x20000, 0x20000},
320 {"SBL2", 0x40000, 0x20000},
321 {"SBL3", 0x60000, 0x30000},
322 {"DDRCONFIG", 0x90000, 0x10000},
323 {"SSD", 0xa0000, 0x10000},
324 {"TZ", 0xb0000, 0x30000},
325 {"RPM", 0xe0000, 0x20000},
326 {"fs-uboot", 0x100000, 0x70000},
327 {"uboot-env", 0x170000, 0x40000},
328 {"radio", 0x1b0000, 0x40000},
329 {"os-image", 0x1f0000, 0x400000}, /* Stock: base 0x1f0000 size 0x200000 */
330 {"file-system", 0x5f0000, 0x1900000}, /* Stock: base 0x3f0000 size 0x1b00000 */
331 {"default-mac", 0x1ef0000, 0x00200},
332 {"pin", 0x1ef0200, 0x00200},
333 {"product-info", 0x1ef0400, 0x0fc00},
334 {"partition-table", 0x1f00000, 0x10000},
335 {"soft-version", 0x1f10000, 0x10000},
336 {"support-list", 0x1f20000, 0x10000},
337 {"profile", 0x1f30000, 0x10000},
338 {"default-config", 0x1f40000, 0x10000},
339 {"user-config", 0x1f50000, 0x40000},
340 {"qos-db", 0x1f90000, 0x40000},
341 {"usb-config", 0x1fd0000, 0x10000},
342 {"log", 0x1fe0000, 0x20000},
343 {NULL, 0, 0}
344 },
345  
346 .first_sysupgrade_partition = "os-image",
347 .last_sysupgrade_partition = "file-system"
348 },
349  
350 /** Firmware layout for the C25v1 */
351 {
352 .id = "ARCHER-C25-V1",
353 .support_list =
354 "SupportList:\n"
355 "{product_name:ArcherC25,product_ver:1.0.0,special_id:00000000}\n"
356 "{product_name:ArcherC25,product_ver:1.0.0,special_id:55530000}\n"
357 "{product_name:ArcherC25,product_ver:1.0.0,special_id:45550000}\n",
358 .support_trail = '\x00',
359 .soft_ver = "soft_ver:1.0.0\n",
360  
3 office 361 /**
362 We use a bigger os-image partition than the stock images (and thus
363 smaller file-system), as our kernel doesn't fit in the stock firmware's
364 1MB os-image.
365 */
1 office 366 .partitions = {
367 {"factory-boot", 0x00000, 0x20000},
368 {"fs-uboot", 0x20000, 0x10000},
3 office 369 {"os-image", 0x30000, 0x180000}, /* Stock: base 0x30000 size 0x100000 */
370 {"file-system", 0x1b0000, 0x620000}, /* Stock: base 0x130000 size 0x6a0000 */
1 office 371 {"user-config", 0x7d0000, 0x04000},
372 {"default-mac", 0x7e0000, 0x00100},
373 {"device-id", 0x7e0100, 0x00100},
374 {"extra-para", 0x7e0200, 0x00100},
375 {"pin", 0x7e0300, 0x00100},
376 {"support-list", 0x7e0400, 0x00400},
377 {"soft-version", 0x7e0800, 0x00400},
378 {"product-info", 0x7e0c00, 0x01400},
379 {"partition-table", 0x7e2000, 0x01000},
380 {"profile", 0x7e3000, 0x01000},
381 {"default-config", 0x7e4000, 0x04000},
382 {"merge-config", 0x7ec000, 0x02000},
383 {"qos-db", 0x7ee000, 0x02000},
384 {"radio", 0x7f0000, 0x10000},
385 {NULL, 0, 0}
386 },
387  
388 .first_sysupgrade_partition = "os-image",
389 .last_sysupgrade_partition = "file-system",
390 },
391  
392 /** Firmware layout for the C58v1 */
393 {
394 .id = "ARCHER-C58-V1",
395 .vendor = "",
396 .support_list =
397 "SupportList:\r\n"
398 "{product_name:Archer C58,product_ver:1.0.0,special_id:00000000}\r\n"
399 "{product_name:Archer C58,product_ver:1.0.0,special_id:45550000}\r\n"
400 "{product_name:Archer C58,product_ver:1.0.0,special_id:55530000}\r\n",
401 .support_trail = '\x00',
402 .soft_ver = "soft_ver:1.0.0\n",
403  
404 .partitions = {
405 {"fs-uboot", 0x00000, 0x10000},
406 {"default-mac", 0x10000, 0x00200},
407 {"pin", 0x10200, 0x00200},
408 {"product-info", 0x10400, 0x00100},
409 {"partition-table", 0x10500, 0x00800},
410 {"soft-version", 0x11300, 0x00200},
411 {"support-list", 0x11500, 0x00100},
412 {"device-id", 0x11600, 0x00100},
413 {"profile", 0x11700, 0x03900},
414 {"default-config", 0x15000, 0x04000},
415 {"user-config", 0x19000, 0x04000},
3 office 416 {"os-image", 0x20000, 0x180000},
417 {"file-system", 0x1a0000, 0x648000},
1 office 418 {"certyficate", 0x7e8000, 0x08000},
419 {"radio", 0x7f0000, 0x10000},
420 {NULL, 0, 0}
421 },
422  
423 .first_sysupgrade_partition = "os-image",
424 .last_sysupgrade_partition = "file-system",
425 },
426  
427 /** Firmware layout for the C59v1 */
428 {
429 .id = "ARCHER-C59-V1",
430 .vendor = "",
431 .support_list =
432 "SupportList:\r\n"
433 "{product_name:Archer C59,product_ver:1.0.0,special_id:00000000}\r\n"
434 "{product_name:Archer C59,product_ver:1.0.0,special_id:45550000}\r\n"
435 "{product_name:Archer C59,product_ver:1.0.0,special_id:52550000}\r\n"
436 "{product_name:Archer C59,product_ver:1.0.0,special_id:55530000}\r\n",
437 .support_trail = '\x00',
438 .soft_ver = "soft_ver:1.0.0\n",
439  
440 .partitions = {
441 {"fs-uboot", 0x00000, 0x10000},
442 {"default-mac", 0x10000, 0x00200},
443 {"pin", 0x10200, 0x00200},
444 {"device-id", 0x10400, 0x00100},
445 {"product-info", 0x10500, 0x0fb00},
3 office 446 {"os-image", 0x20000, 0x180000},
447 {"file-system", 0x1a0000, 0xcb0000},
1 office 448 {"partition-table", 0xe50000, 0x10000},
449 {"soft-version", 0xe60000, 0x10000},
450 {"support-list", 0xe70000, 0x10000},
451 {"profile", 0xe80000, 0x10000},
452 {"default-config", 0xe90000, 0x10000},
453 {"user-config", 0xea0000, 0x40000},
454 {"usb-config", 0xee0000, 0x10000},
455 {"certificate", 0xef0000, 0x10000},
456 {"qos-db", 0xf00000, 0x40000},
457 {"log", 0xfe0000, 0x10000},
458 {"radio", 0xff0000, 0x10000},
459 {NULL, 0, 0}
460 },
461  
462 .first_sysupgrade_partition = "os-image",
463 .last_sysupgrade_partition = "file-system",
464 },
465  
466 /** Firmware layout for the C60v1 */
467 {
468 .id = "ARCHER-C60-V1",
469 .vendor = "",
470 .support_list =
471 "SupportList:\r\n"
472 "{product_name:Archer C60,product_ver:1.0.0,special_id:00000000}\r\n"
473 "{product_name:Archer C60,product_ver:1.0.0,special_id:45550000}\r\n"
474 "{product_name:Archer C60,product_ver:1.0.0,special_id:55530000}\r\n",
475 .support_trail = '\x00',
476 .soft_ver = "soft_ver:1.0.0\n",
477  
478 .partitions = {
479 {"fs-uboot", 0x00000, 0x10000},
480 {"default-mac", 0x10000, 0x00200},
481 {"pin", 0x10200, 0x00200},
482 {"product-info", 0x10400, 0x00100},
483 {"partition-table", 0x10500, 0x00800},
484 {"soft-version", 0x11300, 0x00200},
485 {"support-list", 0x11500, 0x00100},
486 {"device-id", 0x11600, 0x00100},
487 {"profile", 0x11700, 0x03900},
488 {"default-config", 0x15000, 0x04000},
489 {"user-config", 0x19000, 0x04000},
3 office 490 {"os-image", 0x20000, 0x180000},
491 {"file-system", 0x1a0000, 0x648000},
1 office 492 {"certyficate", 0x7e8000, 0x08000},
493 {"radio", 0x7f0000, 0x10000},
494 {NULL, 0, 0}
495 },
496  
497 .first_sysupgrade_partition = "os-image",
498 .last_sysupgrade_partition = "file-system",
499 },
500  
501 /** Firmware layout for the C60v2 */
502 {
503 .id = "ARCHER-C60-V2",
504 .vendor = "",
505 .support_list =
506 "SupportList:\r\n"
507 "{product_name:Archer C60,product_ver:2.0.0,special_id:42520000}\r\n"
508 "{product_name:Archer C60,product_ver:2.0.0,special_id:45550000}\r\n"
509 "{product_name:Archer C60,product_ver:2.0.0,special_id:55530000}\r\n",
510 .support_trail = '\x00',
511 .soft_ver = "soft_ver:2.0.0\n",
512  
513 .partitions = {
514 {"factory-boot", 0x00000, 0x1fb00},
515 {"default-mac", 0x1fb00, 0x00200},
516 {"pin", 0x1fd00, 0x00100},
517 {"product-info", 0x1fe00, 0x00100},
518 {"device-id", 0x1ff00, 0x00100},
519 {"fs-uboot", 0x20000, 0x10000},
3 office 520 {"os-image", 0x30000, 0x180000},
521 {"file-system", 0x1b0000, 0x620000},
1 office 522 {"soft-version", 0x7d9500, 0x00100},
523 {"support-list", 0x7d9600, 0x00100},
524 {"extra-para", 0x7d9700, 0x00100},
525 {"profile", 0x7d9800, 0x03000},
526 {"default-config", 0x7dc800, 0x03000},
527 {"partition-table", 0x7df800, 0x00800},
528 {"user-config", 0x7e0000, 0x0c000},
529 {"certificate", 0x7ec000, 0x04000},
530 {"radio", 0x7f0000, 0x10000},
531 {NULL, 0, 0}
532 },
533  
534 .first_sysupgrade_partition = "os-image",
535 .last_sysupgrade_partition = "file-system",
536 },
537  
538 /** Firmware layout for the C5 */
539 {
540 .id = "ARCHER-C5-V2",
541 .vendor = "",
542 .support_list =
543 "SupportList:\r\n"
544 "{product_name:ArcherC5,product_ver:2.0.0,special_id:00000000}\r\n"
545 "{product_name:ArcherC5,product_ver:2.0.0,special_id:55530000}\r\n"
546 "{product_name:ArcherC5,product_ver:2.0.0,special_id:4A500000}\r\n", /* JP version */
547 .support_trail = '\x00',
548 .soft_ver = NULL,
549  
550 .partitions = {
551 {"fs-uboot", 0x00000, 0x40000},
552 {"os-image", 0x40000, 0x200000},
553 {"file-system", 0x240000, 0xc00000},
554 {"default-mac", 0xe40000, 0x00200},
555 {"pin", 0xe40200, 0x00200},
556 {"product-info", 0xe40400, 0x00200},
557 {"partition-table", 0xe50000, 0x10000},
558 {"soft-version", 0xe60000, 0x00200},
559 {"support-list", 0xe61000, 0x0f000},
560 {"profile", 0xe70000, 0x10000},
561 {"default-config", 0xe80000, 0x10000},
562 {"user-config", 0xe90000, 0x50000},
563 {"log", 0xee0000, 0x100000},
564 {"radio_bk", 0xfe0000, 0x10000},
565 {"radio", 0xff0000, 0x10000},
566 {NULL, 0, 0}
567 },
568  
569 .first_sysupgrade_partition = "os-image",
570 .last_sysupgrade_partition = "file-system"
571 },
572  
573 /** Firmware layout for the C7 */
574 {
575 .id = "ARCHER-C7-V4",
576 .support_list =
577 "SupportList:\n"
578 "{product_name:Archer C7,product_ver:4.0.0,special_id:00000000}\n"
579 "{product_name:Archer C7,product_ver:4.0.0,special_id:41550000}\n"
580 "{product_name:Archer C7,product_ver:4.0.0,special_id:45550000}\n"
581 "{product_name:Archer C7,product_ver:4.0.0,special_id:4B520000}\n"
582 "{product_name:Archer C7,product_ver:4.0.0,special_id:42520000}\n"
583 "{product_name:Archer C7,product_ver:4.0.0,special_id:4A500000}\n"
584 "{product_name:Archer C7,product_ver:4.0.0,special_id:52550000}\n"
585 "{product_name:Archer C7,product_ver:4.0.0,special_id:54570000}\n"
586 "{product_name:Archer C7,product_ver:4.0.0,special_id:55530000}\n"
587 "{product_name:Archer C7,product_ver:4.0.0,special_id:43410000}\n",
588 .support_trail = '\x00',
589 .soft_ver = "soft_ver:1.0.0\n",
590  
3 office 591 /**
592 We use a bigger os-image partition than the stock images (and thus
593 smaller file-system), as our kernel doesn't fit in the stock firmware's
594 1MB os-image.
595 */
1 office 596 .partitions = {
597 {"factory-boot", 0x00000, 0x20000},
598 {"fs-uboot", 0x20000, 0x20000},
3 office 599 {"os-image", 0x40000, 0x180000}, /* Stock: base 0x40000 size 0x120000 */
600 {"file-system", 0x1c0000, 0xd40000}, /* Stock: base 0x160000 size 0xda0000 */
1 office 601 {"default-mac", 0xf00000, 0x00200},
602 {"pin", 0xf00200, 0x00200},
603 {"device-id", 0xf00400, 0x00100},
604 {"product-info", 0xf00500, 0x0fb00},
605 {"soft-version", 0xf10000, 0x00100},
606 {"extra-para", 0xf11000, 0x01000},
607 {"support-list", 0xf12000, 0x0a000},
608 {"profile", 0xf1c000, 0x04000},
609 {"default-config", 0xf20000, 0x10000},
610 {"user-config", 0xf30000, 0x40000},
611 {"qos-db", 0xf70000, 0x40000},
612 {"certificate", 0xfb0000, 0x10000},
613 {"partition-table", 0xfc0000, 0x10000},
614 {"log", 0xfd0000, 0x20000},
615 {"radio", 0xff0000, 0x10000},
616 {NULL, 0, 0}
617 },
618  
619 .first_sysupgrade_partition = "os-image",
620 .last_sysupgrade_partition = "file-system",
621 },
622  
623 /** Firmware layout for the C7 v5*/
624 {
625 .id = "ARCHER-C7-V5",
626 .support_list =
627 "SupportList:\n"
628 "{product_name:Archer C7,product_ver:5.0.0,special_id:00000000}\n"
3 office 629 "{product_name:Archer C7,product_ver:5.0.0,special_id:55530000}\n",
1 office 630  
631 .support_trail = '\x00',
632 .soft_ver = "soft_ver:1.0.0\n",
633  
3 office 634 /**
635 We use a bigger os-image partition than the stock images (and thus
636 smaller file-system), as our kernel doesn't fit in the stock firmware's
637 1MB os-image.
638 */
1 office 639 .partitions = {
640 {"factory-boot", 0x00000, 0x20000},
641 {"fs-uboot", 0x20000, 0x20000},
642 {"partition-table", 0x40000, 0x10000},
643 {"radio", 0x50000, 0x10000},
644 {"default-mac", 0x60000, 0x00200},
645 {"pin", 0x60200, 0x00200},
646 {"device-id", 0x60400, 0x00100},
647 {"product-info", 0x60500, 0x0fb00},
648 {"soft-version", 0x70000, 0x01000},
649 {"extra-para", 0x71000, 0x01000},
650 {"support-list", 0x72000, 0x0a000},
651 {"profile", 0x7c000, 0x04000},
652 {"user-config", 0x80000, 0x40000},
653  
654  
3 office 655 {"os-image", 0xc0000, 0x180000}, /* Stock: base 0xc0000 size 0x120000 */
656 {"file-system", 0x240000, 0xd80000}, /* Stock: base 0x1e0000 size 0xde0000 */
1 office 657  
658 {"log", 0xfc0000, 0x20000},
659 {"certificate", 0xfe0000, 0x10000},
660 {"default-config", 0xff0000, 0x10000},
661 {NULL, 0, 0}
662  
663 },
664  
665 .first_sysupgrade_partition = "os-image",
666 .last_sysupgrade_partition = "file-system",
667 },
668  
669 /** Firmware layout for the C9 */
670 {
671 .id = "ARCHERC9",
672 .vendor = "",
673 .support_list =
674 "SupportList:\n"
675 "{product_name:ArcherC9,"
676 "product_ver:1.0.0,"
677 "special_id:00000000}\n",
678 .support_trail = '\x00',
679 .soft_ver = NULL,
680  
681 .partitions = {
682 {"fs-uboot", 0x00000, 0x40000},
683 {"os-image", 0x40000, 0x200000},
684 {"file-system", 0x240000, 0xc00000},
685 {"default-mac", 0xe40000, 0x00200},
686 {"pin", 0xe40200, 0x00200},
687 {"product-info", 0xe40400, 0x00200},
688 {"partition-table", 0xe50000, 0x10000},
689 {"soft-version", 0xe60000, 0x00200},
690 {"support-list", 0xe61000, 0x0f000},
691 {"profile", 0xe70000, 0x10000},
692 {"default-config", 0xe80000, 0x10000},
693 {"user-config", 0xe90000, 0x50000},
694 {"log", 0xee0000, 0x100000},
695 {"radio_bk", 0xfe0000, 0x10000},
696 {"radio", 0xff0000, 0x10000},
697 {NULL, 0, 0}
698 },
699  
700 .first_sysupgrade_partition = "os-image",
701 .last_sysupgrade_partition = "file-system"
702 },
703  
704 /** Firmware layout for the EAP120 */
705 {
706 .id = "EAP120",
707 .vendor = "EAP120(TP-LINK|UN|N300-2):1.0\r\n",
708 .support_list =
709 "SupportList:\r\n"
710 "EAP120(TP-LINK|UN|N300-2):1.0\r\n",
711 .support_trail = '\xff',
712 .soft_ver = NULL,
713  
714 .partitions = {
715 {"fs-uboot", 0x00000, 0x20000},
716 {"partition-table", 0x20000, 0x02000},
717 {"default-mac", 0x30000, 0x00020},
718 {"support-list", 0x31000, 0x00100},
719 {"product-info", 0x31100, 0x00100},
720 {"soft-version", 0x32000, 0x00100},
721 {"os-image", 0x40000, 0x180000},
722 {"file-system", 0x1c0000, 0x600000},
723 {"user-config", 0x7c0000, 0x10000},
724 {"backup-config", 0x7d0000, 0x10000},
725 {"log", 0x7e0000, 0x10000},
726 {"radio", 0x7f0000, 0x10000},
727 {NULL, 0, 0}
728 },
729  
730 .first_sysupgrade_partition = "os-image",
731 .last_sysupgrade_partition = "file-system"
732 },
733  
734 /** Firmware layout for the TL-WA850RE v2 */
735 {
736 .id = "TLWA850REV2",
737 .vendor = "",
738 .support_list =
739 "SupportList:\n"
740 "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:55530000}\n"
741 "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:00000000}\n"
742 "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:55534100}\n"
743 "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:45550000}\n"
744 "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:4B520000}\n"
745 "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:42520000}\n"
746 "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:4A500000}\n"
747 "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:43410000}\n"
748 "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:41550000}\n"
749 "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:52550000}\n",
750 .support_trail = '\x00',
751 .soft_ver = NULL,
752  
753 /**
754 576KB were moved from file-system to os-image
755 in comparison to the stock image
756 */
757 .partitions = {
758 {"fs-uboot", 0x00000, 0x20000},
759 {"os-image", 0x20000, 0x150000},
760 {"file-system", 0x170000, 0x240000},
761 {"partition-table", 0x3b0000, 0x02000},
762 {"default-mac", 0x3c0000, 0x00020},
763 {"pin", 0x3c0100, 0x00020},
764 {"product-info", 0x3c1000, 0x01000},
765 {"soft-version", 0x3c2000, 0x00100},
766 {"support-list", 0x3c3000, 0x01000},
767 {"profile", 0x3c4000, 0x08000},
768 {"user-config", 0x3d0000, 0x10000},
769 {"default-config", 0x3e0000, 0x10000},
770 {"radio", 0x3f0000, 0x10000},
771 {NULL, 0, 0}
772 },
773  
774 .first_sysupgrade_partition = "os-image",
775 .last_sysupgrade_partition = "file-system"
776 },
777  
778 /** Firmware layout for the TL-WA855RE v1 */
779 {
780 .id = "TLWA855REV1",
781 .vendor = "",
782 .support_list =
783 "SupportList:\n"
784 "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:00000000}\n"
785 "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:55530000}\n"
786 "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:45550000}\n"
787 "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:4B520000}\n"
788 "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:42520000}\n"
789 "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:4A500000}\n"
790 "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:43410000}\n"
791 "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:41550000}\n"
792 "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:52550000}\n",
793 .support_trail = '\x00',
794 .soft_ver = NULL,
795  
796 .partitions = {
797 {"fs-uboot", 0x00000, 0x20000},
798 {"os-image", 0x20000, 0x150000},
799 {"file-system", 0x170000, 0x240000},
800 {"partition-table", 0x3b0000, 0x02000},
801 {"default-mac", 0x3c0000, 0x00020},
802 {"pin", 0x3c0100, 0x00020},
803 {"product-info", 0x3c1000, 0x01000},
804 {"soft-version", 0x3c2000, 0x00100},
805 {"support-list", 0x3c3000, 0x01000},
806 {"profile", 0x3c4000, 0x08000},
807 {"user-config", 0x3d0000, 0x10000},
808 {"default-config", 0x3e0000, 0x10000},
809 {"radio", 0x3f0000, 0x10000},
810 {NULL, 0, 0}
811 },
812  
813 .first_sysupgrade_partition = "os-image",
814 .last_sysupgrade_partition = "file-system"
815 },
816  
817 /** Firmware layout for the TL-WR1043 v5 */
818 {
819 .id = "TLWR1043NV5",
820 .vendor = "",
821 .support_list =
822 "SupportList:\n"
823 "{product_name:TL-WR1043N,product_ver:5.0.0,special_id:45550000}\n"
824 "{product_name:TL-WR1043N,product_ver:5.0.0,special_id:55530000}\n",
825 .support_trail = '\x00',
826 .soft_ver = "soft_ver:1.0.0\n",
827 .partitions = {
828 {"factory-boot", 0x00000, 0x20000},
829 {"fs-uboot", 0x20000, 0x20000},
3 office 830 {"os-image", 0x40000, 0x180000},
831 {"file-system", 0x1c0000, 0xd40000},
1 office 832 {"default-mac", 0xf00000, 0x00200},
833 {"pin", 0xf00200, 0x00200},
834 {"device-id", 0xf00400, 0x00100},
835 {"product-info", 0xf00500, 0x0fb00},
836 {"soft-version", 0xf10000, 0x01000},
837 {"extra-para", 0xf11000, 0x01000},
838 {"support-list", 0xf12000, 0x0a000},
839 {"profile", 0xf1c000, 0x04000},
840 {"default-config", 0xf20000, 0x10000},
841 {"user-config", 0xf30000, 0x40000},
842 {"qos-db", 0xf70000, 0x40000},
843 {"certificate", 0xfb0000, 0x10000},
844 {"partition-table", 0xfc0000, 0x10000},
845 {"log", 0xfd0000, 0x20000},
846 {"radio", 0xff0000, 0x10000},
847 {NULL, 0, 0}
848 },
849 .first_sysupgrade_partition = "os-image",
850 .last_sysupgrade_partition = "file-system"
851 },
852  
853 /** Firmware layout for the TL-WR1043 v4 */
854 {
855 .id = "TLWR1043NDV4",
856 .vendor = "",
857 .support_list =
858 "SupportList:\n"
859 "{product_name:TL-WR1043ND,product_ver:4.0.0,special_id:45550000}\n",
860 .support_trail = '\x00',
861 .soft_ver = NULL,
862  
3 office 863 /**
864 We use a bigger os-image partition than the stock images (and thus
865 smaller file-system), as our kernel doesn't fit in the stock firmware's
866 1MB os-image.
867 */
1 office 868 .partitions = {
869 {"fs-uboot", 0x00000, 0x20000},
3 office 870 {"os-image", 0x20000, 0x180000},
871 {"file-system", 0x1a0000, 0xdb0000},
1 office 872 {"default-mac", 0xf50000, 0x00200},
873 {"pin", 0xf50200, 0x00200},
874 {"product-info", 0xf50400, 0x0fc00},
875 {"soft-version", 0xf60000, 0x0b000},
876 {"support-list", 0xf6b000, 0x04000},
877 {"profile", 0xf70000, 0x04000},
878 {"default-config", 0xf74000, 0x0b000},
879 {"user-config", 0xf80000, 0x40000},
880 {"partition-table", 0xfc0000, 0x10000},
881 {"log", 0xfd0000, 0x20000},
882 {"radio", 0xff0000, 0x10000},
883 {NULL, 0, 0}
884 },
885  
886 .first_sysupgrade_partition = "os-image",
887 .last_sysupgrade_partition = "file-system"
888 },
889  
890 /** Firmware layout for the TL-WR902AC v1 */
891 {
892 .id = "TL-WR902AC-V1",
893 .vendor = "",
894 .support_list =
895 "SupportList:\n"
896 "{product_name:TL-WR902AC,product_ver:1.0.0,special_id:45550000}\n"
897 "{product_name:TL-WR902AC,product_ver:1.0.0,special_id:55530000}\n",
898 .support_trail = '\x00',
899 .soft_ver = NULL,
900  
901 /**
902 384KB were moved from file-system to os-image
903 in comparison to the stock image
904 */
905 .partitions = {
906 {"fs-uboot", 0x00000, 0x20000},
3 office 907 {"os-image", 0x20000, 0x180000},
908 {"file-system", 0x1a0000, 0x5b0000},
1 office 909 {"default-mac", 0x750000, 0x00200},
910 {"pin", 0x750200, 0x00200},
911 {"product-info", 0x750400, 0x0fc00},
912 {"soft-version", 0x760000, 0x0b000},
913 {"support-list", 0x76b000, 0x04000},
914 {"profile", 0x770000, 0x04000},
915 {"default-config", 0x774000, 0x0b000},
916 {"user-config", 0x780000, 0x40000},
917 {"partition-table", 0x7c0000, 0x10000},
918 {"log", 0x7d0000, 0x20000},
919 {"radio", 0x7f0000, 0x10000},
920 {NULL, 0, 0}
921 },
922  
923 .first_sysupgrade_partition = "os-image",
924 .last_sysupgrade_partition = "file-system",
925 },
926  
927 /** Firmware layout for the TL-WR942N V1 */
928 {
929 .id = "TLWR942NV1",
930 .vendor = "",
931 .support_list =
932 "SupportList:\r\n"
933 "{product_name:TL-WR942N,product_ver:1.0.0,special_id:00000000}\r\n"
934 "{product_name:TL-WR942N,product_ver:1.0.0,special_id:52550000}\r\n",
935 .support_trail = '\x00',
936 .soft_ver = NULL,
937  
938 .partitions = {
939 {"fs-uboot", 0x00000, 0x20000},
3 office 940 {"os-image", 0x20000, 0x180000},
941 {"file-system", 0x1a0000, 0xca0000},
1 office 942 {"default-mac", 0xe40000, 0x00200},
943 {"pin", 0xe40200, 0x00200},
944 {"product-info", 0xe40400, 0x0fc00},
945 {"partition-table", 0xe50000, 0x10000},
946 {"soft-version", 0xe60000, 0x10000},
947 {"support-list", 0xe70000, 0x10000},
948 {"profile", 0xe80000, 0x10000},
949 {"default-config", 0xe90000, 0x10000},
950 {"user-config", 0xea0000, 0x40000},
951 {"qos-db", 0xee0000, 0x40000},
952 {"certificate", 0xf20000, 0x10000},
953 {"usb-config", 0xfb0000, 0x10000},
954 {"log", 0xfc0000, 0x20000},
955 {"radio-bk", 0xfe0000, 0x10000},
956 {"radio", 0xff0000, 0x10000},
957 {NULL, 0, 0}
958 },
959  
960 .first_sysupgrade_partition = "os-image",
961 .last_sysupgrade_partition = "file-system",
962 },
963  
964 /** Firmware layout for the RE350 v1 */
965 {
966 .id = "RE350-V1",
967 .vendor = "",
968 .support_list =
969 "SupportList:\n"
970 "{product_name:RE350,product_ver:1.0.0,special_id:45550000}\n"
971 "{product_name:RE350,product_ver:1.0.0,special_id:00000000}\n"
972 "{product_name:RE350,product_ver:1.0.0,special_id:41550000}\n"
973 "{product_name:RE350,product_ver:1.0.0,special_id:55530000}\n"
974 "{product_name:RE350,product_ver:1.0.0,special_id:43410000}\n"
975 "{product_name:RE350,product_ver:1.0.0,special_id:4b520000}\n"
976 "{product_name:RE350,product_ver:1.0.0,special_id:4a500000}\n",
977 .support_trail = '\x00',
978 .soft_ver = NULL,
979  
3 office 980 /**
981 The original os-image partition is too small,
982 so we enlarge it to 1.75M
983 */
1 office 984 .partitions = {
985 {"fs-uboot", 0x00000, 0x20000},
3 office 986 {"os-image", 0x20000, 0x1c0000},
987 {"file-system", 0x1e0000, 0x420000},
1 office 988 {"partition-table", 0x600000, 0x02000},
989 {"default-mac", 0x610000, 0x00020},
990 {"pin", 0x610100, 0x00020},
991 {"product-info", 0x611100, 0x01000},
992 {"soft-version", 0x620000, 0x01000},
993 {"support-list", 0x621000, 0x01000},
994 {"profile", 0x622000, 0x08000},
995 {"user-config", 0x630000, 0x10000},
996 {"default-config", 0x640000, 0x10000},
997 {"radio", 0x7f0000, 0x10000},
998 {NULL, 0, 0}
999 },
1000  
1001 .first_sysupgrade_partition = "os-image",
1002 .last_sysupgrade_partition = "file-system"
1003 },
1004  
1005 /** Firmware layout for the RE355 */
1006 {
1007 .id = "RE355",
1008 .vendor = "",
1009 .support_list =
1010 "SupportList:\r\n"
1011 "{product_name:RE355,product_ver:1.0.0,special_id:00000000}\r\n"
1012 "{product_name:RE355,product_ver:1.0.0,special_id:55530000}\r\n"
1013 "{product_name:RE355,product_ver:1.0.0,special_id:45550000}\r\n"
1014 "{product_name:RE355,product_ver:1.0.0,special_id:4A500000}\r\n"
1015 "{product_name:RE355,product_ver:1.0.0,special_id:43410000}\r\n"
1016 "{product_name:RE355,product_ver:1.0.0,special_id:41550000}\r\n"
1017 "{product_name:RE355,product_ver:1.0.0,special_id:4B520000}\r\n"
1018 "{product_name:RE355,product_ver:1.0.0,special_id:55534100}\r\n",
1019 .support_trail = '\x00',
1020 .soft_ver = NULL,
1021  
3 office 1022 /**
1023 The flash partition table for RE355;
1024 it is almost the same as the one used by the stock images,
1025 576KB were moved from file-system to os-image.
1026 */
1 office 1027 .partitions = {
1028 {"fs-uboot", 0x00000, 0x20000},
3 office 1029 {"os-image", 0x20000, 0x180000},
1030 {"file-system", 0x1a0000, 0x460000},
1 office 1031 {"partition-table", 0x600000, 0x02000},
1032 {"default-mac", 0x610000, 0x00020},
1033 {"pin", 0x610100, 0x00020},
1034 {"product-info", 0x611100, 0x01000},
1035 {"soft-version", 0x620000, 0x01000},
1036 {"support-list", 0x621000, 0x01000},
1037 {"profile", 0x622000, 0x08000},
1038 {"user-config", 0x630000, 0x10000},
1039 {"default-config", 0x640000, 0x10000},
1040 {"radio", 0x7f0000, 0x10000},
1041 {NULL, 0, 0}
1042 },
1043  
1044 .first_sysupgrade_partition = "os-image",
1045 .last_sysupgrade_partition = "file-system"
1046 },
1047  
1048 /** Firmware layout for the RE450 */
1049 {
1050 .id = "RE450",
1051 .vendor = "",
1052 .support_list =
1053 "SupportList:\r\n"
1054 "{product_name:RE450,product_ver:1.0.0,special_id:00000000}\r\n"
1055 "{product_name:RE450,product_ver:1.0.0,special_id:55530000}\r\n"
1056 "{product_name:RE450,product_ver:1.0.0,special_id:45550000}\r\n"
1057 "{product_name:RE450,product_ver:1.0.0,special_id:4A500000}\r\n"
1058 "{product_name:RE450,product_ver:1.0.0,special_id:43410000}\r\n"
1059 "{product_name:RE450,product_ver:1.0.0,special_id:41550000}\r\n"
1060 "{product_name:RE450,product_ver:1.0.0,special_id:4B520000}\r\n"
1061 "{product_name:RE450,product_ver:1.0.0,special_id:55534100}\r\n",
1062 .support_trail = '\x00',
1063 .soft_ver = NULL,
1064  
3 office 1065 /**
1066 The flash partition table for RE450;
1067 it is almost the same as the one used by the stock images,
1068 576KB were moved from file-system to os-image.
1069 */
1 office 1070 .partitions = {
1071 {"fs-uboot", 0x00000, 0x20000},
3 office 1072 {"os-image", 0x20000, 0x180000},
1073 {"file-system", 0x1a0000, 0x460000},
1 office 1074 {"partition-table", 0x600000, 0x02000},
1075 {"default-mac", 0x610000, 0x00020},
1076 {"pin", 0x610100, 0x00020},
1077 {"product-info", 0x611100, 0x01000},
1078 {"soft-version", 0x620000, 0x01000},
1079 {"support-list", 0x621000, 0x01000},
1080 {"profile", 0x622000, 0x08000},
1081 {"user-config", 0x630000, 0x10000},
1082 {"default-config", 0x640000, 0x10000},
1083 {"radio", 0x7f0000, 0x10000},
1084 {NULL, 0, 0}
1085 },
1086  
1087 .first_sysupgrade_partition = "os-image",
1088 .last_sysupgrade_partition = "file-system"
1089 },
1090  
1091 {}
1092 };
1093  
1094 #define error(_ret, _errno, _str, ...) \
1095 do { \
1096 fprintf(stderr, _str ": %s\n", ## __VA_ARGS__, \
1097 strerror(_errno)); \
1098 if (_ret) \
1099 exit(_ret); \
1100 } while (0)
1101  
1102  
1103 /** Stores a uint32 as big endian */
1104 static inline void put32(uint8_t *buf, uint32_t val) {
1105 buf[0] = val >> 24;
1106 buf[1] = val >> 16;
1107 buf[2] = val >> 8;
1108 buf[3] = val;
1109 }
1110  
1111 /** Allocates a new image partition */
1112 static struct image_partition_entry alloc_image_partition(const char *name, size_t len) {
1113 struct image_partition_entry entry = {name, len, malloc(len)};
1114 if (!entry.data)
1115 error(1, errno, "malloc");
1116  
1117 return entry;
1118 }
1119  
1120 /** Frees an image partition */
1121 static void free_image_partition(struct image_partition_entry entry) {
1122 free(entry.data);
1123 }
1124  
1125 static time_t source_date_epoch = -1;
1126 static void set_source_date_epoch() {
1127 char *env = getenv("SOURCE_DATE_EPOCH");
1128 char *endptr = env;
1129 errno = 0;
1130 if (env && *env) {
1131 source_date_epoch = strtoull(env, &endptr, 10);
1132 if (errno || (endptr && *endptr != '\0')) {
1133 fprintf(stderr, "Invalid SOURCE_DATE_EPOCH");
1134 exit(1);
1135 }
1136 }
1137 }
1138  
1139 /** Generates the partition-table partition */
1140 static struct image_partition_entry make_partition_table(const struct flash_partition_entry *p) {
1141 struct image_partition_entry entry = alloc_image_partition("partition-table", 0x800);
1142  
1143 char *s = (char *)entry.data, *end = (char *)(s+entry.size);
1144  
1145 *(s++) = 0x00;
1146 *(s++) = 0x04;
1147 *(s++) = 0x00;
1148 *(s++) = 0x00;
1149  
1150 size_t i;
1151 for (i = 0; p[i].name; i++) {
1152 size_t len = end-s;
1153 size_t w = snprintf(s, len, "partition %s base 0x%05x size 0x%05x\n", p[i].name, p[i].base, p[i].size);
1154  
1155 if (w > len-1)
1156 error(1, 0, "flash partition table overflow?");
1157  
1158 s += w;
1159 }
1160  
1161 s++;
1162  
1163 memset(s, 0xff, end-s);
1164  
1165 return entry;
1166 }
1167  
1168  
1169 /** Generates a binary-coded decimal representation of an integer in the range [0, 99] */
1170 static inline uint8_t bcd(uint8_t v) {
1171 return 0x10 * (v/10) + v%10;
1172 }
1173  
1174  
1175 /** Generates the soft-version partition */
1176 static struct image_partition_entry make_soft_version(uint32_t rev) {
1177 struct image_partition_entry entry = alloc_image_partition("soft-version", sizeof(struct soft_version));
1178 struct soft_version *s = (struct soft_version *)entry.data;
1179  
1180 time_t t;
1181  
1182 if (source_date_epoch != -1)
1183 t = source_date_epoch;
1184 else if (time(&t) == (time_t)(-1))
1185 error(1, errno, "time");
1186  
1187 struct tm *tm = localtime(&t);
1188  
1189 s->magic = htonl(0x0000000c);
1190 s->zero = 0;
1191 s->pad1 = 0xff;
1192  
1193 s->version_major = 0;
1194 s->version_minor = 0;
1195 s->version_patch = 0;
1196  
1197 s->year_hi = bcd((1900+tm->tm_year)/100);
1198 s->year_lo = bcd(tm->tm_year%100);
1199 s->month = bcd(tm->tm_mon+1);
1200 s->day = bcd(tm->tm_mday);
1201 s->rev = htonl(rev);
1202  
1203 s->pad2 = 0xff;
1204  
1205 return entry;
1206 }
1207  
1208 static struct image_partition_entry make_soft_version_from_string(const char *soft_ver) {
1209 /** String length _including_ the terminating zero byte */
1210 uint32_t ver_len = strlen(soft_ver) + 1;
1211 /** Partition contains 64 bit header, the version string, and one additional null byte */
1212 size_t partition_len = 2*sizeof(uint32_t) + ver_len + 1;
1213 struct image_partition_entry entry = alloc_image_partition("soft-version", partition_len);
1214  
1215 uint32_t *len = (uint32_t *)entry.data;
1216 len[0] = htonl(ver_len);
1217 len[1] = 0;
1218 memcpy(&len[2], soft_ver, ver_len);
1219  
1220 entry.data[partition_len - 1] = 0;
1221  
1222 return entry;
1223 }
1224  
1225 /** Generates the support-list partition */
3 office 1226 static struct image_partition_entry make_support_list(const struct device_info *info) {
1 office 1227 size_t len = strlen(info->support_list);
1228 struct image_partition_entry entry = alloc_image_partition("support-list", len + 9);
1229  
1230 put32(entry.data, len);
1231 memset(entry.data+4, 0, 4);
1232 memcpy(entry.data+8, info->support_list, len);
1233 entry.data[len+8] = info->support_trail;
1234  
1235 return entry;
1236 }
1237  
1238 /** Creates a new image partition with an arbitrary name from a file */
3 office 1239 static struct image_partition_entry read_file(const char *part_name, const char *filename, bool add_jffs2_eof) {
1 office 1240 struct stat statbuf;
1241  
1242 if (stat(filename, &statbuf) < 0)
1243 error(1, errno, "unable to stat file `%s'", filename);
1244  
1245 size_t len = statbuf.st_size;
1246  
1247 if (add_jffs2_eof)
3 office 1248 len = ALIGN(len, 0x10000) + sizeof(jffs2_eof_mark);
1 office 1249  
1250 struct image_partition_entry entry = alloc_image_partition(part_name, len);
1251  
1252 FILE *file = fopen(filename, "rb");
1253 if (!file)
1254 error(1, errno, "unable to open file `%s'", filename);
1255  
1256 if (fread(entry.data, statbuf.st_size, 1, file) != 1)
1257 error(1, errno, "unable to read file `%s'", filename);
1258  
1259 if (add_jffs2_eof) {
1260 uint8_t *eof = entry.data + statbuf.st_size, *end = entry.data+entry.size;
1261  
1262 memset(eof, 0xff, end - eof - sizeof(jffs2_eof_mark));
1263 memcpy(end - sizeof(jffs2_eof_mark), jffs2_eof_mark, sizeof(jffs2_eof_mark));
1264 }
1265  
1266 fclose(file);
1267  
1268 return entry;
1269 }
1270  
1271 /** Creates a new image partition from arbitrary data */
1272 static struct image_partition_entry put_data(const char *part_name, const char *datain, size_t len) {
1273  
1274 struct image_partition_entry entry = alloc_image_partition(part_name, len);
1275  
1276 memcpy(entry.data, datain, len);
1277  
1278 return entry;
1279 }
1280  
1281 /**
1282 Copies a list of image partitions into an image buffer and generates the image partition table while doing so
1283  
1284 Example image partition table:
1285  
1286 fwup-ptn partition-table base 0x00800 size 0x00800
1287 fwup-ptn os-image base 0x01000 size 0x113b45
1288 fwup-ptn file-system base 0x114b45 size 0x1d0004
1289 fwup-ptn support-list base 0x2e4b49 size 0x000d1
1290  
1291 Each line of the partition table is terminated with the bytes 09 0d 0a ("\t\r\n"),
1292 the end of the partition table is marked with a zero byte.
1293  
1294 The firmware image must contain at least the partition-table and support-list partitions
1295 to be accepted. There aren't any alignment constraints for the image partitions.
1296  
1297 The partition-table partition contains the actual flash layout; partitions
1298 from the image partition table are mapped to the corresponding flash partitions during
1299 the firmware upgrade. The support-list partition contains a list of devices supported by
1300 the firmware image.
1301  
1302 The base offsets in the firmware partition table are relative to the end
1303 of the vendor information block, so the partition-table partition will
1304 actually start at offset 0x1814 of the image.
1305  
1306 I think partition-table must be the first partition in the firmware image.
1307 */
1308 static void put_partitions(uint8_t *buffer, const struct flash_partition_entry *flash_parts, const struct image_partition_entry *parts) {
1309 size_t i, j;
1310 char *image_pt = (char *)buffer, *end = image_pt + 0x800;
1311  
1312 size_t base = 0x800;
1313 for (i = 0; parts[i].name; i++) {
1314 for (j = 0; flash_parts[j].name; j++) {
1315 if (!strcmp(flash_parts[j].name, parts[i].name)) {
1316 if (parts[i].size > flash_parts[j].size)
1317 error(1, 0, "%s partition too big (more than %u bytes)", flash_parts[j].name, (unsigned)flash_parts[j].size);
1318 break;
1319 }
1320 }
1321  
1322 assert(flash_parts[j].name);
1323  
1324 memcpy(buffer + base, parts[i].data, parts[i].size);
1325  
1326 size_t len = end-image_pt;
1327 size_t w = snprintf(image_pt, len, "fwup-ptn %s base 0x%05x size 0x%05x\t\r\n", parts[i].name, (unsigned)base, (unsigned)parts[i].size);
1328  
1329 if (w > len-1)
1330 error(1, 0, "image partition table overflow?");
1331  
1332 image_pt += w;
1333  
1334 base += parts[i].size;
1335 }
1336 }
1337  
1338 /** Generates and writes the image MD5 checksum */
1339 static void put_md5(uint8_t *md5, uint8_t *buffer, unsigned int len) {
1340 MD5_CTX ctx;
1341  
1342 MD5_Init(&ctx);
1343 MD5_Update(&ctx, md5_salt, (unsigned int)sizeof(md5_salt));
1344 MD5_Update(&ctx, buffer, len);
1345 MD5_Final(md5, &ctx);
1346 }
1347  
1348  
1349 /**
1350 Generates the firmware image in factory format
1351  
1352 Image format:
1353  
1354 Bytes (hex) Usage
1355 ----------- -----
1356 0000-0003 Image size (4 bytes, big endian)
1357 0004-0013 MD5 hash (hash of a 16 byte salt and the image data starting with byte 0x14)
1358 0014-0017 Vendor information length (without padding) (4 bytes, big endian)
1359 0018-1013 Vendor information (4092 bytes, padded with 0xff; there seem to be older
1360 (VxWorks-based) TP-LINK devices which use a smaller vendor information block)
1361 1014-1813 Image partition table (2048 bytes, padded with 0xff)
1362 1814-xxxx Firmware partitions
1363 */
3 office 1364 static void * generate_factory_image(const struct device_info *info, const struct image_partition_entry *parts, size_t *len) {
1 office 1365 *len = 0x1814;
1366  
1367 size_t i;
1368 for (i = 0; parts[i].name; i++)
1369 *len += parts[i].size;
1370  
1371 uint8_t *image = malloc(*len);
1372 if (!image)
1373 error(1, errno, "malloc");
1374  
1375 memset(image, 0xff, *len);
1376 put32(image, *len);
1377  
1378 if (info->vendor) {
1379 size_t vendor_len = strlen(info->vendor);
1380 put32(image+0x14, vendor_len);
1381 memcpy(image+0x18, info->vendor, vendor_len);
1382 }
1383  
1384 put_partitions(image + 0x1014, info->partitions, parts);
1385 put_md5(image+0x04, image+0x14, *len-0x14);
1386  
1387 return image;
1388 }
1389  
1390 /**
1391 Generates the firmware image in sysupgrade format
1392  
1393 This makes some assumptions about the provided flash and image partition tables and
1394 should be generalized when TP-LINK starts building its safeloader into hardware with
1395 different flash layouts.
1396 */
3 office 1397 static void * generate_sysupgrade_image(const struct device_info *info, const struct image_partition_entry *image_parts, size_t *len) {
1 office 1398 size_t i, j;
1399 size_t flash_first_partition_index = 0;
1400 size_t flash_last_partition_index = 0;
1401 const struct flash_partition_entry *flash_first_partition = NULL;
1402 const struct flash_partition_entry *flash_last_partition = NULL;
1403 const struct image_partition_entry *image_last_partition = NULL;
1404  
1405 /** Find first and last partitions */
1406 for (i = 0; info->partitions[i].name; i++) {
1407 if (!strcmp(info->partitions[i].name, info->first_sysupgrade_partition)) {
1408 flash_first_partition = &info->partitions[i];
1409 flash_first_partition_index = i;
1410 } else if (!strcmp(info->partitions[i].name, info->last_sysupgrade_partition)) {
1411 flash_last_partition = &info->partitions[i];
1412 flash_last_partition_index = i;
1413 }
1414 }
1415  
1416 assert(flash_first_partition && flash_last_partition);
1417 assert(flash_first_partition_index < flash_last_partition_index);
1418  
1419 /** Find last partition from image to calculate needed size */
1420 for (i = 0; image_parts[i].name; i++) {
1421 if (!strcmp(image_parts[i].name, info->last_sysupgrade_partition)) {
1422 image_last_partition = &image_parts[i];
1423 break;
1424 }
1425 }
1426  
1427 assert(image_last_partition);
1428  
1429 *len = flash_last_partition->base - flash_first_partition->base + image_last_partition->size;
1430  
1431 uint8_t *image = malloc(*len);
1432 if (!image)
1433 error(1, errno, "malloc");
1434  
1435 memset(image, 0xff, *len);
1436  
1437 for (i = flash_first_partition_index; i <= flash_last_partition_index; i++) {
1438 for (j = 0; image_parts[j].name; j++) {
1439 if (!strcmp(info->partitions[i].name, image_parts[j].name)) {
1440 if (image_parts[j].size > info->partitions[i].size)
1441 error(1, 0, "%s partition too big (more than %u bytes)", info->partitions[i].name, (unsigned)info->partitions[i].size);
1442 memcpy(image + info->partitions[i].base - flash_first_partition->base, image_parts[j].data, image_parts[j].size);
1443 break;
1444 }
1445  
1446 assert(image_parts[j].name);
1447 }
1448 }
1449  
1450 return image;
1451 }
1452  
1453 /** Generates an image according to a given layout and writes it to a file */
1454 static void build_image(const char *output,
1455 const char *kernel_image,
1456 const char *rootfs_image,
1457 uint32_t rev,
1458 bool add_jffs2_eof,
1459 bool sysupgrade,
3 office 1460 const struct device_info *info) {
1 office 1461  
1462 struct image_partition_entry parts[7] = {};
1463  
1464 parts[0] = make_partition_table(info->partitions);
1465 if (info->soft_ver)
1466 parts[1] = make_soft_version_from_string(info->soft_ver);
1467 else
1468 parts[1] = make_soft_version(rev);
1469  
1470 parts[2] = make_support_list(info);
3 office 1471 parts[3] = read_file("os-image", kernel_image, false);
1472 parts[4] = read_file("file-system", rootfs_image, add_jffs2_eof);
1 office 1473  
1474 /* Some devices need the extra-para partition to accept the firmware */
3 office 1475 if (strcasecmp(info->id, "ARCHER-C25-V1") == 0 ||
1 office 1476 strcasecmp(info->id, "ARCHER-C60-V2") == 0 ||
1477 strcasecmp(info->id, "TLWR1043NV5") == 0) {
1478 const char mdat[11] = {0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00};
1479 parts[5] = put_data("extra-para", mdat, 11);
3 office 1480 } else if (strcasecmp(info->id, "ARCHER-C7-V4") == 0 || strcasecmp(info->id, "ARCHER-C7-V5") == 0) {
1 office 1481 const char mdat[11] = {0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0xca, 0x00, 0x01, 0x00, 0x00};
1482 parts[5] = put_data("extra-para", mdat, 11);
1483 }
1484  
1485 size_t len;
1486 void *image;
1487 if (sysupgrade)
1488 image = generate_sysupgrade_image(info, parts, &len);
1489 else
1490 image = generate_factory_image(info, parts, &len);
1491  
1492 FILE *file = fopen(output, "wb");
1493 if (!file)
1494 error(1, errno, "unable to open output file");
1495  
1496 if (fwrite(image, len, 1, file) != 1)
1497 error(1, 0, "unable to write output file");
1498  
1499 fclose(file);
1500  
1501 free(image);
1502  
3 office 1503 size_t i;
1 office 1504 for (i = 0; parts[i].name; i++)
1505 free_image_partition(parts[i]);
1506 }
1507  
1508 /** Usage output */
1509 static void usage(const char *argv0) {
1510 fprintf(stderr,
1511 "Usage: %s [OPTIONS...]\n"
1512 "\n"
1513 "Options:\n"
1514 " -h show this help\n"
1515 "\n"
1516 "Create a new image:\n"
1517 " -B <board> create image for the board specified with <board>\n"
1518 " -k <file> read kernel image from the file <file>\n"
1519 " -r <file> read rootfs image from the file <file>\n"
1520 " -o <file> write output to the file <file>\n"
1521 " -V <rev> sets the revision number to <rev>\n"
1522 " -j add jffs2 end-of-filesystem markers\n"
1523 " -S create sysupgrade instead of factory image\n"
1524 "Extract an old image:\n"
1525 " -x <file> extract all oem firmware partition\n"
1526 " -d <dir> destination to extract the firmware partition\n"
1527 " -z <file> convert an oem firmware into a sysupgade file. Use -o for output file\n",
1528 argv0
1529 );
1530 };
1531  
1532  
3 office 1533 static const struct device_info *find_board(const char *id)
1 office 1534 {
1535 struct device_info *board = NULL;
1536  
1537 for (board = boards; board->id != NULL; board++)
1538 if (strcasecmp(id, board->id) == 0)
1539 return board;
1540  
1541 return NULL;
1542 }
1543  
1544 static int add_flash_partition(
1545 struct flash_partition_entry *part_list,
1546 size_t max_entries,
1547 const char *name,
1548 unsigned long base,
1549 unsigned long size)
1550 {
1551 int ptr;
1552 /* check if the list has a free entry */
1553 for (ptr = 0; ptr < max_entries; ptr++, part_list++) {
1554 if (part_list->name == NULL &&
1555 part_list->base == 0 &&
1556 part_list->size == 0)
1557 break;
1558 }
1559  
1560 if (ptr == max_entries) {
1561 error(1, 0, "No free flash part entry available.");
1562 }
1563  
1564 part_list->name = calloc(1, strlen(name) + 1);
1565 memcpy((char *)part_list->name, name, strlen(name));
1566 part_list->base = base;
1567 part_list->size = size;
1568  
1569 return 0;
1570 }
1571  
1572 /** read the partition table into struct flash_partition_entry */
1573 static int read_partition_table(
1574 FILE *file, long offset,
1575 struct flash_partition_entry *entries, size_t max_entries,
1576 int type)
1577 {
1578 char buf[2048];
1579 char *ptr, *end;
1580 const char *parthdr = NULL;
1581 const char *fwuphdr = "fwup-ptn";
1582 const char *flashhdr = "partition";
1583  
1584 /* TODO: search for the partition table */
1585  
1586 switch(type) {
1587 case 0:
1588 parthdr = fwuphdr;
1589 break;
1590 case 1:
1591 parthdr = flashhdr;
1592 break;
1593 default:
1594 error(1, 0, "Invalid partition table");
1595 }
1596  
1597 if (fseek(file, offset, SEEK_SET) < 0)
1598 error(1, errno, "Can not seek in the firmware");
1599  
1600 if (fread(buf, 1, 2048, file) < 0)
1601 error(1, errno, "Can not read fwup-ptn from the firmware");
1602  
1603 buf[2047] = '\0';
1604  
1605 /* look for the partition header */
1606 if (memcmp(buf, parthdr, strlen(parthdr)) != 0) {
1607 fprintf(stderr, "DEBUG: can not find fwuphdr\n");
1608 return 1;
1609 }
1610  
1611 ptr = buf;
1612 end = buf + sizeof(buf);
1613 while ((ptr + strlen(parthdr)) < end &&
1614 memcmp(ptr, parthdr, strlen(parthdr)) == 0) {
1615 char *end_part;
1616 char *end_element;
1617  
1618 char name[32] = { 0 };
1619 int name_len = 0;
1620 unsigned long base = 0;
1621 unsigned long size = 0;
1622  
1623 end_part = memchr(ptr, '\n', (end - ptr));
1624 if (end_part == NULL) {
1625 /* in theory this should never happen, because a partition always ends with 0x09, 0x0D, 0x0A */
1626 break;
1627 }
1628  
1629 for (int i = 0; i <= 4; i++) {
1630 if (end_part <= ptr)
1631 break;
1632  
1633 end_element = memchr(ptr, 0x20, (end_part - ptr));
1634 if (end_element == NULL) {
1635 error(1, errno, "Ignoring the rest of the partition entries.");
1636 break;
1637 }
1638  
1639 switch (i) {
1640 /* partition header */
1641 case 0:
1642 ptr = end_element + 1;
1643 continue;
1644 /* name */
1645 case 1:
1646 name_len = (end_element - ptr) > 31 ? 31 : (end_element - ptr);
1647 strncpy(name, ptr, name_len);
1648 name[name_len] = '\0';
1649 ptr = end_element + 1;
1650 continue;
1651  
1652 /* string "base" */
1653 case 2:
1654 ptr = end_element + 1;
1655 continue;
1656  
1657 /* actual base */
1658 case 3:
1659 base = strtoul(ptr, NULL, 16);
1660 ptr = end_element + 1;
1661 continue;
1662  
1663 /* string "size" */
1664 case 4:
1665 ptr = end_element + 1;
1666 /* actual size. The last element doesn't have a sepeartor */
1667 size = strtoul(ptr, NULL, 16);
1668 /* the part ends with 0x09, 0x0d, 0x0a */
1669 ptr = end_part + 1;
1670 add_flash_partition(entries, max_entries, name, base, size);
1671 continue;
1672 }
1673 }
1674 }
1675  
1676 return 0;
1677 }
1678  
1679 static void write_partition(
1680 FILE *input_file,
1681 size_t firmware_offset,
1682 struct flash_partition_entry *entry,
1683 FILE *output_file)
1684 {
1685 char buf[4096];
1686 size_t offset;
1687  
1688 fseek(input_file, entry->base + firmware_offset, SEEK_SET);
1689  
1690 for (offset = 0; sizeof(buf) + offset <= entry->size; offset += sizeof(buf)) {
1691 if (fread(buf, sizeof(buf), 1, input_file) < 0)
1692 error(1, errno, "Can not read partition from input_file");
1693  
1694 if (fwrite(buf, sizeof(buf), 1, output_file) < 0)
1695 error(1, errno, "Can not write partition to output_file");
1696 }
1697 /* write last chunk smaller than buffer */
1698 if (offset < entry->size) {
1699 offset = entry->size - offset;
1700 if (fread(buf, offset, 1, input_file) < 0)
1701 error(1, errno, "Can not read partition from input_file");
1702 if (fwrite(buf, offset, 1, output_file) < 0)
1703 error(1, errno, "Can not write partition to output_file");
1704 }
1705 }
1706  
1707 static int extract_firmware_partition(FILE *input_file, size_t firmware_offset, struct flash_partition_entry *entry, const char *output_directory)
1708 {
1709 FILE *output_file;
1710 char output[PATH_MAX];
1711  
1712 snprintf(output, PATH_MAX, "%s/%s", output_directory, entry->name);
1713 output_file = fopen(output, "wb+");
1714 if (output_file == NULL) {
1715 error(1, errno, "Can not open output file %s", output);
1716 }
1717  
1718 write_partition(input_file, firmware_offset, entry, output_file);
1719  
1720 fclose(output_file);
1721  
1722 return 0;
1723 }
1724  
1725 /** extract all partitions from the firmware file */
1726 static int extract_firmware(const char *input, const char *output_directory)
1727 {
1728 struct flash_partition_entry entries[16] = { 0 };
1729 size_t max_entries = 16;
1730 size_t firmware_offset = 0x1014;
1731 FILE *input_file;
1732  
1733 struct stat statbuf;
1734  
1735 /* check input file */
1736 if (stat(input, &statbuf)) {
1737 error(1, errno, "Can not read input firmware %s", input);
1738 }
1739  
1740 /* check if output directory exists */
1741 if (stat(output_directory, &statbuf)) {
1742 error(1, errno, "Failed to stat output directory %s", output_directory);
1743 }
1744  
1745 if ((statbuf.st_mode & S_IFMT) != S_IFDIR) {
1746 error(1, errno, "Given output directory is not a directory %s", output_directory);
1747 }
1748  
1749 input_file = fopen(input, "rb");
1750  
1751 if (read_partition_table(input_file, firmware_offset, entries, 16, 0) != 0) {
1752 error(1, 0, "Error can not read the partition table (fwup-ptn)");
1753 }
1754  
1755 for (int i = 0; i < max_entries; i++) {
1756 if (entries[i].name == NULL &&
1757 entries[i].base == 0 &&
1758 entries[i].size == 0)
1759 continue;
1760  
1761 extract_firmware_partition(input_file, firmware_offset, &entries[i], output_directory);
1762 }
1763  
1764 return 0;
1765 }
1766  
1767 static struct flash_partition_entry *find_partition(
1768 struct flash_partition_entry *entries, size_t max_entries,
1769 const char *name, const char *error_msg)
1770 {
1771 for (int i = 0; i < max_entries; i++, entries++) {
1772 if (strcmp(entries->name, name) == 0)
1773 return entries;
1774 }
1775  
1776 error(1, 0, "%s", error_msg);
1777 return NULL;
1778 }
1779  
1780 static void write_ff(FILE *output_file, size_t size)
1781 {
1782 char buf[4096];
1783 int offset;
1784  
1785 memset(buf, 0xff, sizeof(buf));
1786  
1787 for (offset = 0; offset + sizeof(buf) < size ; offset += sizeof(buf)) {
1788 if (fwrite(buf, sizeof(buf), 1, output_file) < 0)
1789 error(1, errno, "Can not write 0xff to output_file");
1790 }
1791  
1792 /* write last chunk smaller than buffer */
1793 if (offset < size) {
1794 offset = size - offset;
1795 if (fwrite(buf, offset, 1, output_file) < 0)
1796 error(1, errno, "Can not write partition to output_file");
1797 }
1798 }
1799  
1800 static void convert_firmware(const char *input, const char *output)
1801 {
1802 struct flash_partition_entry fwup[MAX_PARTITIONS] = { 0 };
1803 struct flash_partition_entry flash[MAX_PARTITIONS] = { 0 };
1804 struct flash_partition_entry *fwup_os_image = NULL, *fwup_file_system = NULL;
1805 struct flash_partition_entry *flash_os_image = NULL, *flash_file_system = NULL;
1806 struct flash_partition_entry *fwup_partition_table = NULL;
1807 size_t firmware_offset = 0x1014;
1808 FILE *input_file, *output_file;
1809  
1810 struct stat statbuf;
1811  
1812 /* check input file */
1813 if (stat(input, &statbuf)) {
1814 error(1, errno, "Can not read input firmware %s", input);
1815 }
1816  
1817 input_file = fopen(input, "rb");
1818 if (!input_file)
1819 error(1, 0, "Can not open input firmware %s", input);
1820  
1821 output_file = fopen(output, "wb");
1822 if (!output_file)
1823 error(1, 0, "Can not open output firmware %s", output);
1824  
1825 if (read_partition_table(input_file, firmware_offset, fwup, MAX_PARTITIONS, 0) != 0) {
1826 error(1, 0, "Error can not read the partition table (fwup-ptn)");
1827 }
1828  
1829 fwup_os_image = find_partition(fwup, MAX_PARTITIONS,
1830 "os-image", "Error can not find os-image partition (fwup)");
1831 fwup_file_system = find_partition(fwup, MAX_PARTITIONS,
1832 "file-system", "Error can not find file-system partition (fwup)");
1833 fwup_partition_table = find_partition(fwup, MAX_PARTITIONS,
1834 "partition-table", "Error can not find partition-table partition");
1835  
1836 /* the flash partition table has a 0x00000004 magic haeder */
1837 if (read_partition_table(input_file, firmware_offset + fwup_partition_table->base + 4, flash, MAX_PARTITIONS, 1) != 0)
1838 error(1, 0, "Error can not read the partition table (flash)");
1839  
1840 flash_os_image = find_partition(flash, MAX_PARTITIONS,
1841 "os-image", "Error can not find os-image partition (flash)");
1842 flash_file_system = find_partition(flash, MAX_PARTITIONS,
1843 "file-system", "Error can not find file-system partition (flash)");
1844  
1845 /* write os_image to 0x0 */
1846 write_partition(input_file, firmware_offset, fwup_os_image, output_file);
1847 write_ff(output_file, flash_os_image->size - fwup_os_image->size);
1848  
1849 /* write file-system behind os_image */
1850 fseek(output_file, flash_file_system->base - flash_os_image->base, SEEK_SET);
1851 write_partition(input_file, firmware_offset, fwup_file_system, output_file);
1852 write_ff(output_file, flash_file_system->size - fwup_file_system->size);
1853  
1854 fclose(output_file);
1855 fclose(input_file);
1856 }
1857  
1858 int main(int argc, char *argv[]) {
1859 const char *board = NULL, *kernel_image = NULL, *rootfs_image = NULL, *output = NULL;
1860 const char *extract_image = NULL, *output_directory = NULL, *convert_image = NULL;
1861 bool add_jffs2_eof = false, sysupgrade = false;
1862 unsigned rev = 0;
3 office 1863 const struct device_info *info;
1 office 1864 set_source_date_epoch();
1865  
1866 while (true) {
1867 int c;
1868  
1869 c = getopt(argc, argv, "B:k:r:o:V:jSh:x:d:z:");
1870 if (c == -1)
1871 break;
1872  
1873 switch (c) {
1874 case 'B':
1875 board = optarg;
1876 break;
1877  
1878 case 'k':
1879 kernel_image = optarg;
1880 break;
1881  
1882 case 'r':
1883 rootfs_image = optarg;
1884 break;
1885  
1886 case 'o':
1887 output = optarg;
1888 break;
1889  
1890 case 'V':
1891 sscanf(optarg, "r%u", &rev);
1892 break;
1893  
1894 case 'j':
1895 add_jffs2_eof = true;
1896 break;
1897  
1898 case 'S':
1899 sysupgrade = true;
1900 break;
1901  
1902 case 'h':
1903 usage(argv[0]);
1904 return 0;
1905  
1906 case 'd':
1907 output_directory = optarg;
1908 break;
1909  
1910 case 'x':
1911 extract_image = optarg;
1912 break;
1913  
1914 case 'z':
1915 convert_image = optarg;
1916 break;
1917  
1918 default:
1919 usage(argv[0]);
1920 return 1;
1921 }
1922 }
1923  
1924 if (extract_image || output_directory) {
1925 if (!extract_image)
1926 error(1, 0, "No factory/oem image given via -x <file>. Output directory is only valid with -x");
1927 if (!output_directory)
1928 error(1, 0, "Can not extract an image without output directory. Use -d <dir>");
1929 extract_firmware(extract_image, output_directory);
1930 } else if (convert_image) {
1931 if (!output)
1932 error(1, 0, "Can not convert a factory/oem image into sysupgrade image without output file. Use -o <file>");
1933 convert_firmware(convert_image, output);
1934 } else {
1935 if (!board)
1936 error(1, 0, "no board has been specified");
1937 if (!kernel_image)
1938 error(1, 0, "no kernel image has been specified");
1939 if (!rootfs_image)
1940 error(1, 0, "no rootfs image has been specified");
1941 if (!output)
1942 error(1, 0, "no output filename has been specified");
1943  
1944 info = find_board(board);
1945  
1946 if (info == NULL)
1947 error(1, 0, "unsupported board %s", board);
1948  
1949 build_image(output, kernel_image, rootfs_image, rev, add_jffs2_eof, sysupgrade, info);
1950 }
1951  
1952 return 0;
1953 }