2 Copyright (c) 2014, Matthias Schiffer <mschiffer@universe-factory.net>
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
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.
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.
30 Image generation tool for the TP-LINK SafeLoader as seen on
31 TP-LINK Pharos devices (CPE210/220/510/520)
45 #include <arpa/inet.h>
47 #include <sys/types.h>
54 #define ALIGN(x,a) ({ typeof(a) __a = (a); (((x) + __a - 1) & ~(__a - 1)); })
57 #define MAX_PARTITIONS 32
59 /** An image partition table entry */
60 struct image_partition_entry
{
66 /** A flash partition table entry */
67 struct flash_partition_entry
{
73 /** Firmware layout description */
77 const char *support_list
;
80 struct flash_partition_entry partitions
[MAX_PARTITIONS
+1];
81 const char *first_sysupgrade_partition
;
82 const char *last_sysupgrade_partition
;
85 /** The content of the soft-version structure */
86 struct __attribute__((__packed__
)) soft_version
{
90 uint8_t version_major
;
91 uint8_t version_minor
;
92 uint8_t version_patch
;
102 static const uint8_t jffs2_eof_mark
[4] = {0xde, 0xad, 0xc0, 0xde};
106 Salt for the MD5 hash
108 Fortunately, TP-LINK seems to use the same salt for most devices which use
109 the new image format.
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,
119 /** Firmware layout table */
120 static struct device_info boards
[] = {
121 /** Firmware layout for the CPE210/220 V1 */
124 .vendor
= "CPE510(TP-LINK|UN|N300-5):1.0\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',
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, 0x200000},
144 {"file-system", 0x240000, 0x570000},
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},
154 .first_sysupgrade_partition
= "os-image",
155 .last_sysupgrade_partition
= "support-list",
158 /** Firmware layout for the CPE210 V2 */
161 .vendor
= "CPE210(TP-LINK|UN|N300-2|00000000):2.0\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',
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 {"firmware", 0x40000, 0x770000},
186 {"soft-version", 0x7b0000, 0x00100},
187 {"support-list", 0x7b1000, 0x01000},
188 {"user-config", 0x7c0000, 0x10000},
189 {"default-config", 0x7d0000, 0x10000},
190 {"log", 0x7e0000, 0x10000},
191 {"radio", 0x7f0000, 0x10000},
195 .first_sysupgrade_partition
= "os-image",
196 .last_sysupgrade_partition
= "support-list",
199 /** Firmware layout for the CPE210 V3 */
202 .vendor
= "CPE210(TP-LINK|UN|N300-2|00000000):3.0\r\n",
205 "CPE210(TP-LINK|EU|N300-2|45550000):3.0\r\n"
206 "CPE210(TP-LINK|UN|N300-2|00000000):3.0\r\n"
207 "CPE210(TP-LINK|UN|N300-2):3.0\r\n"
208 "CPE210(TP-LINK|EU|N300-2):3.0\r\n",
209 .support_trail
= '\xff',
213 {"fs-uboot", 0x00000, 0x20000},
214 {"partition-table", 0x20000, 0x01000},
215 {"default-mac", 0x30000, 0x00020},
216 {"product-info", 0x31100, 0x00100},
217 {"device-info", 0x31400, 0x00400},
218 {"signature", 0x32000, 0x00400},
219 {"device-id", 0x33000, 0x00100},
220 {"firmware", 0x40000, 0x770000},
221 {"soft-version", 0x7b0000, 0x00100},
222 {"support-list", 0x7b1000, 0x01000},
223 {"user-config", 0x7c0000, 0x10000},
224 {"default-config", 0x7d0000, 0x10000},
225 {"log", 0x7e0000, 0x10000},
226 {"radio", 0x7f0000, 0x10000},
230 .first_sysupgrade_partition
= "os-image",
231 .last_sysupgrade_partition
= "support-list",
234 /** Firmware layout for the CPE220 V2 */
237 .vendor
= "CPE510(TP-LINK|UN|N300-5):1.0\r\n",
240 "CPE220(TP-LINK|EU|N300-2|00000000):2.0\r\n"
241 "CPE220(TP-LINK|EU|N300-2|45550000):2.0\r\n"
242 "CPE220(TP-LINK|EU|N300-2|55530000):2.0\r\n"
243 "CPE220(TP-LINK|UN|N300-2|00000000):2.0\r\n"
244 "CPE220(TP-LINK|UN|N300-2|45550000):2.0\r\n"
245 "CPE220(TP-LINK|UN|N300-2|55530000):2.0\r\n"
246 "CPE220(TP-LINK|US|N300-2|55530000):2.0\r\n"
247 "CPE220(TP-LINK|UN|N300-2):2.0\r\n"
248 "CPE220(TP-LINK|EU|N300-2):2.0\r\n"
249 "CPE220(TP-LINK|US|N300-2):2.0\r\n",
250 .support_trail
= '\xff',
254 {"fs-uboot", 0x00000, 0x20000},
255 {"partition-table", 0x20000, 0x02000},
256 {"default-mac", 0x30000, 0x00020},
257 {"product-info", 0x31100, 0x00100},
258 {"signature", 0x32000, 0x00400},
259 {"os-image", 0x40000, 0x200000},
260 {"file-system", 0x240000, 0x570000},
261 {"soft-version", 0x7b0000, 0x00100},
262 {"support-list", 0x7b1000, 0x00400},
263 {"user-config", 0x7c0000, 0x10000},
264 {"default-config", 0x7d0000, 0x10000},
265 {"log", 0x7e0000, 0x10000},
266 {"radio", 0x7f0000, 0x10000},
270 .first_sysupgrade_partition
= "os-image",
271 .last_sysupgrade_partition
= "support-list",
274 /** Firmware layout for the CPE220 V3 */
277 .vendor
= "CPE220(TP-LINK|UN|N300-2|00000000):3.0\r\n",
280 "CPE220(TP-LINK|EU|N300-2|00000000):3.0\r\n"
281 "CPE220(TP-LINK|EU|N300-2|45550000):3.0\r\n"
282 "CPE220(TP-LINK|EU|N300-2|55530000):3.0\r\n"
283 "CPE220(TP-LINK|UN|N300-2|00000000):3.0\r\n"
284 "CPE220(TP-LINK|UN|N300-2|45550000):3.0\r\n"
285 "CPE220(TP-LINK|UN|N300-2|55530000):3.0\r\n"
286 "CPE220(TP-LINK|US|N300-2|55530000):3.0\r\n"
287 "CPE220(TP-LINK|UN|N300-2):3.0\r\n"
288 "CPE220(TP-LINK|EU|N300-2):3.0\r\n"
289 "CPE220(TP-LINK|US|N300-2):3.0\r\n",
290 .support_trail
= '\xff',
294 {"fs-uboot", 0x00000, 0x20000},
295 {"partition-table", 0x20000, 0x02000},
296 {"default-mac", 0x30000, 0x00020},
297 {"product-info", 0x31100, 0x00100},
298 {"device-info", 0x31400, 0x00400},
299 {"signature", 0x32000, 0x00400},
300 {"device-id", 0x33000, 0x00100},
301 {"firmware", 0x40000, 0x770000},
302 {"soft-version", 0x7b0000, 0x00100},
303 {"support-list", 0x7b1000, 0x01000},
304 {"user-config", 0x7c0000, 0x10000},
305 {"default-config", 0x7d0000, 0x10000},
306 {"log", 0x7e0000, 0x10000},
307 {"radio", 0x7f0000, 0x10000},
311 .first_sysupgrade_partition
= "os-image",
312 .last_sysupgrade_partition
= "support-list",
315 /** Firmware layout for the CPE510/520 V1 */
318 .vendor
= "CPE510(TP-LINK|UN|N300-5):1.0\r\n",
321 "CPE510(TP-LINK|UN|N300-5):1.0\r\n"
322 "CPE510(TP-LINK|UN|N300-5):1.1\r\n"
323 "CPE510(TP-LINK|UN|N300-5):1.1\r\n"
324 "CPE510(TP-LINK|US|N300-5):1.1\r\n"
325 "CPE510(TP-LINK|EU|N300-5):1.1\r\n"
326 "CPE520(TP-LINK|UN|N300-5):1.1\r\n"
327 "CPE520(TP-LINK|US|N300-5):1.1\r\n"
328 "CPE520(TP-LINK|EU|N300-5):1.1\r\n",
329 .support_trail
= '\xff',
333 {"fs-uboot", 0x00000, 0x20000},
334 {"partition-table", 0x20000, 0x02000},
335 {"default-mac", 0x30000, 0x00020},
336 {"product-info", 0x31100, 0x00100},
337 {"signature", 0x32000, 0x00400},
338 {"os-image", 0x40000, 0x200000},
339 {"file-system", 0x240000, 0x570000},
340 {"soft-version", 0x7b0000, 0x00100},
341 {"support-list", 0x7b1000, 0x00400},
342 {"user-config", 0x7c0000, 0x10000},
343 {"default-config", 0x7d0000, 0x10000},
344 {"log", 0x7e0000, 0x10000},
345 {"radio", 0x7f0000, 0x10000},
349 .first_sysupgrade_partition
= "os-image",
350 .last_sysupgrade_partition
= "support-list",
353 /** Firmware layout for the CPE510 V2 */
356 .vendor
= "CPE510(TP-LINK|UN|N300-5):2.0\r\n",
359 "CPE510(TP-LINK|EU|N300-5|00000000):2.0\r\n"
360 "CPE510(TP-LINK|EU|N300-5|45550000):2.0\r\n"
361 "CPE510(TP-LINK|EU|N300-5|55530000):2.0\r\n"
362 "CPE510(TP-LINK|UN|N300-5|00000000):2.0\r\n"
363 "CPE510(TP-LINK|UN|N300-5|45550000):2.0\r\n"
364 "CPE510(TP-LINK|UN|N300-5|55530000):2.0\r\n"
365 "CPE510(TP-LINK|US|N300-5|00000000):2.0\r\n"
366 "CPE510(TP-LINK|US|N300-5|45550000):2.0\r\n"
367 "CPE510(TP-LINK|US|N300-5|55530000):2.0\r\n"
368 "CPE510(TP-LINK|UN|N300-5):2.0\r\n"
369 "CPE510(TP-LINK|EU|N300-5):2.0\r\n"
370 "CPE510(TP-LINK|US|N300-5):2.0\r\n",
371 .support_trail
= '\xff',
375 {"fs-uboot", 0x00000, 0x20000},
376 {"partition-table", 0x20000, 0x02000},
377 {"default-mac", 0x30000, 0x00020},
378 {"product-info", 0x31100, 0x00100},
379 {"signature", 0x32000, 0x00400},
380 {"os-image", 0x40000, 0x200000},
381 {"file-system", 0x240000, 0x570000},
382 {"soft-version", 0x7b0000, 0x00100},
383 {"support-list", 0x7b1000, 0x00400},
384 {"user-config", 0x7c0000, 0x10000},
385 {"default-config", 0x7d0000, 0x10000},
386 {"log", 0x7e0000, 0x10000},
387 {"radio", 0x7f0000, 0x10000},
391 .first_sysupgrade_partition
= "os-image",
392 .last_sysupgrade_partition
= "support-list",
395 /** Firmware layout for the CPE510 V3 */
398 .vendor
= "CPE510(TP-LINK|UN|N300-5):3.0\r\n",
401 "CPE510(TP-LINK|EU|N300-5|00000000):3.0\r\n"
402 "CPE510(TP-LINK|EU|N300-5|45550000):3.0\r\n"
403 "CPE510(TP-LINK|EU|N300-5|55530000):3.0\r\n"
404 "CPE510(TP-LINK|UN|N300-5|00000000):3.0\r\n"
405 "CPE510(TP-LINK|UN|N300-5|45550000):3.0\r\n"
406 "CPE510(TP-LINK|UN|N300-5|55530000):3.0\r\n"
407 "CPE510(TP-LINK|US|N300-5|00000000):3.0\r\n"
408 "CPE510(TP-LINK|US|N300-5|45550000):3.0\r\n"
409 "CPE510(TP-LINK|US|N300-5|55530000):3.0\r\n"
410 "CPE510(TP-LINK|UN|N300-5):3.0\r\n"
411 "CPE510(TP-LINK|EU|N300-5):3.0\r\n"
412 "CPE510(TP-LINK|US|N300-5):3.0\r\n",
413 .support_trail
= '\xff',
417 {"fs-uboot", 0x00000, 0x20000},
418 {"partition-table", 0x20000, 0x02000},
419 {"default-mac", 0x30000, 0x00020},
420 {"product-info", 0x31100, 0x00100},
421 {"signature", 0x32000, 0x00400},
422 {"os-image", 0x40000, 0x200000},
423 {"file-system", 0x240000, 0x570000},
424 {"soft-version", 0x7b0000, 0x00100},
425 {"support-list", 0x7b1000, 0x00400},
426 {"user-config", 0x7c0000, 0x10000},
427 {"default-config", 0x7d0000, 0x10000},
428 {"log", 0x7e0000, 0x10000},
429 {"radio", 0x7f0000, 0x10000},
433 .first_sysupgrade_partition
= "os-image",
434 .last_sysupgrade_partition
= "support-list",
437 /** Firmware layout for the CPE610V1 */
440 .vendor
= "CPE610(TP-LINK|UN|N300-5|00000000):1.0\r\n",
443 "CPE610(TP-LINK|EU|N300-5|00000000):1.0\r\n"
444 "CPE610(TP-LINK|EU|N300-5|45550000):1.0\r\n"
445 "CPE610(TP-LINK|EU|N300-5|55530000):1.0\r\n"
446 "CPE610(TP-LINK|UN|N300-5|00000000):1.0\r\n"
447 "CPE610(TP-LINK|UN|N300-5|45550000):1.0\r\n"
448 "CPE610(TP-LINK|UN|N300-5|55530000):1.0\r\n"
449 "CPE610(TP-LINK|US|N300-5|55530000):1.0\r\n"
450 "CPE610(TP-LINK|UN|N300-5):1.0\r\n"
451 "CPE610(TP-LINK|EU|N300-5):1.0\r\n"
452 "CPE610(TP-LINK|US|N300-5):1.0\r\n",
453 .support_trail
= '\xff',
457 {"fs-uboot", 0x00000, 0x20000},
458 {"partition-table", 0x20000, 0x02000},
459 {"default-mac", 0x30000, 0x00020},
460 {"product-info", 0x31100, 0x00100},
461 {"signature", 0x32000, 0x00400},
462 {"os-image", 0x40000, 0x200000},
463 {"file-system", 0x240000, 0x570000},
464 {"soft-version", 0x7b0000, 0x00100},
465 {"support-list", 0x7b1000, 0x00400},
466 {"user-config", 0x7c0000, 0x10000},
467 {"default-config", 0x7d0000, 0x10000},
468 {"log", 0x7e0000, 0x10000},
469 {"radio", 0x7f0000, 0x10000},
473 .first_sysupgrade_partition
= "os-image",
474 .last_sysupgrade_partition
= "support-list",
479 .vendor
= "CPE510(TP-LINK|UN|N300-5):1.0\r\n",
482 "WBS210(TP-LINK|UN|N300-2):1.20\r\n"
483 "WBS210(TP-LINK|US|N300-2):1.20\r\n"
484 "WBS210(TP-LINK|EU|N300-2):1.20\r\n",
485 .support_trail
= '\xff',
489 {"fs-uboot", 0x00000, 0x20000},
490 {"partition-table", 0x20000, 0x02000},
491 {"default-mac", 0x30000, 0x00020},
492 {"product-info", 0x31100, 0x00100},
493 {"signature", 0x32000, 0x00400},
494 {"os-image", 0x40000, 0x200000},
495 {"file-system", 0x240000, 0x570000},
496 {"soft-version", 0x7b0000, 0x00100},
497 {"support-list", 0x7b1000, 0x00400},
498 {"user-config", 0x7c0000, 0x10000},
499 {"default-config", 0x7d0000, 0x10000},
500 {"log", 0x7e0000, 0x10000},
501 {"radio", 0x7f0000, 0x10000},
505 .first_sysupgrade_partition
= "os-image",
506 .last_sysupgrade_partition
= "support-list",
511 .vendor
= "CPE510(TP-LINK|UN|N300-5):1.0\r\n",
514 "WBS210(TP-LINK|UN|N300-2|00000000):2.00\r\n"
515 "WBS210(TP-LINK|US|N300-2|55530000):2.00\r\n"
516 "WBS210(TP-LINK|EU|N300-2|45550000):2.00\r\n",
517 .support_trail
= '\xff',
521 {"fs-uboot", 0x00000, 0x20000},
522 {"partition-table", 0x20000, 0x02000},
523 {"default-mac", 0x30000, 0x00020},
524 {"product-info", 0x31100, 0x00100},
525 {"signature", 0x32000, 0x00400},
526 {"os-image", 0x40000, 0x200000},
527 {"file-system", 0x240000, 0x570000},
528 {"soft-version", 0x7b0000, 0x00100},
529 {"support-list", 0x7b1000, 0x00400},
530 {"user-config", 0x7c0000, 0x10000},
531 {"default-config", 0x7d0000, 0x10000},
532 {"log", 0x7e0000, 0x10000},
533 {"radio", 0x7f0000, 0x10000},
537 .first_sysupgrade_partition
= "os-image",
538 .last_sysupgrade_partition
= "support-list",
543 .vendor
= "CPE510(TP-LINK|UN|N300-5):1.0\r\n",
546 "WBS510(TP-LINK|UN|N300-5):1.20\r\n"
547 "WBS510(TP-LINK|US|N300-5):1.20\r\n"
548 "WBS510(TP-LINK|EU|N300-5):1.20\r\n",
549 .support_trail
= '\xff',
553 {"fs-uboot", 0x00000, 0x20000},
554 {"partition-table", 0x20000, 0x02000},
555 {"default-mac", 0x30000, 0x00020},
556 {"product-info", 0x31100, 0x00100},
557 {"signature", 0x32000, 0x00400},
558 {"os-image", 0x40000, 0x200000},
559 {"file-system", 0x240000, 0x570000},
560 {"soft-version", 0x7b0000, 0x00100},
561 {"support-list", 0x7b1000, 0x00400},
562 {"user-config", 0x7c0000, 0x10000},
563 {"default-config", 0x7d0000, 0x10000},
564 {"log", 0x7e0000, 0x10000},
565 {"radio", 0x7f0000, 0x10000},
569 .first_sysupgrade_partition
= "os-image",
570 .last_sysupgrade_partition
= "support-list",
573 /** Firmware layout for the C2600 */
579 "{product_name:Archer C2600,product_ver:1.0.0,special_id:00000000}\r\n",
580 .support_trail
= '\x00',
584 We use a bigger os-image partition than the stock images (and thus
585 smaller file-system), as our kernel doesn't fit in the stock firmware's
586 2 MB os-image since kernel 4.14.
589 {"SBL1", 0x00000, 0x20000},
590 {"MIBIB", 0x20000, 0x20000},
591 {"SBL2", 0x40000, 0x20000},
592 {"SBL3", 0x60000, 0x30000},
593 {"DDRCONFIG", 0x90000, 0x10000},
594 {"SSD", 0xa0000, 0x10000},
595 {"TZ", 0xb0000, 0x30000},
596 {"RPM", 0xe0000, 0x20000},
597 {"fs-uboot", 0x100000, 0x70000},
598 {"uboot-env", 0x170000, 0x40000},
599 {"radio", 0x1b0000, 0x40000},
600 {"os-image", 0x1f0000, 0x400000}, /* Stock: base 0x1f0000 size 0x200000 */
601 {"file-system", 0x5f0000, 0x1900000}, /* Stock: base 0x3f0000 size 0x1b00000 */
602 {"default-mac", 0x1ef0000, 0x00200},
603 {"pin", 0x1ef0200, 0x00200},
604 {"product-info", 0x1ef0400, 0x0fc00},
605 {"partition-table", 0x1f00000, 0x10000},
606 {"soft-version", 0x1f10000, 0x10000},
607 {"support-list", 0x1f20000, 0x10000},
608 {"profile", 0x1f30000, 0x10000},
609 {"default-config", 0x1f40000, 0x10000},
610 {"user-config", 0x1f50000, 0x40000},
611 {"qos-db", 0x1f90000, 0x40000},
612 {"usb-config", 0x1fd0000, 0x10000},
613 {"log", 0x1fe0000, 0x20000},
617 .first_sysupgrade_partition
= "os-image",
618 .last_sysupgrade_partition
= "file-system"
621 /** Firmware layout for the A7-V5 */
623 .id
= "ARCHER-A7-V5",
626 "{product_name:Archer A7,product_ver:5.0.0,special_id:45550000}\n"
627 "{product_name:Archer A7,product_ver:5.0.0,special_id:55530000}\n"
628 "{product_name:Archer A7,product_ver:5.0.0,special_id:43410000}\n"
629 "{product_name:Archer A7,product_ver:5.0.0,special_id:4A500000}\n"
630 "{product_name:Archer A7,product_ver:5.0.0,special_id:54570000}\n",
631 .support_trail
= '\x00',
632 .soft_ver
= "soft_ver:1.0.0\n",
634 /* We're using a dynamic kernel/rootfs split here */
636 {"factory-boot", 0x00000, 0x20000},
637 {"fs-uboot", 0x20000, 0x20000},
638 {"firmware", 0x40000, 0xec0000}, /* Stock: name os-image base 0x40000 size 0x120000 */
639 /* Stock: name file-system base 0x160000 size 0xda0000 */
640 {"default-mac", 0xf40000, 0x00200},
641 {"pin", 0xf40200, 0x00200},
642 {"device-id", 0xf40400, 0x00100},
643 {"product-info", 0xf40500, 0x0fb00},
644 {"soft-version", 0xf50000, 0x00100},
645 {"extra-para", 0xf51000, 0x01000},
646 {"support-list", 0xf52000, 0x0a000},
647 {"profile", 0xf5c000, 0x04000},
648 {"default-config", 0xf60000, 0x10000},
649 {"user-config", 0xf70000, 0x40000},
650 {"certificate", 0xfb0000, 0x10000},
651 {"partition-table", 0xfc0000, 0x10000},
652 {"log", 0xfd0000, 0x20000},
653 {"radio", 0xff0000, 0x10000},
657 .first_sysupgrade_partition
= "os-image",
658 .last_sysupgrade_partition
= "file-system",
661 /** Firmware layout for the C2v3 */
663 .id
= "ARCHER-C2-V3",
666 "{product_name:ArcherC2,product_ver:3.0.0,special_id:00000000}\n"
667 "{product_name:ArcherC2,product_ver:3.0.0,special_id:55530000}\n"
668 "{product_name:ArcherC2,product_ver:3.0.0,special_id:45550000}\n",
669 .support_trail
= '\x00',
670 .soft_ver
= "soft_ver:3.0.1\n",
672 /** We're using a dynamic kernel/rootfs split here */
675 {"factory-boot", 0x00000, 0x20000},
676 {"fs-uboot", 0x20000, 0x10000},
677 {"firmware", 0x30000, 0x7a0000},
678 {"user-config", 0x7d0000, 0x04000},
679 {"default-mac", 0x7e0000, 0x00100},
680 {"device-id", 0x7e0100, 0x00100},
681 {"extra-para", 0x7e0200, 0x00100},
682 {"pin", 0x7e0300, 0x00100},
683 {"support-list", 0x7e0400, 0x00400},
684 {"soft-version", 0x7e0800, 0x00400},
685 {"product-info", 0x7e0c00, 0x01400},
686 {"partition-table", 0x7e2000, 0x01000},
687 {"profile", 0x7e3000, 0x01000},
688 {"default-config", 0x7e4000, 0x04000},
689 {"merge-config", 0x7ec000, 0x02000},
690 {"qos-db", 0x7ee000, 0x02000},
691 {"radio", 0x7f0000, 0x10000},
695 .first_sysupgrade_partition
= "os-image",
696 .last_sysupgrade_partition
= "file-system",
699 /** Firmware layout for the C25v1 */
701 .id
= "ARCHER-C25-V1",
704 "{product_name:ArcherC25,product_ver:1.0.0,special_id:00000000}\n"
705 "{product_name:ArcherC25,product_ver:1.0.0,special_id:55530000}\n"
706 "{product_name:ArcherC25,product_ver:1.0.0,special_id:45550000}\n",
707 .support_trail
= '\x00',
708 .soft_ver
= "soft_ver:1.0.0\n",
710 /* We're using a dynamic kernel/rootfs split here */
712 {"factory-boot", 0x00000, 0x20000},
713 {"fs-uboot", 0x20000, 0x10000},
714 {"firmware", 0x30000, 0x7a0000}, /* Stock: name os-image base 0x30000 size 0x100000 */
715 /* Stock: name file-system base 0x130000 size 0x6a0000 */
716 {"user-config", 0x7d0000, 0x04000},
717 {"default-mac", 0x7e0000, 0x00100},
718 {"device-id", 0x7e0100, 0x00100},
719 {"extra-para", 0x7e0200, 0x00100},
720 {"pin", 0x7e0300, 0x00100},
721 {"support-list", 0x7e0400, 0x00400},
722 {"soft-version", 0x7e0800, 0x00400},
723 {"product-info", 0x7e0c00, 0x01400},
724 {"partition-table", 0x7e2000, 0x01000},
725 {"profile", 0x7e3000, 0x01000},
726 {"default-config", 0x7e4000, 0x04000},
727 {"merge-config", 0x7ec000, 0x02000},
728 {"qos-db", 0x7ee000, 0x02000},
729 {"radio", 0x7f0000, 0x10000},
733 .first_sysupgrade_partition
= "os-image",
734 .last_sysupgrade_partition
= "file-system",
737 /** Firmware layout for the C58v1 */
739 .id
= "ARCHER-C58-V1",
743 "{product_name:Archer C58,product_ver:1.0.0,special_id:00000000}\r\n"
744 "{product_name:Archer C58,product_ver:1.0.0,special_id:45550000}\r\n"
745 "{product_name:Archer C58,product_ver:1.0.0,special_id:55530000}\r\n",
746 .support_trail
= '\x00',
747 .soft_ver
= "soft_ver:1.0.0\n",
750 {"fs-uboot", 0x00000, 0x10000},
751 {"default-mac", 0x10000, 0x00200},
752 {"pin", 0x10200, 0x00200},
753 {"product-info", 0x10400, 0x00100},
754 {"partition-table", 0x10500, 0x00800},
755 {"soft-version", 0x11300, 0x00200},
756 {"support-list", 0x11500, 0x00100},
757 {"device-id", 0x11600, 0x00100},
758 {"profile", 0x11700, 0x03900},
759 {"default-config", 0x15000, 0x04000},
760 {"user-config", 0x19000, 0x04000},
761 {"firmware", 0x20000, 0x7c8000},
762 {"certyficate", 0x7e8000, 0x08000},
763 {"radio", 0x7f0000, 0x10000},
767 .first_sysupgrade_partition
= "os-image",
768 .last_sysupgrade_partition
= "file-system",
771 /** Firmware layout for the C59v1 */
773 .id
= "ARCHER-C59-V1",
777 "{product_name:Archer C59,product_ver:1.0.0,special_id:00000000}\r\n"
778 "{product_name:Archer C59,product_ver:1.0.0,special_id:45550000}\r\n"
779 "{product_name:Archer C59,product_ver:1.0.0,special_id:52550000}\r\n"
780 "{product_name:Archer C59,product_ver:1.0.0,special_id:55530000}\r\n",
781 .support_trail
= '\x00',
782 .soft_ver
= "soft_ver:1.0.0\n",
784 /* We're using a dynamic kernel/rootfs split here */
786 {"fs-uboot", 0x00000, 0x10000},
787 {"default-mac", 0x10000, 0x00200},
788 {"pin", 0x10200, 0x00200},
789 {"device-id", 0x10400, 0x00100},
790 {"product-info", 0x10500, 0x0fb00},
791 {"firmware", 0x20000, 0xe30000},
792 {"partition-table", 0xe50000, 0x10000},
793 {"soft-version", 0xe60000, 0x10000},
794 {"support-list", 0xe70000, 0x10000},
795 {"profile", 0xe80000, 0x10000},
796 {"default-config", 0xe90000, 0x10000},
797 {"user-config", 0xea0000, 0x40000},
798 {"usb-config", 0xee0000, 0x10000},
799 {"certificate", 0xef0000, 0x10000},
800 {"qos-db", 0xf00000, 0x40000},
801 {"log", 0xfe0000, 0x10000},
802 {"radio", 0xff0000, 0x10000},
806 .first_sysupgrade_partition
= "os-image",
807 .last_sysupgrade_partition
= "file-system",
810 /** Firmware layout for the C59v2 */
812 .id
= "ARCHER-C59-V2",
816 "{product_name:Archer C59,product_ver:2.0.0,special_id:00000000}\r\n"
817 "{product_name:Archer C59,product_ver:2.0.0,special_id:45550000}\r\n"
818 "{product_name:Archer C59,product_ver:2.0.0,special_id:55530000}\r\n",
819 .support_trail
= '\x00',
820 .soft_ver
= "soft_ver:2.0.0 Build 20161206 rel.7303\n",
822 /** We're using a dynamic kernel/rootfs split here */
824 {"factory-boot", 0x00000, 0x20000},
825 {"fs-uboot", 0x20000, 0x10000},
826 {"default-mac", 0x30000, 0x00200},
827 {"pin", 0x30200, 0x00200},
828 {"device-id", 0x30400, 0x00100},
829 {"product-info", 0x30500, 0x0fb00},
830 {"firmware", 0x40000, 0xe10000},
831 {"partition-table", 0xe50000, 0x10000},
832 {"soft-version", 0xe60000, 0x10000},
833 {"support-list", 0xe70000, 0x10000},
834 {"profile", 0xe80000, 0x10000},
835 {"default-config", 0xe90000, 0x10000},
836 {"user-config", 0xea0000, 0x40000},
837 {"usb-config", 0xee0000, 0x10000},
838 {"certificate", 0xef0000, 0x10000},
839 {"extra-para", 0xf00000, 0x10000},
840 {"qos-db", 0xf10000, 0x30000},
841 {"log", 0xfe0000, 0x10000},
842 {"radio", 0xff0000, 0x10000},
846 .first_sysupgrade_partition
= "os-image",
847 .last_sysupgrade_partition
= "file-system",
850 /** Firmware layout for the C6v2 */
852 .id
= "ARCHER-C6-V2",
856 "{product_name:Archer C6,product_ver:2.0.0,special_id:45550000}\r\n"
857 "{product_name:Archer C6,product_ver:2.0.0,special_id:52550000}\r\n"
858 "{product_name:Archer C6,product_ver:2.0.0,special_id:4A500000}\r\n",
859 .support_trail
= '\x00',
860 .soft_ver
= "soft_ver:1.0.0\n",
863 {"fs-uboot", 0x00000, 0x20000},
864 {"default-mac", 0x20000, 0x00200},
865 {"pin", 0x20200, 0x00100},
866 {"product-info", 0x20300, 0x00200},
867 {"device-id", 0x20500, 0x0fb00},
868 {"firmware", 0x30000, 0x7a9400},
869 {"soft-version", 0x7d9400, 0x00100},
870 {"extra-para", 0x7d9500, 0x00100},
871 {"support-list", 0x7d9600, 0x00200},
872 {"profile", 0x7d9800, 0x03000},
873 {"default-config", 0x7dc800, 0x03000},
874 {"partition-table", 0x7df800, 0x00800},
875 {"user-config", 0x7e0000, 0x0c000},
876 {"certificate", 0x7ec000, 0x04000},
877 {"radio", 0x7f0000, 0x10000},
881 .first_sysupgrade_partition
= "os-image",
882 .last_sysupgrade_partition
= "file-system",
886 /** Firmware layout for the C60v1 */
888 .id
= "ARCHER-C60-V1",
892 "{product_name:Archer C60,product_ver:1.0.0,special_id:00000000}\r\n"
893 "{product_name:Archer C60,product_ver:1.0.0,special_id:45550000}\r\n"
894 "{product_name:Archer C60,product_ver:1.0.0,special_id:55530000}\r\n",
895 .support_trail
= '\x00',
896 .soft_ver
= "soft_ver:1.0.0\n",
899 {"fs-uboot", 0x00000, 0x10000},
900 {"default-mac", 0x10000, 0x00200},
901 {"pin", 0x10200, 0x00200},
902 {"product-info", 0x10400, 0x00100},
903 {"partition-table", 0x10500, 0x00800},
904 {"soft-version", 0x11300, 0x00200},
905 {"support-list", 0x11500, 0x00100},
906 {"device-id", 0x11600, 0x00100},
907 {"profile", 0x11700, 0x03900},
908 {"default-config", 0x15000, 0x04000},
909 {"user-config", 0x19000, 0x04000},
910 {"firmware", 0x20000, 0x7c8000},
911 {"certyficate", 0x7e8000, 0x08000},
912 {"radio", 0x7f0000, 0x10000},
916 .first_sysupgrade_partition
= "os-image",
917 .last_sysupgrade_partition
= "file-system",
920 /** Firmware layout for the C60v2 */
922 .id
= "ARCHER-C60-V2",
926 "{product_name:Archer C60,product_ver:2.0.0,special_id:42520000}\r\n"
927 "{product_name:Archer C60,product_ver:2.0.0,special_id:45550000}\r\n"
928 "{product_name:Archer C60,product_ver:2.0.0,special_id:55530000}\r\n",
929 .support_trail
= '\x00',
930 .soft_ver
= "soft_ver:2.0.0\n",
933 {"factory-boot", 0x00000, 0x1fb00},
934 {"default-mac", 0x1fb00, 0x00200},
935 {"pin", 0x1fd00, 0x00100},
936 {"product-info", 0x1fe00, 0x00100},
937 {"device-id", 0x1ff00, 0x00100},
938 {"fs-uboot", 0x20000, 0x10000},
939 {"firmware", 0x30000, 0x7a0000},
940 {"soft-version", 0x7d9500, 0x00100},
941 {"support-list", 0x7d9600, 0x00100},
942 {"extra-para", 0x7d9700, 0x00100},
943 {"profile", 0x7d9800, 0x03000},
944 {"default-config", 0x7dc800, 0x03000},
945 {"partition-table", 0x7df800, 0x00800},
946 {"user-config", 0x7e0000, 0x0c000},
947 {"certificate", 0x7ec000, 0x04000},
948 {"radio", 0x7f0000, 0x10000},
952 .first_sysupgrade_partition
= "os-image",
953 .last_sysupgrade_partition
= "file-system",
956 /** Firmware layout for the C5 */
958 .id
= "ARCHER-C5-V2",
962 "{product_name:ArcherC5,product_ver:2.0.0,special_id:00000000}\r\n"
963 "{product_name:ArcherC5,product_ver:2.0.0,special_id:55530000}\r\n"
964 "{product_name:ArcherC5,product_ver:2.0.0,special_id:4A500000}\r\n", /* JP version */
965 .support_trail
= '\x00',
969 {"fs-uboot", 0x00000, 0x40000},
970 {"os-image", 0x40000, 0x200000},
971 {"file-system", 0x240000, 0xc00000},
972 {"default-mac", 0xe40000, 0x00200},
973 {"pin", 0xe40200, 0x00200},
974 {"product-info", 0xe40400, 0x00200},
975 {"partition-table", 0xe50000, 0x10000},
976 {"soft-version", 0xe60000, 0x00200},
977 {"support-list", 0xe61000, 0x0f000},
978 {"profile", 0xe70000, 0x10000},
979 {"default-config", 0xe80000, 0x10000},
980 {"user-config", 0xe90000, 0x50000},
981 {"log", 0xee0000, 0x100000},
982 {"radio_bk", 0xfe0000, 0x10000},
983 {"radio", 0xff0000, 0x10000},
987 .first_sysupgrade_partition
= "os-image",
988 .last_sysupgrade_partition
= "file-system"
991 /** Firmware layout for the C7 */
993 .id
= "ARCHER-C7-V4",
996 "{product_name:Archer C7,product_ver:4.0.0,special_id:00000000}\n"
997 "{product_name:Archer C7,product_ver:4.0.0,special_id:41550000}\n"
998 "{product_name:Archer C7,product_ver:4.0.0,special_id:45550000}\n"
999 "{product_name:Archer C7,product_ver:4.0.0,special_id:4B520000}\n"
1000 "{product_name:Archer C7,product_ver:4.0.0,special_id:42520000}\n"
1001 "{product_name:Archer C7,product_ver:4.0.0,special_id:4A500000}\n"
1002 "{product_name:Archer C7,product_ver:4.0.0,special_id:52550000}\n"
1003 "{product_name:Archer C7,product_ver:4.0.0,special_id:54570000}\n"
1004 "{product_name:Archer C7,product_ver:4.0.0,special_id:55530000}\n"
1005 "{product_name:Archer C7,product_ver:4.0.0,special_id:43410000}\n",
1006 .support_trail
= '\x00',
1007 .soft_ver
= "soft_ver:1.0.0\n",
1009 /* We're using a dynamic kernel/rootfs split here */
1011 {"factory-boot", 0x00000, 0x20000},
1012 {"fs-uboot", 0x20000, 0x20000},
1013 {"firmware", 0x40000, 0xEC0000}, /* Stock: name os-image base 0x40000 size 0x120000 */
1014 /* Stock: name file-system base 0x160000 size 0xda0000 */
1015 {"default-mac", 0xf00000, 0x00200},
1016 {"pin", 0xf00200, 0x00200},
1017 {"device-id", 0xf00400, 0x00100},
1018 {"product-info", 0xf00500, 0x0fb00},
1019 {"soft-version", 0xf10000, 0x00100},
1020 {"extra-para", 0xf11000, 0x01000},
1021 {"support-list", 0xf12000, 0x0a000},
1022 {"profile", 0xf1c000, 0x04000},
1023 {"default-config", 0xf20000, 0x10000},
1024 {"user-config", 0xf30000, 0x40000},
1025 {"qos-db", 0xf70000, 0x40000},
1026 {"certificate", 0xfb0000, 0x10000},
1027 {"partition-table", 0xfc0000, 0x10000},
1028 {"log", 0xfd0000, 0x20000},
1029 {"radio", 0xff0000, 0x10000},
1033 .first_sysupgrade_partition
= "os-image",
1034 .last_sysupgrade_partition
= "file-system",
1037 /** Firmware layout for the C7 v5*/
1039 .id
= "ARCHER-C7-V5",
1042 "{product_name:Archer C7,product_ver:5.0.0,special_id:00000000}\n"
1043 "{product_name:Archer C7,product_ver:5.0.0,special_id:45550000}\n"
1044 "{product_name:Archer C7,product_ver:5.0.0,special_id:55530000}\n"
1045 "{product_name:Archer C7,product_ver:5.0.0,special_id:43410000}\n"
1046 "{product_name:Archer C7,product_ver:5.0.0,special_id:4A500000}\n"
1047 "{product_name:Archer C7,product_ver:5.0.0,special_id:54570000}\n"
1048 "{product_name:Archer C7,product_ver:5.0.0,special_id:52550000}\n"
1049 "{product_name:Archer C7,product_ver:5.0.0,special_id:4B520000}\n",
1051 .support_trail
= '\x00',
1052 .soft_ver
= "soft_ver:1.0.0\n",
1054 /* We're using a dynamic kernel/rootfs split here */
1056 {"factory-boot", 0x00000, 0x20000},
1057 {"fs-uboot", 0x20000, 0x20000},
1058 {"partition-table", 0x40000, 0x10000},
1059 {"radio", 0x50000, 0x10000},
1060 {"default-mac", 0x60000, 0x00200},
1061 {"pin", 0x60200, 0x00200},
1062 {"device-id", 0x60400, 0x00100},
1063 {"product-info", 0x60500, 0x0fb00},
1064 {"soft-version", 0x70000, 0x01000},
1065 {"extra-para", 0x71000, 0x01000},
1066 {"support-list", 0x72000, 0x0a000},
1067 {"profile", 0x7c000, 0x04000},
1068 {"user-config", 0x80000, 0x40000},
1071 {"firmware", 0xc0000, 0xf00000}, /* Stock: name os-image base 0xc0000 size 0x120000 */
1072 /* Stock: name file-system base 0x1e0000 size 0xde0000 */
1074 {"log", 0xfc0000, 0x20000},
1075 {"certificate", 0xfe0000, 0x10000},
1076 {"default-config", 0xff0000, 0x10000},
1081 .first_sysupgrade_partition
= "os-image",
1082 .last_sysupgrade_partition
= "file-system",
1085 /** Firmware layout for the C9 */
1091 "{product_name:ArcherC9,"
1092 "product_ver:1.0.0,"
1093 "special_id:00000000}\n",
1094 .support_trail
= '\x00',
1098 {"fs-uboot", 0x00000, 0x40000},
1099 {"os-image", 0x40000, 0x200000},
1100 {"file-system", 0x240000, 0xc00000},
1101 {"default-mac", 0xe40000, 0x00200},
1102 {"pin", 0xe40200, 0x00200},
1103 {"product-info", 0xe40400, 0x00200},
1104 {"partition-table", 0xe50000, 0x10000},
1105 {"soft-version", 0xe60000, 0x00200},
1106 {"support-list", 0xe61000, 0x0f000},
1107 {"profile", 0xe70000, 0x10000},
1108 {"default-config", 0xe80000, 0x10000},
1109 {"user-config", 0xe90000, 0x50000},
1110 {"log", 0xee0000, 0x100000},
1111 {"radio_bk", 0xfe0000, 0x10000},
1112 {"radio", 0xff0000, 0x10000},
1116 .first_sysupgrade_partition
= "os-image",
1117 .last_sysupgrade_partition
= "file-system"
1120 /** Firmware layout for the EAP120 */
1123 .vendor
= "EAP120(TP-LINK|UN|N300-2):1.0\r\n",
1126 "EAP120(TP-LINK|UN|N300-2):1.0\r\n",
1127 .support_trail
= '\xff',
1131 {"fs-uboot", 0x00000, 0x20000},
1132 {"partition-table", 0x20000, 0x02000},
1133 {"default-mac", 0x30000, 0x00020},
1134 {"support-list", 0x31000, 0x00100},
1135 {"product-info", 0x31100, 0x00100},
1136 {"soft-version", 0x32000, 0x00100},
1137 {"os-image", 0x40000, 0x180000},
1138 {"file-system", 0x1c0000, 0x600000},
1139 {"user-config", 0x7c0000, 0x10000},
1140 {"backup-config", 0x7d0000, 0x10000},
1141 {"log", 0x7e0000, 0x10000},
1142 {"radio", 0x7f0000, 0x10000},
1146 .first_sysupgrade_partition
= "os-image",
1147 .last_sysupgrade_partition
= "file-system"
1150 /** Firmware layout for the TL-WA850RE v2 */
1152 .id
= "TLWA850REV2",
1156 "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:55530000}\n"
1157 "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:00000000}\n"
1158 "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:55534100}\n"
1159 "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:45550000}\n"
1160 "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:4B520000}\n"
1161 "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:42520000}\n"
1162 "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:4A500000}\n"
1163 "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:43410000}\n"
1164 "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:41550000}\n"
1165 "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:52550000}\n",
1166 .support_trail
= '\x00',
1170 576KB were moved from file-system to os-image
1171 in comparison to the stock image
1174 {"fs-uboot", 0x00000, 0x20000},
1175 {"os-image", 0x20000, 0x150000},
1176 {"file-system", 0x170000, 0x240000},
1177 {"partition-table", 0x3b0000, 0x02000},
1178 {"default-mac", 0x3c0000, 0x00020},
1179 {"pin", 0x3c0100, 0x00020},
1180 {"product-info", 0x3c1000, 0x01000},
1181 {"soft-version", 0x3c2000, 0x00100},
1182 {"support-list", 0x3c3000, 0x01000},
1183 {"profile", 0x3c4000, 0x08000},
1184 {"user-config", 0x3d0000, 0x10000},
1185 {"default-config", 0x3e0000, 0x10000},
1186 {"radio", 0x3f0000, 0x10000},
1190 .first_sysupgrade_partition
= "os-image",
1191 .last_sysupgrade_partition
= "file-system"
1194 /** Firmware layout for the TL-WA855RE v1 */
1196 .id
= "TLWA855REV1",
1200 "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:00000000}\n"
1201 "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:55530000}\n"
1202 "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:45550000}\n"
1203 "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:4B520000}\n"
1204 "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:42520000}\n"
1205 "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:4A500000}\n"
1206 "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:43410000}\n"
1207 "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:41550000}\n"
1208 "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:52550000}\n",
1209 .support_trail
= '\x00',
1213 {"fs-uboot", 0x00000, 0x20000},
1214 {"os-image", 0x20000, 0x150000},
1215 {"file-system", 0x170000, 0x240000},
1216 {"partition-table", 0x3b0000, 0x02000},
1217 {"default-mac", 0x3c0000, 0x00020},
1218 {"pin", 0x3c0100, 0x00020},
1219 {"product-info", 0x3c1000, 0x01000},
1220 {"soft-version", 0x3c2000, 0x00100},
1221 {"support-list", 0x3c3000, 0x01000},
1222 {"profile", 0x3c4000, 0x08000},
1223 {"user-config", 0x3d0000, 0x10000},
1224 {"default-config", 0x3e0000, 0x10000},
1225 {"radio", 0x3f0000, 0x10000},
1229 .first_sysupgrade_partition
= "os-image",
1230 .last_sysupgrade_partition
= "file-system"
1233 /** Firmware layout for the TL-WR1043 v5 */
1235 .id
= "TLWR1043NV5",
1239 "{product_name:TL-WR1043N,product_ver:5.0.0,special_id:45550000}\n"
1240 "{product_name:TL-WR1043N,product_ver:5.0.0,special_id:55530000}\n",
1241 .support_trail
= '\x00',
1242 .soft_ver
= "soft_ver:1.0.0\n",
1244 {"factory-boot", 0x00000, 0x20000},
1245 {"fs-uboot", 0x20000, 0x20000},
1246 {"firmware", 0x40000, 0xec0000},
1247 {"default-mac", 0xf00000, 0x00200},
1248 {"pin", 0xf00200, 0x00200},
1249 {"device-id", 0xf00400, 0x00100},
1250 {"product-info", 0xf00500, 0x0fb00},
1251 {"soft-version", 0xf10000, 0x01000},
1252 {"extra-para", 0xf11000, 0x01000},
1253 {"support-list", 0xf12000, 0x0a000},
1254 {"profile", 0xf1c000, 0x04000},
1255 {"default-config", 0xf20000, 0x10000},
1256 {"user-config", 0xf30000, 0x40000},
1257 {"qos-db", 0xf70000, 0x40000},
1258 {"certificate", 0xfb0000, 0x10000},
1259 {"partition-table", 0xfc0000, 0x10000},
1260 {"log", 0xfd0000, 0x20000},
1261 {"radio", 0xff0000, 0x10000},
1264 .first_sysupgrade_partition
= "os-image",
1265 .last_sysupgrade_partition
= "file-system"
1268 /** Firmware layout for the TL-WR1043 v4 */
1270 .id
= "TLWR1043NDV4",
1274 "{product_name:TL-WR1043ND,product_ver:4.0.0,special_id:45550000}\n",
1275 .support_trail
= '\x00',
1278 /* We're using a dynamic kernel/rootfs split here */
1280 {"fs-uboot", 0x00000, 0x20000},
1281 {"firmware", 0x20000, 0xf30000},
1282 {"default-mac", 0xf50000, 0x00200},
1283 {"pin", 0xf50200, 0x00200},
1284 {"product-info", 0xf50400, 0x0fc00},
1285 {"soft-version", 0xf60000, 0x0b000},
1286 {"support-list", 0xf6b000, 0x04000},
1287 {"profile", 0xf70000, 0x04000},
1288 {"default-config", 0xf74000, 0x0b000},
1289 {"user-config", 0xf80000, 0x40000},
1290 {"partition-table", 0xfc0000, 0x10000},
1291 {"log", 0xfd0000, 0x20000},
1292 {"radio", 0xff0000, 0x10000},
1296 .first_sysupgrade_partition
= "os-image",
1297 .last_sysupgrade_partition
= "file-system"
1300 /** Firmware layout for the TL-WR902AC v1 */
1302 .id
= "TL-WR902AC-V1",
1306 "{product_name:TL-WR902AC,product_ver:1.0.0,special_id:45550000}\n"
1307 "{product_name:TL-WR902AC,product_ver:1.0.0,special_id:55530000}\n",
1308 .support_trail
= '\x00',
1312 384KB were moved from file-system to os-image
1313 in comparison to the stock image
1316 {"fs-uboot", 0x00000, 0x20000},
1317 {"firmware", 0x20000, 0x730000},
1318 {"default-mac", 0x750000, 0x00200},
1319 {"pin", 0x750200, 0x00200},
1320 {"product-info", 0x750400, 0x0fc00},
1321 {"soft-version", 0x760000, 0x0b000},
1322 {"support-list", 0x76b000, 0x04000},
1323 {"profile", 0x770000, 0x04000},
1324 {"default-config", 0x774000, 0x0b000},
1325 {"user-config", 0x780000, 0x40000},
1326 {"partition-table", 0x7c0000, 0x10000},
1327 {"log", 0x7d0000, 0x20000},
1328 {"radio", 0x7f0000, 0x10000},
1332 .first_sysupgrade_partition
= "os-image",
1333 .last_sysupgrade_partition
= "file-system",
1336 /** Firmware layout for the TL-WR942N V1 */
1342 "{product_name:TL-WR942N,product_ver:1.0.0,special_id:00000000}\r\n"
1343 "{product_name:TL-WR942N,product_ver:1.0.0,special_id:52550000}\r\n",
1344 .support_trail
= '\x00',
1348 {"fs-uboot", 0x00000, 0x20000},
1349 {"firmware", 0x20000, 0xe20000},
1350 {"default-mac", 0xe40000, 0x00200},
1351 {"pin", 0xe40200, 0x00200},
1352 {"product-info", 0xe40400, 0x0fc00},
1353 {"partition-table", 0xe50000, 0x10000},
1354 {"soft-version", 0xe60000, 0x10000},
1355 {"support-list", 0xe70000, 0x10000},
1356 {"profile", 0xe80000, 0x10000},
1357 {"default-config", 0xe90000, 0x10000},
1358 {"user-config", 0xea0000, 0x40000},
1359 {"qos-db", 0xee0000, 0x40000},
1360 {"certificate", 0xf20000, 0x10000},
1361 {"usb-config", 0xfb0000, 0x10000},
1362 {"log", 0xfc0000, 0x20000},
1363 {"radio-bk", 0xfe0000, 0x10000},
1364 {"radio", 0xff0000, 0x10000},
1368 .first_sysupgrade_partition
= "os-image",
1369 .last_sysupgrade_partition
= "file-system",
1372 /** Firmware layout for the RE350 v1 */
1378 "{product_name:RE350,product_ver:1.0.0,special_id:45550000}\n"
1379 "{product_name:RE350,product_ver:1.0.0,special_id:00000000}\n"
1380 "{product_name:RE350,product_ver:1.0.0,special_id:41550000}\n"
1381 "{product_name:RE350,product_ver:1.0.0,special_id:55530000}\n"
1382 "{product_name:RE350,product_ver:1.0.0,special_id:43410000}\n"
1383 "{product_name:RE350,product_ver:1.0.0,special_id:4b520000}\n"
1384 "{product_name:RE350,product_ver:1.0.0,special_id:4a500000}\n",
1385 .support_trail
= '\x00',
1388 /** We're using a dynamic kernel/rootfs split here */
1390 {"fs-uboot", 0x00000, 0x20000},
1391 {"firmware", 0x20000, 0x5e0000},
1392 {"partition-table", 0x600000, 0x02000},
1393 {"default-mac", 0x610000, 0x00020},
1394 {"pin", 0x610100, 0x00020},
1395 {"product-info", 0x611100, 0x01000},
1396 {"soft-version", 0x620000, 0x01000},
1397 {"support-list", 0x621000, 0x01000},
1398 {"profile", 0x622000, 0x08000},
1399 {"user-config", 0x630000, 0x10000},
1400 {"default-config", 0x640000, 0x10000},
1401 {"radio", 0x7f0000, 0x10000},
1405 .first_sysupgrade_partition
= "os-image",
1406 .last_sysupgrade_partition
= "file-system"
1409 /** Firmware layout for the RE350K v1 */
1415 "{product_name:RE350K,product_ver:1.0.0,special_id:00000000,product_region:US}\n",
1416 .support_trail
= '\x00',
1419 /** We're using a dynamic kernel/rootfs split here */
1421 {"fs-uboot", 0x00000, 0x20000},
1422 {"firmware", 0x20000, 0xd70000},
1423 {"partition-table", 0xd90000, 0x02000},
1424 {"default-mac", 0xda0000, 0x00020},
1425 {"pin", 0xda0100, 0x00020},
1426 {"product-info", 0xda1100, 0x01000},
1427 {"soft-version", 0xdb0000, 0x01000},
1428 {"support-list", 0xdb1000, 0x01000},
1429 {"profile", 0xdb2000, 0x08000},
1430 {"user-config", 0xdc0000, 0x10000},
1431 {"default-config", 0xdd0000, 0x10000},
1432 {"device-id", 0xde0000, 0x00108},
1433 {"radio", 0xff0000, 0x10000},
1437 .first_sysupgrade_partition
= "os-image",
1438 .last_sysupgrade_partition
= "file-system"
1441 /** Firmware layout for the RE355 */
1447 "{product_name:RE355,product_ver:1.0.0,special_id:00000000}\r\n"
1448 "{product_name:RE355,product_ver:1.0.0,special_id:55530000}\r\n"
1449 "{product_name:RE355,product_ver:1.0.0,special_id:45550000}\r\n"
1450 "{product_name:RE355,product_ver:1.0.0,special_id:4A500000}\r\n"
1451 "{product_name:RE355,product_ver:1.0.0,special_id:43410000}\r\n"
1452 "{product_name:RE355,product_ver:1.0.0,special_id:41550000}\r\n"
1453 "{product_name:RE355,product_ver:1.0.0,special_id:4B520000}\r\n"
1454 "{product_name:RE355,product_ver:1.0.0,special_id:55534100}\r\n",
1455 .support_trail
= '\x00',
1458 /* We're using a dynamic kernel/rootfs split here */
1460 {"fs-uboot", 0x00000, 0x20000},
1461 {"firmware", 0x20000, 0x5e0000},
1462 {"partition-table", 0x600000, 0x02000},
1463 {"default-mac", 0x610000, 0x00020},
1464 {"pin", 0x610100, 0x00020},
1465 {"product-info", 0x611100, 0x01000},
1466 {"soft-version", 0x620000, 0x01000},
1467 {"support-list", 0x621000, 0x01000},
1468 {"profile", 0x622000, 0x08000},
1469 {"user-config", 0x630000, 0x10000},
1470 {"default-config", 0x640000, 0x10000},
1471 {"radio", 0x7f0000, 0x10000},
1475 .first_sysupgrade_partition
= "os-image",
1476 .last_sysupgrade_partition
= "file-system"
1479 /** Firmware layout for the RE450 */
1485 "{product_name:RE450,product_ver:1.0.0,special_id:00000000}\r\n"
1486 "{product_name:RE450,product_ver:1.0.0,special_id:55530000}\r\n"
1487 "{product_name:RE450,product_ver:1.0.0,special_id:45550000}\r\n"
1488 "{product_name:RE450,product_ver:1.0.0,special_id:4A500000}\r\n"
1489 "{product_name:RE450,product_ver:1.0.0,special_id:43410000}\r\n"
1490 "{product_name:RE450,product_ver:1.0.0,special_id:41550000}\r\n"
1491 "{product_name:RE450,product_ver:1.0.0,special_id:4B520000}\r\n"
1492 "{product_name:RE450,product_ver:1.0.0,special_id:55534100}\r\n",
1493 .support_trail
= '\x00',
1496 /** We're using a dynamic kernel/rootfs split here */
1498 {"fs-uboot", 0x00000, 0x20000},
1499 {"firmware", 0x20000, 0x5e0000},
1500 {"partition-table", 0x600000, 0x02000},
1501 {"default-mac", 0x610000, 0x00020},
1502 {"pin", 0x610100, 0x00020},
1503 {"product-info", 0x611100, 0x01000},
1504 {"soft-version", 0x620000, 0x01000},
1505 {"support-list", 0x621000, 0x01000},
1506 {"profile", 0x622000, 0x08000},
1507 {"user-config", 0x630000, 0x10000},
1508 {"default-config", 0x640000, 0x10000},
1509 {"radio", 0x7f0000, 0x10000},
1513 .first_sysupgrade_partition
= "os-image",
1514 .last_sysupgrade_partition
= "file-system"
1517 /** Firmware layout for the RE450 v2 */
1523 "{product_name:RE450,product_ver:2.0.0,special_id:00000000}\r\n"
1524 "{product_name:RE450,product_ver:2.0.0,special_id:55530000}\r\n"
1525 "{product_name:RE450,product_ver:2.0.0,special_id:45550000}\r\n"
1526 "{product_name:RE450,product_ver:2.0.0,special_id:4A500000}\r\n"
1527 "{product_name:RE450,product_ver:2.0.0,special_id:43410000}\r\n"
1528 "{product_name:RE450,product_ver:2.0.0,special_id:41550000}\r\n"
1529 "{product_name:RE450,product_ver:2.0.0,special_id:41530000}\r\n"
1530 "{product_name:RE450,product_ver:2.0.0,special_id:4B520000}\r\n"
1531 "{product_name:RE450,product_ver:2.0.0,special_id:42520000}\r\n",
1532 .support_trail
= '\x00',
1535 /* We're using a dynamic kernel/rootfs split here */
1537 {"fs-uboot", 0x00000, 0x20000},
1538 {"firmware", 0x20000, 0x5e0000},
1539 {"partition-table", 0x600000, 0x02000},
1540 {"default-mac", 0x610000, 0x00020},
1541 {"pin", 0x610100, 0x00020},
1542 {"product-info", 0x611100, 0x01000},
1543 {"soft-version", 0x620000, 0x01000},
1544 {"support-list", 0x621000, 0x01000},
1545 {"profile", 0x622000, 0x08000},
1546 {"user-config", 0x630000, 0x10000},
1547 {"default-config", 0x640000, 0x10000},
1548 {"radio", 0x7f0000, 0x10000},
1553 .first_sysupgrade_partition
= "os-image",
1554 .last_sysupgrade_partition
= "file-system"
1557 /** Firmware layout for the RE650 */
1563 "{product_name:RE650,product_ver:1.0.0,special_id:00000000}\r\n"
1564 "{product_name:RE650,product_ver:1.0.0,special_id:55530000}\r\n"
1565 "{product_name:RE650,product_ver:1.0.0,special_id:45550000}\r\n"
1566 "{product_name:RE650,product_ver:1.0.0,special_id:4A500000}\r\n"
1567 "{product_name:RE650,product_ver:1.0.0,special_id:43410000}\r\n"
1568 "{product_name:RE650,product_ver:1.0.0,special_id:41550000}\r\n"
1569 "{product_name:RE650,product_ver:1.0.0,special_id:41530000}\r\n",
1570 .support_trail
= '\x00',
1573 /* We're using a dynamic kernel/rootfs split here */
1575 {"fs-uboot", 0x00000, 0x20000},
1576 {"firmware", 0x20000, 0xde0000},
1577 {"partition-table", 0xe00000, 0x02000},
1578 {"default-mac", 0xe10000, 0x00020},
1579 {"pin", 0xe10100, 0x00020},
1580 {"product-info", 0xe11100, 0x01000},
1581 {"soft-version", 0xe20000, 0x01000},
1582 {"support-list", 0xe21000, 0x01000},
1583 {"profile", 0xe22000, 0x08000},
1584 {"user-config", 0xe30000, 0x10000},
1585 {"default-config", 0xe40000, 0x10000},
1586 {"radio", 0xff0000, 0x10000},
1590 .first_sysupgrade_partition
= "os-image",
1591 .last_sysupgrade_partition
= "file-system"
1597 #define error(_ret, _errno, _str, ...) \
1599 fprintf(stderr, _str ": %s\n", ## __VA_ARGS__, \
1600 strerror(_errno)); \
1606 /** Stores a uint32 as big endian */
1607 static inline void put32(uint8_t *buf
, uint32_t val
) {
1614 /** Allocates a new image partition */
1615 static struct image_partition_entry
alloc_image_partition(const char *name
, size_t len
) {
1616 struct image_partition_entry entry
= {name
, len
, malloc(len
)};
1618 error(1, errno
, "malloc");
1623 /** Frees an image partition */
1624 static void free_image_partition(struct image_partition_entry entry
) {
1628 static time_t source_date_epoch
= -1;
1629 static void set_source_date_epoch() {
1630 char *env
= getenv("SOURCE_DATE_EPOCH");
1634 source_date_epoch
= strtoull(env
, &endptr
, 10);
1635 if (errno
|| (endptr
&& *endptr
!= '\0')) {
1636 fprintf(stderr
, "Invalid SOURCE_DATE_EPOCH");
1642 /** Generates the partition-table partition */
1643 static struct image_partition_entry
make_partition_table(const struct flash_partition_entry
*p
) {
1644 struct image_partition_entry entry
= alloc_image_partition("partition-table", 0x800);
1646 char *s
= (char *)entry
.data
, *end
= (char *)(s
+entry
.size
);
1654 for (i
= 0; p
[i
].name
; i
++) {
1656 size_t w
= snprintf(s
, len
, "partition %s base 0x%05x size 0x%05x\n", p
[i
].name
, p
[i
].base
, p
[i
].size
);
1659 error(1, 0, "flash partition table overflow?");
1666 memset(s
, 0xff, end
-s
);
1672 /** Generates a binary-coded decimal representation of an integer in the range [0, 99] */
1673 static inline uint8_t bcd(uint8_t v
) {
1674 return 0x10 * (v
/10) + v
%10;
1678 /** Generates the soft-version partition */
1679 static struct image_partition_entry
make_soft_version(uint32_t rev
) {
1680 struct image_partition_entry entry
= alloc_image_partition("soft-version", sizeof(struct soft_version
));
1681 struct soft_version
*s
= (struct soft_version
*)entry
.data
;
1685 if (source_date_epoch
!= -1)
1686 t
= source_date_epoch
;
1687 else if (time(&t
) == (time_t)(-1))
1688 error(1, errno
, "time");
1690 struct tm
*tm
= localtime(&t
);
1692 s
->magic
= htonl(0x0000000c);
1696 s
->version_major
= 0;
1697 s
->version_minor
= 0;
1698 s
->version_patch
= 0;
1700 s
->year_hi
= bcd((1900+tm
->tm_year
)/100);
1701 s
->year_lo
= bcd(tm
->tm_year
%100);
1702 s
->month
= bcd(tm
->tm_mon
+1);
1703 s
->day
= bcd(tm
->tm_mday
);
1704 s
->rev
= htonl(rev
);
1711 static struct image_partition_entry
make_soft_version_from_string(const char *soft_ver
) {
1712 /** String length _including_ the terminating zero byte */
1713 uint32_t ver_len
= strlen(soft_ver
) + 1;
1714 /** Partition contains 64 bit header, the version string, and one additional null byte */
1715 size_t partition_len
= 2*sizeof(uint32_t) + ver_len
+ 1;
1716 struct image_partition_entry entry
= alloc_image_partition("soft-version", partition_len
);
1718 uint32_t *len
= (uint32_t *)entry
.data
;
1719 len
[0] = htonl(ver_len
);
1721 memcpy(&len
[2], soft_ver
, ver_len
);
1723 entry
.data
[partition_len
- 1] = 0;
1728 /** Generates the support-list partition */
1729 static struct image_partition_entry
make_support_list(struct device_info
*info
) {
1730 size_t len
= strlen(info
->support_list
);
1731 struct image_partition_entry entry
= alloc_image_partition("support-list", len
+ 9);
1733 put32(entry
.data
, len
);
1734 memset(entry
.data
+4, 0, 4);
1735 memcpy(entry
.data
+8, info
->support_list
, len
);
1736 entry
.data
[len
+8] = info
->support_trail
;
1741 /** Creates a new image partition with an arbitrary name from a file */
1742 static struct image_partition_entry
read_file(const char *part_name
, const char *filename
, bool add_jffs2_eof
, struct flash_partition_entry
*file_system_partition
) {
1743 struct stat statbuf
;
1745 if (stat(filename
, &statbuf
) < 0)
1746 error(1, errno
, "unable to stat file `%s'", filename
);
1748 size_t len
= statbuf
.st_size
;
1750 if (add_jffs2_eof
) {
1751 if (file_system_partition
)
1752 len
= ALIGN(len
+ file_system_partition
->base
, 0x10000) + sizeof(jffs2_eof_mark
) - file_system_partition
->base
;
1754 len
= ALIGN(len
, 0x10000) + sizeof(jffs2_eof_mark
);
1757 struct image_partition_entry entry
= alloc_image_partition(part_name
, len
);
1759 FILE *file
= fopen(filename
, "rb");
1761 error(1, errno
, "unable to open file `%s'", filename
);
1763 if (fread(entry
.data
, statbuf
.st_size
, 1, file
) != 1)
1764 error(1, errno
, "unable to read file `%s'", filename
);
1766 if (add_jffs2_eof
) {
1767 uint8_t *eof
= entry
.data
+ statbuf
.st_size
, *end
= entry
.data
+entry
.size
;
1769 memset(eof
, 0xff, end
- eof
- sizeof(jffs2_eof_mark
));
1770 memcpy(end
- sizeof(jffs2_eof_mark
), jffs2_eof_mark
, sizeof(jffs2_eof_mark
));
1778 /** Creates a new image partition from arbitrary data */
1779 static struct image_partition_entry
put_data(const char *part_name
, const char *datain
, size_t len
) {
1781 struct image_partition_entry entry
= alloc_image_partition(part_name
, len
);
1783 memcpy(entry
.data
, datain
, len
);
1789 Copies a list of image partitions into an image buffer and generates the image partition table while doing so
1791 Example image partition table:
1793 fwup-ptn partition-table base 0x00800 size 0x00800
1794 fwup-ptn os-image base 0x01000 size 0x113b45
1795 fwup-ptn file-system base 0x114b45 size 0x1d0004
1796 fwup-ptn support-list base 0x2e4b49 size 0x000d1
1798 Each line of the partition table is terminated with the bytes 09 0d 0a ("\t\r\n"),
1799 the end of the partition table is marked with a zero byte.
1801 The firmware image must contain at least the partition-table and support-list partitions
1802 to be accepted. There aren't any alignment constraints for the image partitions.
1804 The partition-table partition contains the actual flash layout; partitions
1805 from the image partition table are mapped to the corresponding flash partitions during
1806 the firmware upgrade. The support-list partition contains a list of devices supported by
1809 The base offsets in the firmware partition table are relative to the end
1810 of the vendor information block, so the partition-table partition will
1811 actually start at offset 0x1814 of the image.
1813 I think partition-table must be the first partition in the firmware image.
1815 static void put_partitions(uint8_t *buffer
, const struct flash_partition_entry
*flash_parts
, const struct image_partition_entry
*parts
) {
1817 char *image_pt
= (char *)buffer
, *end
= image_pt
+ 0x800;
1819 size_t base
= 0x800;
1820 for (i
= 0; parts
[i
].name
; i
++) {
1821 for (j
= 0; flash_parts
[j
].name
; j
++) {
1822 if (!strcmp(flash_parts
[j
].name
, parts
[i
].name
)) {
1823 if (parts
[i
].size
> flash_parts
[j
].size
)
1824 error(1, 0, "%s partition too big (more than %u bytes)", flash_parts
[j
].name
, (unsigned)flash_parts
[j
].size
);
1829 assert(flash_parts
[j
].name
);
1831 memcpy(buffer
+ base
, parts
[i
].data
, parts
[i
].size
);
1833 size_t len
= end
-image_pt
;
1834 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
);
1837 error(1, 0, "image partition table overflow?");
1841 base
+= parts
[i
].size
;
1845 /** Generates and writes the image MD5 checksum */
1846 static void put_md5(uint8_t *md5
, uint8_t *buffer
, unsigned int len
) {
1850 MD5_Update(&ctx
, md5_salt
, (unsigned int)sizeof(md5_salt
));
1851 MD5_Update(&ctx
, buffer
, len
);
1852 MD5_Final(md5
, &ctx
);
1857 Generates the firmware image in factory format
1863 0000-0003 Image size (4 bytes, big endian)
1864 0004-0013 MD5 hash (hash of a 16 byte salt and the image data starting with byte 0x14)
1865 0014-0017 Vendor information length (without padding) (4 bytes, big endian)
1866 0018-1013 Vendor information (4092 bytes, padded with 0xff; there seem to be older
1867 (VxWorks-based) TP-LINK devices which use a smaller vendor information block)
1868 1014-1813 Image partition table (2048 bytes, padded with 0xff)
1869 1814-xxxx Firmware partitions
1871 static void * generate_factory_image(struct device_info
*info
, const struct image_partition_entry
*parts
, size_t *len
) {
1875 for (i
= 0; parts
[i
].name
; i
++)
1876 *len
+= parts
[i
].size
;
1878 uint8_t *image
= malloc(*len
);
1880 error(1, errno
, "malloc");
1882 memset(image
, 0xff, *len
);
1886 size_t vendor_len
= strlen(info
->vendor
);
1887 put32(image
+0x14, vendor_len
);
1888 memcpy(image
+0x18, info
->vendor
, vendor_len
);
1891 put_partitions(image
+ 0x1014, info
->partitions
, parts
);
1892 put_md5(image
+0x04, image
+0x14, *len
-0x14);
1898 Generates the firmware image in sysupgrade format
1900 This makes some assumptions about the provided flash and image partition tables and
1901 should be generalized when TP-LINK starts building its safeloader into hardware with
1902 different flash layouts.
1904 static void * generate_sysupgrade_image(struct device_info
*info
, const struct image_partition_entry
*image_parts
, size_t *len
) {
1906 size_t flash_first_partition_index
= 0;
1907 size_t flash_last_partition_index
= 0;
1908 const struct flash_partition_entry
*flash_first_partition
= NULL
;
1909 const struct flash_partition_entry
*flash_last_partition
= NULL
;
1910 const struct image_partition_entry
*image_last_partition
= NULL
;
1912 /** Find first and last partitions */
1913 for (i
= 0; info
->partitions
[i
].name
; i
++) {
1914 if (!strcmp(info
->partitions
[i
].name
, info
->first_sysupgrade_partition
)) {
1915 flash_first_partition
= &info
->partitions
[i
];
1916 flash_first_partition_index
= i
;
1917 } else if (!strcmp(info
->partitions
[i
].name
, info
->last_sysupgrade_partition
)) {
1918 flash_last_partition
= &info
->partitions
[i
];
1919 flash_last_partition_index
= i
;
1923 assert(flash_first_partition
&& flash_last_partition
);
1924 assert(flash_first_partition_index
< flash_last_partition_index
);
1926 /** Find last partition from image to calculate needed size */
1927 for (i
= 0; image_parts
[i
].name
; i
++) {
1928 if (!strcmp(image_parts
[i
].name
, info
->last_sysupgrade_partition
)) {
1929 image_last_partition
= &image_parts
[i
];
1934 assert(image_last_partition
);
1936 *len
= flash_last_partition
->base
- flash_first_partition
->base
+ image_last_partition
->size
;
1938 uint8_t *image
= malloc(*len
);
1940 error(1, errno
, "malloc");
1942 memset(image
, 0xff, *len
);
1944 for (i
= flash_first_partition_index
; i
<= flash_last_partition_index
; i
++) {
1945 for (j
= 0; image_parts
[j
].name
; j
++) {
1946 if (!strcmp(info
->partitions
[i
].name
, image_parts
[j
].name
)) {
1947 if (image_parts
[j
].size
> info
->partitions
[i
].size
)
1948 error(1, 0, "%s partition too big (more than %u bytes)", info
->partitions
[i
].name
, (unsigned)info
->partitions
[i
].size
);
1949 memcpy(image
+ info
->partitions
[i
].base
- flash_first_partition
->base
, image_parts
[j
].data
, image_parts
[j
].size
);
1953 assert(image_parts
[j
].name
);
1960 /** Generates an image according to a given layout and writes it to a file */
1961 static void build_image(const char *output
,
1962 const char *kernel_image
,
1963 const char *rootfs_image
,
1967 struct device_info
*info
) {
1971 struct image_partition_entry parts
[7] = {};
1973 struct flash_partition_entry
*firmware_partition
= NULL
;
1974 struct flash_partition_entry
*os_image_partition
= NULL
;
1975 struct flash_partition_entry
*file_system_partition
= NULL
;
1976 size_t firmware_partition_index
= 0;
1978 for (i
= 0; info
->partitions
[i
].name
; i
++) {
1979 if (!strcmp(info
->partitions
[i
].name
, "firmware"))
1981 firmware_partition
= &info
->partitions
[i
];
1982 firmware_partition_index
= i
;
1986 if (firmware_partition
)
1988 os_image_partition
= &info
->partitions
[firmware_partition_index
];
1989 file_system_partition
= &info
->partitions
[firmware_partition_index
+ 1];
1992 if (stat(kernel_image
, &kernel
) < 0)
1993 error(1, errno
, "unable to stat file `%s'", kernel_image
);
1995 if (kernel
.st_size
> firmware_partition
->size
)
1996 error(1, 0, "kernel overflowed firmware partition\n");
1998 for (i
= MAX_PARTITIONS
-1; i
>= firmware_partition_index
+ 1; i
--)
1999 info
->partitions
[i
+1] = info
->partitions
[i
];
2001 file_system_partition
->name
= "file-system";
2002 file_system_partition
->base
= firmware_partition
->base
+ kernel
.st_size
;
2004 /* Align partition start to erase blocks for factory images only */
2006 file_system_partition
->base
= ALIGN(firmware_partition
->base
+ kernel
.st_size
, 0x10000);
2008 file_system_partition
->size
= firmware_partition
->size
- file_system_partition
->base
;
2010 os_image_partition
->name
= "os-image";
2011 os_image_partition
->size
= kernel
.st_size
;
2014 parts
[0] = make_partition_table(info
->partitions
);
2016 parts
[1] = make_soft_version_from_string(info
->soft_ver
);
2018 parts
[1] = make_soft_version(rev
);
2020 parts
[2] = make_support_list(info
);
2021 parts
[3] = read_file("os-image", kernel_image
, false, NULL
);
2022 parts
[4] = read_file("file-system", rootfs_image
, add_jffs2_eof
, file_system_partition
);
2024 /* Some devices need the extra-para partition to accept the firmware */
2025 if (strcasecmp(info
->id
, "ARCHER-C2-V3") == 0 ||
2026 strcasecmp(info
->id
, "ARCHER-C25-V1") == 0 ||
2027 strcasecmp(info
->id
, "ARCHER-C59-V2") == 0 ||
2028 strcasecmp(info
->id
, "ARCHER-C60-V2") == 0 ||
2029 strcasecmp(info
->id
, "TLWR1043NV5") == 0) {
2030 const char mdat
[11] = {0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00};
2031 parts
[5] = put_data("extra-para", mdat
, 11);
2032 } else if (strcasecmp(info
->id
, "ARCHER-A7-V5") == 0 || strcasecmp(info
->id
, "ARCHER-C7-V4") == 0 || strcasecmp(info
->id
, "ARCHER-C7-V5") == 0) {
2033 const char mdat
[11] = {0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0xca, 0x00, 0x01, 0x00, 0x00};
2034 parts
[5] = put_data("extra-para", mdat
, 11);
2035 } else if (strcasecmp(info
->id
, "ARCHER-C6-V2") == 0) {
2036 const char mdat
[11] = {0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00};
2037 parts
[5] = put_data("extra-para", mdat
, 11);
2043 image
= generate_sysupgrade_image(info
, parts
, &len
);
2045 image
= generate_factory_image(info
, parts
, &len
);
2047 FILE *file
= fopen(output
, "wb");
2049 error(1, errno
, "unable to open output file");
2051 if (fwrite(image
, len
, 1, file
) != 1)
2052 error(1, 0, "unable to write output file");
2058 for (i
= 0; parts
[i
].name
; i
++)
2059 free_image_partition(parts
[i
]);
2063 static void usage(const char *argv0
) {
2065 "Usage: %s [OPTIONS...]\n"
2068 " -h show this help\n"
2070 "Create a new image:\n"
2071 " -B <board> create image for the board specified with <board>\n"
2072 " -k <file> read kernel image from the file <file>\n"
2073 " -r <file> read rootfs image from the file <file>\n"
2074 " -o <file> write output to the file <file>\n"
2075 " -V <rev> sets the revision number to <rev>\n"
2076 " -j add jffs2 end-of-filesystem markers\n"
2077 " -S create sysupgrade instead of factory image\n"
2078 "Extract an old image:\n"
2079 " -x <file> extract all oem firmware partition\n"
2080 " -d <dir> destination to extract the firmware partition\n"
2081 " -z <file> convert an oem firmware into a sysupgade file. Use -o for output file\n",
2087 static struct device_info
*find_board(const char *id
)
2089 struct device_info
*board
= NULL
;
2091 for (board
= boards
; board
->id
!= NULL
; board
++)
2092 if (strcasecmp(id
, board
->id
) == 0)
2098 static int add_flash_partition(
2099 struct flash_partition_entry
*part_list
,
2106 /* check if the list has a free entry */
2107 for (ptr
= 0; ptr
< max_entries
; ptr
++, part_list
++) {
2108 if (part_list
->name
== NULL
&&
2109 part_list
->base
== 0 &&
2110 part_list
->size
== 0)
2114 if (ptr
== max_entries
) {
2115 error(1, 0, "No free flash part entry available.");
2118 part_list
->name
= calloc(1, strlen(name
) + 1);
2119 if (!part_list
->name
) {
2120 error(1, 0, "Unable to allocate memory");
2123 memcpy((char *)part_list
->name
, name
, strlen(name
));
2124 part_list
->base
= base
;
2125 part_list
->size
= size
;
2130 /** read the partition table into struct flash_partition_entry */
2131 static int read_partition_table(
2132 FILE *file
, long offset
,
2133 struct flash_partition_entry
*entries
, size_t max_entries
,
2138 const char *parthdr
= NULL
;
2139 const char *fwuphdr
= "fwup-ptn";
2140 const char *flashhdr
= "partition";
2142 /* TODO: search for the partition table */
2152 error(1, 0, "Invalid partition table");
2155 if (fseek(file
, offset
, SEEK_SET
) < 0)
2156 error(1, errno
, "Can not seek in the firmware");
2158 if (fread(buf
, 2048, 1, file
) != 1)
2159 error(1, errno
, "Can not read fwup-ptn from the firmware");
2163 /* look for the partition header */
2164 if (memcmp(buf
, parthdr
, strlen(parthdr
)) != 0) {
2165 fprintf(stderr
, "DEBUG: can not find fwuphdr\n");
2170 end
= buf
+ sizeof(buf
);
2171 while ((ptr
+ strlen(parthdr
)) < end
&&
2172 memcmp(ptr
, parthdr
, strlen(parthdr
)) == 0) {
2176 char name
[32] = { 0 };
2178 unsigned long base
= 0;
2179 unsigned long size
= 0;
2181 end_part
= memchr(ptr
, '\n', (end
- ptr
));
2182 if (end_part
== NULL
) {
2183 /* in theory this should never happen, because a partition always ends with 0x09, 0x0D, 0x0A */
2187 for (int i
= 0; i
<= 4; i
++) {
2188 if (end_part
<= ptr
)
2191 end_element
= memchr(ptr
, 0x20, (end_part
- ptr
));
2192 if (end_element
== NULL
) {
2193 error(1, errno
, "Ignoring the rest of the partition entries.");
2198 /* partition header */
2200 ptr
= end_element
+ 1;
2204 name_len
= (end_element
- ptr
) > 31 ? 31 : (end_element
- ptr
);
2205 strncpy(name
, ptr
, name_len
);
2206 name
[name_len
] = '\0';
2207 ptr
= end_element
+ 1;
2212 ptr
= end_element
+ 1;
2217 base
= strtoul(ptr
, NULL
, 16);
2218 ptr
= end_element
+ 1;
2223 ptr
= end_element
+ 1;
2224 /* actual size. The last element doesn't have a sepeartor */
2225 size
= strtoul(ptr
, NULL
, 16);
2226 /* the part ends with 0x09, 0x0d, 0x0a */
2228 add_flash_partition(entries
, max_entries
, name
, base
, size
);
2237 static void write_partition(
2239 size_t firmware_offset
,
2240 struct flash_partition_entry
*entry
,
2246 fseek(input_file
, entry
->base
+ firmware_offset
, SEEK_SET
);
2248 for (offset
= 0; sizeof(buf
) + offset
<= entry
->size
; offset
+= sizeof(buf
)) {
2249 if (fread(buf
, sizeof(buf
), 1, input_file
) != 1)
2250 error(1, errno
, "Can not read partition from input_file");
2252 if (fwrite(buf
, sizeof(buf
), 1, output_file
) != 1)
2253 error(1, errno
, "Can not write partition to output_file");
2255 /* write last chunk smaller than buffer */
2256 if (offset
< entry
->size
) {
2257 offset
= entry
->size
- offset
;
2258 if (fread(buf
, offset
, 1, input_file
) != 1)
2259 error(1, errno
, "Can not read partition from input_file");
2260 if (fwrite(buf
, offset
, 1, output_file
) != 1)
2261 error(1, errno
, "Can not write partition to output_file");
2265 static int extract_firmware_partition(FILE *input_file
, size_t firmware_offset
, struct flash_partition_entry
*entry
, const char *output_directory
)
2268 char output
[PATH_MAX
];
2270 snprintf(output
, PATH_MAX
, "%s/%s", output_directory
, entry
->name
);
2271 output_file
= fopen(output
, "wb+");
2272 if (output_file
== NULL
) {
2273 error(1, errno
, "Can not open output file %s", output
);
2276 write_partition(input_file
, firmware_offset
, entry
, output_file
);
2278 fclose(output_file
);
2283 /** extract all partitions from the firmware file */
2284 static int extract_firmware(const char *input
, const char *output_directory
)
2286 struct flash_partition_entry entries
[16] = { 0 };
2287 size_t max_entries
= 16;
2288 size_t firmware_offset
= 0x1014;
2291 struct stat statbuf
;
2293 /* check input file */
2294 if (stat(input
, &statbuf
)) {
2295 error(1, errno
, "Can not read input firmware %s", input
);
2298 /* check if output directory exists */
2299 if (stat(output_directory
, &statbuf
)) {
2300 error(1, errno
, "Failed to stat output directory %s", output_directory
);
2303 if ((statbuf
.st_mode
& S_IFMT
) != S_IFDIR
) {
2304 error(1, errno
, "Given output directory is not a directory %s", output_directory
);
2307 input_file
= fopen(input
, "rb");
2309 if (read_partition_table(input_file
, firmware_offset
, entries
, 16, 0) != 0) {
2310 error(1, 0, "Error can not read the partition table (fwup-ptn)");
2313 for (size_t i
= 0; i
< max_entries
; i
++) {
2314 if (entries
[i
].name
== NULL
&&
2315 entries
[i
].base
== 0 &&
2316 entries
[i
].size
== 0)
2319 extract_firmware_partition(input_file
, firmware_offset
, &entries
[i
], output_directory
);
2325 static struct flash_partition_entry
*find_partition(
2326 struct flash_partition_entry
*entries
, size_t max_entries
,
2327 const char *name
, const char *error_msg
)
2329 for (size_t i
= 0; i
< max_entries
; i
++, entries
++) {
2330 if (strcmp(entries
->name
, name
) == 0)
2334 error(1, 0, "%s", error_msg
);
2338 static void write_ff(FILE *output_file
, size_t size
)
2343 memset(buf
, 0xff, sizeof(buf
));
2345 for (offset
= 0; offset
+ sizeof(buf
) < size
; offset
+= sizeof(buf
)) {
2346 if (fwrite(buf
, sizeof(buf
), 1, output_file
) != 1)
2347 error(1, errno
, "Can not write 0xff to output_file");
2350 /* write last chunk smaller than buffer */
2351 if (offset
< size
) {
2352 offset
= size
- offset
;
2353 if (fwrite(buf
, offset
, 1, output_file
) != 1)
2354 error(1, errno
, "Can not write partition to output_file");
2358 static void convert_firmware(const char *input
, const char *output
)
2360 struct flash_partition_entry fwup
[MAX_PARTITIONS
] = { 0 };
2361 struct flash_partition_entry flash
[MAX_PARTITIONS
] = { 0 };
2362 struct flash_partition_entry
*fwup_os_image
= NULL
, *fwup_file_system
= NULL
;
2363 struct flash_partition_entry
*flash_os_image
= NULL
, *flash_file_system
= NULL
;
2364 struct flash_partition_entry
*fwup_partition_table
= NULL
;
2365 size_t firmware_offset
= 0x1014;
2366 FILE *input_file
, *output_file
;
2368 struct stat statbuf
;
2370 /* check input file */
2371 if (stat(input
, &statbuf
)) {
2372 error(1, errno
, "Can not read input firmware %s", input
);
2375 input_file
= fopen(input
, "rb");
2377 error(1, 0, "Can not open input firmware %s", input
);
2379 output_file
= fopen(output
, "wb");
2381 error(1, 0, "Can not open output firmware %s", output
);
2383 if (read_partition_table(input_file
, firmware_offset
, fwup
, MAX_PARTITIONS
, 0) != 0) {
2384 error(1, 0, "Error can not read the partition table (fwup-ptn)");
2387 fwup_os_image
= find_partition(fwup
, MAX_PARTITIONS
,
2388 "os-image", "Error can not find os-image partition (fwup)");
2389 fwup_file_system
= find_partition(fwup
, MAX_PARTITIONS
,
2390 "file-system", "Error can not find file-system partition (fwup)");
2391 fwup_partition_table
= find_partition(fwup
, MAX_PARTITIONS
,
2392 "partition-table", "Error can not find partition-table partition");
2394 /* the flash partition table has a 0x00000004 magic haeder */
2395 if (read_partition_table(input_file
, firmware_offset
+ fwup_partition_table
->base
+ 4, flash
, MAX_PARTITIONS
, 1) != 0)
2396 error(1, 0, "Error can not read the partition table (flash)");
2398 flash_os_image
= find_partition(flash
, MAX_PARTITIONS
,
2399 "os-image", "Error can not find os-image partition (flash)");
2400 flash_file_system
= find_partition(flash
, MAX_PARTITIONS
,
2401 "file-system", "Error can not find file-system partition (flash)");
2403 /* write os_image to 0x0 */
2404 write_partition(input_file
, firmware_offset
, fwup_os_image
, output_file
);
2405 write_ff(output_file
, flash_os_image
->size
- fwup_os_image
->size
);
2407 /* write file-system behind os_image */
2408 fseek(output_file
, flash_file_system
->base
- flash_os_image
->base
, SEEK_SET
);
2409 write_partition(input_file
, firmware_offset
, fwup_file_system
, output_file
);
2410 write_ff(output_file
, flash_file_system
->size
- fwup_file_system
->size
);
2412 fclose(output_file
);
2416 int main(int argc
, char *argv
[]) {
2417 const char *board
= NULL
, *kernel_image
= NULL
, *rootfs_image
= NULL
, *output
= NULL
;
2418 const char *extract_image
= NULL
, *output_directory
= NULL
, *convert_image
= NULL
;
2419 bool add_jffs2_eof
= false, sysupgrade
= false;
2421 struct device_info
*info
;
2422 set_source_date_epoch();
2427 c
= getopt(argc
, argv
, "B:k:r:o:V:jSh:x:d:z:");
2437 kernel_image
= optarg
;
2441 rootfs_image
= optarg
;
2449 sscanf(optarg
, "r%u", &rev
);
2453 add_jffs2_eof
= true;
2465 output_directory
= optarg
;
2469 extract_image
= optarg
;
2473 convert_image
= optarg
;
2482 if (extract_image
|| output_directory
) {
2484 error(1, 0, "No factory/oem image given via -x <file>. Output directory is only valid with -x");
2485 if (!output_directory
)
2486 error(1, 0, "Can not extract an image without output directory. Use -d <dir>");
2487 extract_firmware(extract_image
, output_directory
);
2488 } else if (convert_image
) {
2490 error(1, 0, "Can not convert a factory/oem image into sysupgrade image without output file. Use -o <file>");
2491 convert_firmware(convert_image
, output
);
2494 error(1, 0, "no board has been specified");
2496 error(1, 0, "no kernel image has been specified");
2498 error(1, 0, "no rootfs image has been specified");
2500 error(1, 0, "no output filename has been specified");
2502 info
= find_board(board
);
2505 error(1, 0, "unsupported board %s", board
);
2507 build_image(output
, kernel_image
, rootfs_image
, rev
, add_jffs2_eof
, sysupgrade
, info
);